From fbe2cd6ce811b779dc9f941de23400cac48424e4 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Mon, 16 Sep 2024 15:04:20 +0200 Subject: [PATCH 01/45] Adding initial support to parse interface changes between swift files --- Package.resolved | 13 +- Package.swift | 12 +- .../Resources/expected-reference-changes.md | 96 +++++ Tests/UnitTests/SwiftInterfaceTests.swift | 363 ++++++++++++++++++ 4 files changed, 479 insertions(+), 5 deletions(-) create mode 100644 Tests/UnitTests/Resources/expected-reference-changes.md create mode 100644 Tests/UnitTests/SwiftInterfaceTests.swift diff --git a/Package.resolved b/Package.resolved index 393f191..6d73072 100644 --- a/Package.resolved +++ b/Package.resolved @@ -9,13 +9,22 @@ "version" : "1.5.0" } }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/swiftlang/swift-syntax", + "state" : { + "revision" : "cb53fa1bd3219b0b23ded7dfdd3b2baff266fd25", + "version" : "600.0.0" + } + }, { "identity" : "swiftformat", "kind" : "remoteSourceControl", "location" : "https://github.com/nicklockwood/SwiftFormat", "state" : { - "revision" : "c6680dd33c013abdd18266538e302f6323fa130e", - "version" : "0.54.4" + "revision" : "ab6844edb79a7b88dc6320e6cee0a0db7674dac3", + "version" : "0.54.5" } } ], diff --git a/Package.swift b/Package.swift index 5c5f357..ba87e1c 100644 --- a/Package.swift +++ b/Package.swift @@ -10,7 +10,8 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/apple/swift-argument-parser", from: "1.5.0"), - .package(url: "https://github.com/nicklockwood/SwiftFormat", from: "0.54.5") + .package(url: "https://github.com/nicklockwood/SwiftFormat", from: "0.54.5"), + .package(url: "https://github.com/swiftlang/swift-syntax", from: "600.0.0") ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. @@ -24,13 +25,18 @@ let package = Package( ), .testTarget( name: "UnitTests", - dependencies: ["public-api-diff"], + dependencies: [ + "public-api-diff", + .product(name: "SwiftSyntax", package: "swift-syntax"), + .product(name: "SwiftParser", package: "swift-syntax"), + ], resources: [ // Copy Tests/ExampleTests/Resources directories as-is. // Use to retain directory structure. // Will be at top level in bundle. .copy("Resources/dummy.abi.json"), - .copy("Resources/dummi-abi-flat-definition.md") + .copy("Resources/dummi-abi-flat-definition.md"), + .copy("Resources/expected-reference-changes.md") ] ), .testTarget( diff --git a/Tests/UnitTests/Resources/expected-reference-changes.md b/Tests/UnitTests/Resources/expected-reference-changes.md new file mode 100644 index 0000000..0acb7d8 --- /dev/null +++ b/Tests/UnitTests/Resources/expected-reference-changes.md @@ -0,0 +1,96 @@ +# πŸ‘€ 11 public changes detected +_Comparing `/.../.../UpdatedPackage` to `/.../.../ReferencePackage`_ + +--- +## `ReferencePackage` +#### πŸ”€ Changed +```javascript +// From +public protocol CustomProtocol + +// To +public protocol CustomProtocol + +/** +Changes: +- Added generic signature `` +*/ +``` +```javascript +// From +public struct CustomStruct : CustomProtocol + +// To +public struct CustomStruct : CustomProtocol + +/** +Changes: +- Added generic signature `` +*/ +``` +### `CustomProtocol` +#### ❇️ Added +```javascript +public associatedtype CustomAssociatedType +``` +#### πŸ”€ Changed +```javascript +// From +public func function() -> any Self.CustomAssociatedType + +// To +public func function() -> Self.CustomAssociatedType +``` +```javascript +// From +public var getSetVar: any Self.CustomAssociatedType { get set } + +// To +public var getSetVar: Self.CustomAssociatedType { get set } +``` +```javascript +// From +public var getVar: any Self.CustomAssociatedType { get } + +// To +public var getVar: Self.CustomAssociatedType { get } +``` +#### πŸ˜Άβ€πŸŒ«οΈ Removed +```javascript +public typealias CustomAssociatedType = Equatable +``` +### `CustomStruct` +#### ❇️ Added +```javascript +public typealias CustomAssociatedType = Int +``` +#### πŸ”€ Changed +```javascript +// From +@discardableResult public func function() -> any Equatable + +// To +@discardableResult public func function() -> Int + +/** +Changes: +- Added generic signature `` +*/ +``` +```javascript +// From +public var getSetVar: any Equatable { get set } + +// To +public var getSetVar: Int { get set } +``` +```javascript +// From +public var getVar: any Equatable { get set } + +// To +public var getVar: Int { get set } +``` + +--- +**Analyzed targets:** ReferencePackage diff --git a/Tests/UnitTests/SwiftInterfaceTests.swift b/Tests/UnitTests/SwiftInterfaceTests.swift new file mode 100644 index 0000000..99ff4b7 --- /dev/null +++ b/Tests/UnitTests/SwiftInterfaceTests.swift @@ -0,0 +1,363 @@ +// +// File.swift +// +// +// Created by Alexander Guretzki on 16/09/2024. +// + +@testable import public_api_diff +import XCTest + +import SwiftSyntax +import SwiftParser + +class SwiftInterfaceTests: XCTestCase { + + func test_swiftinterface() throws { + + // Unfortunately we can't use packages as Test Resources, so we put it in a `ReferencePackages` directory on root + guard let projectRoot = #file.replacingOccurrences(of: "relatve/path/to/file", with: "").split(separator: "/Tests/").first else { + XCTFail("Cannot find root directory") + return + } + + let referencePackagesRoot = URL(filePath: String(projectRoot)).appending(path: "ReferencePackages") + + let expectedOutput: String = try { + let expectedOutputFilePath = try XCTUnwrap(Bundle.module.path(forResource: "expected-reference-changes", ofType: "md")) + let expectedOutputData = try XCTUnwrap(FileManager.default.contents(atPath: expectedOutputFilePath)) + return try XCTUnwrap(String(data: expectedOutputData, encoding: .utf8)) + }() + + let oldSource: String = try { + let oldReferencePackageDirectory = referencePackagesRoot.appending(path: "ReferencePackage") + let interfaceFilePath = try XCTUnwrap(oldReferencePackageDirectory.appending(path: "Sources/ReferencePackage/ReferencePackage.swift")) + let interfaceFileContent = try XCTUnwrap(FileManager.default.contents(atPath: interfaceFilePath.path())) + return try XCTUnwrap(String(data: interfaceFileContent, encoding: .utf8)) + }() + + let newSource: String = try { + let newReferencePackageDirectory = referencePackagesRoot.appending(path: "UpdatedPackage") + let interfaceFilePath = try XCTUnwrap(newReferencePackageDirectory.appending(path: "Sources/ReferencePackage/ReferencePackage.swift")) + let interfaceFileContent = try XCTUnwrap(FileManager.default.contents(atPath: interfaceFilePath.path())) + return try XCTUnwrap(String(data: interfaceFileContent, encoding: .utf8)) + }() + + let oldRoot = SDKDump( + root: .init( + kind: .root, + name: "TopLevel", + printedName: "TopLevel", + children: SwiftInterfaceVisitor.parse(source: oldSource) + ) + ) + + let newRoot = SDKDump( + root: .init( + kind: .root, + name: "TopLevel", + printedName: "TopLevel", + children: SwiftInterfaceVisitor.parse(source: newSource) + ) + ) + + let changes = SDKDumpAnalyzer().analyze(old: oldRoot, new: newRoot) + let markdownOutput = MarkdownOutputGenerator().generate( + from: ["ReferencePackage": changes], + allTargets: ["ReferencePackage"], + oldSource: .local(path: "/.../.../ReferencePackage"), + newSource: .local(path: "/.../.../UpdatedPackage"), + warnings: [] + ) + + XCTAssertEqual(markdownOutput, expectedOutput) + } +} + +/** + Inspired by: https://github.com/sdidla/Hatch/blob/main/Sources/Hatch/SymbolParser.swift + */ +class SwiftInterfaceVisitor: SyntaxVisitor { + + /* + if hasDiscardableResult { components += ["@discardableResult"] } + if isObjcAccessible { components += ["@objc"] } + if isInlinable { components += ["@inlinable"] } + if isOverride { components += ["override"] } + if declKind != .import && declKind != .case { + if isOpen { + components += ["open"] + } else if isInternal { + components += ["internal"] + } else { + components += ["public"] + } + } + if isFinal { components += ["final"] } + if isIndirect { components += ["indirect"] } + if isRequired { components += ["required"] } + if isStatic { components += ["static"] } + if isConvenienceInit { components += ["convenience"] } + if isDynamic { components += ["dynamic"] } + if isPrefix { components += ["prefix"] } + if isPostfix { components += ["postfix"] } + if isInfix { components += ["infix"] } + */ + + private var scope: Scope = .root(symbols: []) + + static public func parse(source: String) -> [SDKDump.Element] { + let visitor = Self() + visitor.walk(Parser.parse(source: source)) + return visitor.scope.symbols + } + + /// Designated initializer + required public init() { + super.init(viewMode: .sourceAccurate) + } + + /// Starts a new scope which can contain zero or more nested symbols + public func startScope() -> SyntaxVisitorContinueKind { + scope.start() + return .visitChildren + } + + /// Ends the current scope and adds the symbol returned by the closure to the symbol tree + /// - Parameter makeSymbolWithChildrenInScope: Closure that return a new ``Symbol`` + /// + /// Call in `visitPost(_ node:)` methods + public func endScopeAndAddSymbol(makeSymbolWithChildrenInScope: (_ children: [SDKDump.Element]) -> SDKDump.Element) { + scope.end(makeSymbolWithChildrenInScope: makeSymbolWithChildrenInScope) + } + + // MARK: Class + + open override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind { + startScope() + } + + open override func visitPost(_ node: ClassDeclSyntax) { + let name: String = node.name.text + + endScopeAndAddSymbol { children in + SDKDump.Element( + kind: .class, + name: name, + printedName: name, + declKind: .class, + children: children, + spiGroupNames: node.attributes.spiGroupNames, + declAttributes: node.attributes.declAttributes, + conformances: node.inheritanceClause?.inheritedTypes.conformances + ) + } + } + + // MARK: Struct + + open override func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind { + startScope() + } + + open override func visitPost(_ node: StructDeclSyntax) { + let name: String = node.name.text + + endScopeAndAddSymbol { children in + SDKDump.Element( + kind: .struct, + name: name, + printedName: name, + declKind: .struct, + children: children, + spiGroupNames: node.attributes.spiGroupNames, + declAttributes: node.attributes.declAttributes, + conformances: node.inheritanceClause?.inheritedTypes.conformances + ) + } + } + + // MARK: Var + + open override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind { + startScope() + } + + open override func visitPost(_ node: VariableDeclSyntax) { + let components = node.bindings.description.split(separator: ":") + guard components.count == 2 else { return } + let name = components[0].trimmingCharacters(in: .whitespacesAndNewlines) + let type = components[1].trimmingCharacters(in: .whitespacesAndNewlines) + + endScopeAndAddSymbol { children in + let varElement = SDKDump.Element( + kind: .var, + name: name, + printedName: name, + declKind: .var, + isLet: node.bindingSpecifier.text == "let", + children: [.init(kind: .typeNominal, name: type, printedName: type)], + spiGroupNames: node.attributes.spiGroupNames, + declAttributes: node.attributes.declAttributes + ) + return varElement + } + } + + // MARK: TypeAlias + + open override func visit(_ node: TypeAliasDeclSyntax) -> SyntaxVisitorContinueKind { + startScope() + } + + open override func visitPost(_ node: TypeAliasDeclSyntax) { + let type = SDKDump.Element( + kind: .typeNominal, + name: node.initializer.value.description, + printedName: node.initializer.value.description + ) + + endScopeAndAddSymbol { children in + let varElement = SDKDump.Element( + kind: .typeAlias, + name: node.name.text, + printedName: node.name.text, + declKind: .typeAlias, + children: [type], + spiGroupNames: node.attributes.spiGroupNames, + declAttributes: node.attributes.declAttributes + ) + return varElement + } + } + + // MARK: AssociatedType + + open override func visit(_ node: AssociatedTypeDeclSyntax) -> SyntaxVisitorContinueKind { + startScope() + } + + open override func visitPost(_ node: AssociatedTypeDeclSyntax) { + endScopeAndAddSymbol { children in + let varElement = SDKDump.Element( + kind: .associatedtype, + name: node.name.text, + printedName: node.name.text, + declKind: .associatedType, + children: children, + spiGroupNames: node.attributes.spiGroupNames, + declAttributes: node.attributes.declAttributes + ) + return varElement + } + } + + // MARK: Function + + open override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind { + startScope() + } + + open override func visitPost(_ node: FunctionDeclSyntax) { + endScopeAndAddSymbol { children in + let varElement = SDKDump.Element( + kind: .func, + name: node.name.text, + printedName: node.name.text, + declKind: .func, + isThrowing: node.signature.isThrowing, + children: children, + spiGroupNames: node.attributes.spiGroupNames, + declAttributes: node.attributes.declAttributes + ) + return varElement + } + } +} + +// MARK: - Convenience + +extension AttributeListSyntax { + private static var spiKeyword: String { "@_spi" } + + var spiGroupNames: [String] { + return self + .map { $0.trimmedDescription } + .filter { $0.starts(with: Self.spiKeyword) } + .map { element in + element + .replacingOccurrences(of: "\(Self.spiKeyword)(", with: "") + .replacingOccurrences(of: ")", with: "") + } + } + + var declAttributes: [String] { + return self + .map { $0.trimmedDescription } + .filter { !$0.starts(with: Self.spiKeyword) } + } +} + +extension InheritedTypeListSyntax { + + var conformances: [SDKDump.Element.Conformance] { + trimmedDescription + .split(separator: ",") + .map { .init(printedName: String($0).trimmingCharacters(in: .whitespacesAndNewlines)) } + } +} + +extension FunctionSignatureSyntax { + + var isThrowing: Bool { + trimmedDescription.range(of: "throws") != nil + } + + var isAsync: Bool { + trimmedDescription.range(of: "async") != nil + } +} + +// MARK: - Models + +public protocol Symbol { + var children: [Symbol] { get } +} + +indirect enum Scope { + + /// The root scope of a file + case root(symbols: [SDKDump.Element]) + /// A nested scope, within a parent scope + case nested(parent: Scope, symbols: [SDKDump.Element]) + + /// Starts a new nested scope + mutating func start() { + self = .nested(parent: self, symbols: []) + } + + /// Ends the current scope by adding a new symbol to the scope tree. + /// The children provided in the closure are the symbols in the scope to be ended + mutating func end(makeSymbolWithChildrenInScope: (_ children: [SDKDump.Element]) -> SDKDump.Element) { + let newSymbol = makeSymbolWithChildrenInScope(symbols) + + switch self { + case .root: + fatalError("Unbalanced calls to start() and end(_:)") + + case .nested(.root(let rootSymbols), _): + self = .root(symbols: rootSymbols + [newSymbol]) + + case .nested(.nested(let parent, let parentSymbols), _): + self = .nested(parent: parent, symbols: parentSymbols + [newSymbol]) + } + } + + /// Symbols at current scope + var symbols: [SDKDump.Element] { + switch self { + case .root(let symbols): return symbols + case .nested(_, let symbols): return symbols + } + } +} From 04fe183f310b0f9b075a22cbb6fe81d5a46b9df9 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Tue, 1 Oct 2024 11:20:50 +0200 Subject: [PATCH 02/45] Adding initial SwiftInterface parsing --- .../ReferencePackage/ReferencePackage.swift | 42 ++- .../Models/SDKDump/SDKDump+Element.swift | 24 +- ...ociatedTypeDeclSyntax+SwiftInterface.swift | 17 + .../ClassDeclSyntac+SwiftInterface.swift | 18 + .../EnumCaseDeclSyntax+SwiftInterface.swift | 29 ++ .../EnumDeclSyntax+SwiftInterface.swift | 18 + .../FunctionDeclSyntax+SwiftInterface.swift | 40 +++ .../ProtocolDeclSyntax+SwiftInterface.swift | 18 + .../StructDeclSyntax+SwiftInterface.swift | 18 + .../TypeAliasDeclSyntax+SwiftInterface.swift | 17 + .../VarDeclSyntax+SwiftInterface.swift | 31 ++ ...SwiftInterfaceElement+AssociatedType.swift | 73 +++++ .../SwiftInterfaceElement+Class.swift | 75 +++++ .../SwiftInterfaceElement+Enum.swift | 75 +++++ .../SwiftInterfaceElement+EnumCase.swift | 93 ++++++ .../SwiftInterfaceElement+Function.swift | 114 +++++++ .../SwiftInterfaceElement+Protocol.swift | 74 +++++ .../SwiftInterfaceElement+Struct.swift | 75 +++++ .../SwiftInterfaceElement+TypeAlias.swift | 72 ++++ .../SwiftInterfaceElement+Var.swift | 67 ++++ .../SwiftInterfaceElement.swift | 43 +++ .../SwiftInterface/SwiftInterfaceParser.swift | 184 +++++++++++ Tests/UnitTests/SwiftInterfaceTests.swift | 308 +----------------- Tests/public-api-diff.xctestplan | 78 +++++ 24 files changed, 1290 insertions(+), 313 deletions(-) create mode 100644 Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/AssociatedTypeDeclSyntax+SwiftInterface.swift create mode 100644 Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/ClassDeclSyntac+SwiftInterface.swift create mode 100644 Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/EnumCaseDeclSyntax+SwiftInterface.swift create mode 100644 Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/EnumDeclSyntax+SwiftInterface.swift create mode 100644 Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/FunctionDeclSyntax+SwiftInterface.swift create mode 100644 Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/ProtocolDeclSyntax+SwiftInterface.swift create mode 100644 Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/StructDeclSyntax+SwiftInterface.swift create mode 100644 Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/TypeAliasDeclSyntax+SwiftInterface.swift create mode 100644 Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/VarDeclSyntax+SwiftInterface.swift create mode 100644 Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+AssociatedType.swift create mode 100644 Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Class.swift create mode 100644 Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Enum.swift create mode 100644 Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+EnumCase.swift create mode 100644 Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Function.swift create mode 100644 Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Protocol.swift create mode 100644 Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Struct.swift create mode 100644 Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+TypeAlias.swift create mode 100644 Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Var.swift create mode 100644 Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement.swift create mode 100644 Tests/UnitTests/SwiftInterface/SwiftInterfaceParser.swift create mode 100644 Tests/public-api-diff.xctestplan diff --git a/ReferencePackages/UpdatedPackage/Sources/ReferencePackage/ReferencePackage.swift b/ReferencePackages/UpdatedPackage/Sources/ReferencePackage/ReferencePackage.swift index 27352e6..d2e367d 100644 --- a/ReferencePackages/UpdatedPackage/Sources/ReferencePackage/ReferencePackage.swift +++ b/ReferencePackages/UpdatedPackage/Sources/ReferencePackage/ReferencePackage.swift @@ -22,18 +22,34 @@ import Foundation // MARK: - Protocol with associatedtype -public protocol CustomProtocol { +public protocol ParentProtocol { + associatedtype ParentType: Equatable + associatedtype Iterator: Collection where Iterator.Element == ParentType +} + +public protocol CustomProtocol: ParentProtocol { associatedtype CustomAssociatedType: Equatable + associatedtype AnotherAssociatedType: Strideable - var getSetVar: CustomAssociatedType { get set } + var getSetVar: AnotherAssociatedType { get set } var getVar: CustomAssociatedType { get } func function() -> CustomAssociatedType } public struct CustomStruct: CustomProtocol { public typealias CustomAssociatedType = Int + public typealias AnotherAssociatedType = Double + public typealias Iterator = Array + + @available(macOS, unavailable, message: "Unavailable on macOS") + public struct NestedStruct { + @available(*, deprecated, renamed: "nestedVar") + public let nestedLet: String = "let" + @available(swift, introduced: 5.9) + public let nestedVar: String = "var" + } - public var getSetVar: Int + public var getSetVar: Double public var getVar: Int @discardableResult public func function() -> Int { 0 } @@ -51,8 +67,10 @@ public class CustomClass { package let constantLet: String = "I'm a let" public var optionalVar: T? + public let a = 0, b = 0, c = 0, d: Double = 5.0 + @MainActor - public func asyncThrowingFunc() async throws {} + public func asyncThrowingFunc(_ element: Element) async throws -> Void where Element: Strideable {} public func rethrowingFunc(throwingArg: @escaping () throws -> String) rethrows {} public init(weakObject: CustomClass? = nil, optionalVar: T? = nil) { @@ -70,13 +88,15 @@ public class CustomClass { // MARK: - Generic open class with Protocol conformance and @_spi constraint @_spi(SystemProgrammingInterface) -open class OpenSpiConformingClass: CustomProtocol { +open class OpenSpiConformingClass: CustomProtocol { public typealias CustomAssociatedType = T + public typealias AnotherAssociatedType = T + public typealias Iterator = Array public var getSetVar: T public var getVar: T @inlinable - public func function() -> T { getVar } + public func function() -> T where T: Equatable { getVar } public init(getSetVar: T, getVar: T) { self.getSetVar = getSetVar @@ -136,9 +156,15 @@ precedencegroup CustomPrecedence { public enum CustomEnum { case normalCase - case caseWithString(String) - case caseWithTuple(String, Int) + case caseWithNamedString(title: String) + case caseWithTuple(_ foo: String, bar: Int) case caseWithBlock((Int) throws -> Void) + case a, b, c, d, e(Int) indirect case recursive(CustomEnum) } + +public enum RawValueEnum: String { + case one + case two = "three" +} diff --git a/Sources/Helpers/Models/SDKDump/SDKDump+Element.swift b/Sources/Helpers/Models/SDKDump/SDKDump+Element.swift index 1a2849e..7c7505c 100644 --- a/Sources/Helpers/Models/SDKDump/SDKDump+Element.swift +++ b/Sources/Helpers/Models/SDKDump/SDKDump+Element.swift @@ -211,51 +211,51 @@ extension SDKDump.Element { var isFinal: Bool { guard declKind == .class else { return false } - return (declAttributes ?? []).contains("Final") + return (declAttributes ?? []).contains { $0.caseInsensitiveCompare("Final") == .orderedSame } } var hasDiscardableResult: Bool { - (declAttributes ?? []).contains("DiscardableResult") + (declAttributes ?? []).contains { $0.caseInsensitiveCompare("DiscardableResult") == .orderedSame } } var isObjcAccessible: Bool { - (declAttributes ?? []).contains("ObjC") + (declAttributes ?? []).contains { $0.caseInsensitiveCompare("ObjC") == .orderedSame } } var isOverride: Bool { - (declAttributes ?? []).contains("Override") + (declAttributes ?? []).contains { $0.caseInsensitiveCompare("Override") == .orderedSame } } var isDynamic: Bool { - (declAttributes ?? []).contains("Dynamic") + (declAttributes ?? []).contains { $0.caseInsensitiveCompare("Dynamic") == .orderedSame } } var isLazy: Bool { - (declAttributes ?? []).contains("Lazy") + (declAttributes ?? []).contains { $0.caseInsensitiveCompare("Lazy") == .orderedSame } } var isRequired: Bool { - (declAttributes ?? []).contains("Required") + (declAttributes ?? []).contains { $0.caseInsensitiveCompare("Required") == .orderedSame } } var isPrefix: Bool { - (declAttributes ?? []).contains("Prefix") + (declAttributes ?? []).contains { $0.caseInsensitiveCompare("Prefix") == .orderedSame } } var isPostfix: Bool { - (declAttributes ?? []).contains("Postfix") + (declAttributes ?? []).contains { $0.caseInsensitiveCompare("Postfix") == .orderedSame } } var isInfix: Bool { - (declAttributes ?? []).contains("Infix") + (declAttributes ?? []).contains { $0.caseInsensitiveCompare("Infix") == .orderedSame } } var isInlinable: Bool { - (declAttributes ?? []).contains("Inlinable") + (declAttributes ?? []).contains { $0.caseInsensitiveCompare("Inlinable") == .orderedSame } } var isIndirect: Bool { - (declAttributes ?? []).contains("Indirect") + (declAttributes ?? []).contains { $0.caseInsensitiveCompare("Indirect") == .orderedSame } } var isTypeInformation: Bool { diff --git a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/AssociatedTypeDeclSyntax+SwiftInterface.swift b/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/AssociatedTypeDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..244e1f5 --- /dev/null +++ b/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/AssociatedTypeDeclSyntax+SwiftInterface.swift @@ -0,0 +1,17 @@ +import SwiftSyntax +import SwiftParser + +/// See: https://swiftpackageindex.com/swiftlang/swift-syntax/documentation/swiftsyntax/associatedtypedeclsyntax-swift.struct +extension AssociatedTypeDeclSyntax { + + func toInterfaceElement() -> SwiftInterfaceAssociatedType { + SwiftInterfaceAssociatedType( + declarationAttributes: self.attributes.map { $0.trimmedDescription }, + modifiers: self.modifiers.map { $0.trimmedDescription }, + name: self.name.trimmedDescription, + inheritance: self.inheritanceClause?.inheritedTypes.map { $0.trimmedDescription }, + initializerValue: self.initializer?.value.trimmedDescription, + genericWhereClauseDescription: self.genericWhereClause?.trimmedDescription + ) + } +} diff --git a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/ClassDeclSyntac+SwiftInterface.swift b/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/ClassDeclSyntac+SwiftInterface.swift new file mode 100644 index 0000000..ce56c2e --- /dev/null +++ b/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/ClassDeclSyntac+SwiftInterface.swift @@ -0,0 +1,18 @@ +import SwiftSyntax +import SwiftParser + +/// See: https://swiftpackageindex.com/swiftlang/swift-syntax/documentation/swiftsyntax/classdeclsyntax +extension ClassDeclSyntax { + + func toInterfaceElement(children: [any SwiftInterfaceElement]) -> SwiftInterfaceClass { + SwiftInterfaceClass( + declarationAttributes: self.attributes.map { $0.trimmedDescription }, + modifiers: self.modifiers.map { $0.trimmedDescription }, + name: self.name.trimmedDescription, + genericParameterDescription: self.genericParameterClause?.trimmedDescription, + inheritance: self.inheritanceClause?.inheritedTypes.map { $0.trimmedDescription }, + genericWhereClauseDescription: self.genericWhereClause?.trimmedDescription, + children: children + ) + } +} diff --git a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/EnumCaseDeclSyntax+SwiftInterface.swift b/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/EnumCaseDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..e6f0ab3 --- /dev/null +++ b/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/EnumCaseDeclSyntax+SwiftInterface.swift @@ -0,0 +1,29 @@ +import SwiftSyntax +import SwiftParser + +/// See: https://swiftpackageindex.com/swiftlang/swift-syntax/documentation/swiftsyntax/enumcasedeclsyntax +extension EnumCaseDeclSyntax { + + func toInterfaceElement(children: [any SwiftInterfaceElement]) -> [SwiftInterfaceEnumCase] { + + let attributes = self.attributes.map { $0.trimmedDescription } + let modifiers = self.modifiers.map { $0.trimmedDescription } + + return elements.map { + SwiftInterfaceEnumCase( + declarationAttributes: attributes, + modifiers: modifiers, + name: $0.name.trimmedDescription, + parameters: $0.parameterClause?.parameters.map { + .init( + firstName: $0.firstName?.trimmedDescription, + secondName: $0.secondName?.trimmedDescription, + type: $0.type.trimmedDescription, + defaultValue: $0.defaultValue?.trimmedDescription + ) + }, + rawValue: $0.rawValue?.value.trimmedDescription + ) + } + } +} diff --git a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/EnumDeclSyntax+SwiftInterface.swift b/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/EnumDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..16c5496 --- /dev/null +++ b/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/EnumDeclSyntax+SwiftInterface.swift @@ -0,0 +1,18 @@ +import SwiftSyntax +import SwiftParser + +/// See: https://swiftpackageindex.com/swiftlang/swift-syntax/documentation/swiftsyntax/enumdeclsyntax +extension EnumDeclSyntax { + + func toInterfaceElement(children: [any SwiftInterfaceElement]) -> SwiftInterfaceEnum { + SwiftInterfaceEnum( + declarationAttributes: self.attributes.map { $0.trimmedDescription }, + modifiers: self.modifiers.map { $0.trimmedDescription }, + name: self.name.trimmedDescription, + genericParameterDescription: self.genericParameterClause?.trimmedDescription, + inheritance: self.inheritanceClause?.inheritedTypes.map { $0.trimmedDescription }, + genericWhereClauseDescription: self.genericWhereClause?.trimmedDescription, + children: children + ) + } +} diff --git a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/FunctionDeclSyntax+SwiftInterface.swift b/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/FunctionDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..421099d --- /dev/null +++ b/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/FunctionDeclSyntax+SwiftInterface.swift @@ -0,0 +1,40 @@ +import SwiftSyntax +import SwiftParser + +/// See: https://swiftpackageindex.com/swiftlang/swift-syntax/documentation/swiftsyntax/functiondeclsyntax +extension FunctionDeclSyntax { + + func toInterfaceElement() -> SwiftInterfaceFunction { + + var effectSpecifiers = [String]() + + if let effects = signature.effectSpecifiers { + if let asyncSpecifier = effects.asyncSpecifier { + effectSpecifiers.append(asyncSpecifier.trimmedDescription) + } + if let throwsClause = effects.throwsClause { + effectSpecifiers.append(throwsClause.trimmedDescription) + } + } + + let parameters: [SwiftInterfaceFunction.Parameter] = self.signature.parameterClause.parameters.map { + .init( + firstName: $0.firstName.trimmedDescription, + secondName: $0.secondName?.trimmedDescription, + type: $0.type.trimmedDescription, + defaultValue: $0.defaultValue?.trimmedDescription + ) + } + + return SwiftInterfaceFunction( + declarationAttributes: self.attributes.map { $0.trimmedDescription }, + modifiers: self.modifiers.map { $0.trimmedDescription }, + name: self.name.trimmedDescription, + genericParameterDescription: self.genericParameterClause?.trimmedDescription, + parameters: parameters, + effectSpecifiers: effectSpecifiers, + returnType: signature.returnClause?.type.trimmedDescription, + genericWhereClauseDescription: self.genericWhereClause?.trimmedDescription + ) + } +} diff --git a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/ProtocolDeclSyntax+SwiftInterface.swift b/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/ProtocolDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..fa5f760 --- /dev/null +++ b/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/ProtocolDeclSyntax+SwiftInterface.swift @@ -0,0 +1,18 @@ +import SwiftSyntax +import SwiftParser + +/// See: https://swiftpackageindex.com/swiftlang/swift-syntax/documentation/swiftsyntax/protocoldeclsyntax +extension ProtocolDeclSyntax { + + func toInterfaceElement(children: [any SwiftInterfaceElement]) -> SwiftInterfaceProtocol { + SwiftInterfaceProtocol( + declarationAttributes: self.attributes.map { $0.trimmedDescription }, + modifiers: self.modifiers.map { $0.trimmedDescription }, + name: self.name.trimmedDescription, + primaryAssociatedTypes: self.primaryAssociatedTypeClause?.primaryAssociatedTypes.map { $0.name.trimmedDescription }, + inheritance: self.inheritanceClause?.inheritedTypes.map { $0.trimmedDescription }, + genericWhereClauseDescription: self.genericWhereClause?.trimmedDescription, + children: children + ) + } +} diff --git a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/StructDeclSyntax+SwiftInterface.swift b/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/StructDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..f1c9fc2 --- /dev/null +++ b/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/StructDeclSyntax+SwiftInterface.swift @@ -0,0 +1,18 @@ +import SwiftSyntax +import SwiftParser + +/// See: https://swiftpackageindex.com/swiftlang/swift-syntax/documentation/swiftsyntax/structdeclsyntax +extension StructDeclSyntax { + + func toInterfaceElement(children: [any SwiftInterfaceElement]) -> SwiftInterfaceStruct { + SwiftInterfaceStruct( + declarationAttributes: self.attributes.map { $0.trimmedDescription }, + modifiers: self.modifiers.map { $0.trimmedDescription }, + name: self.name.trimmedDescription, + genericParameterDescription: self.genericParameterClause?.trimmedDescription, + inheritance: self.inheritanceClause?.inheritedTypes.map { $0.trimmedDescription }, + genericWhereClauseDescription: self.genericWhereClause?.trimmedDescription, + children: children + ) + } +} diff --git a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/TypeAliasDeclSyntax+SwiftInterface.swift b/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/TypeAliasDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..5bcff1f --- /dev/null +++ b/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/TypeAliasDeclSyntax+SwiftInterface.swift @@ -0,0 +1,17 @@ +import SwiftSyntax +import SwiftParser + +/// See: https://swiftpackageindex.com/swiftlang/swift-syntax/documentation/swiftsyntax/typealiasdeclsyntax-swift.struct +extension TypeAliasDeclSyntax { + + func toInterfaceElement(children: [any SwiftInterfaceElement]) -> SwiftInterfaceTypeAlias { + SwiftInterfaceTypeAlias( + declarationAttributes: self.attributes.map { $0.trimmedDescription }, + modifiers: self.modifiers.map { $0.trimmedDescription }, + name: self.name.trimmedDescription, + genericParameterDescription: self.genericParameterClause?.trimmedDescription, + initializerValue: self.initializer.value.trimmedDescription, + genericWhereClauseDescription: self.genericWhereClause?.trimmedDescription + ) + } +} diff --git a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/VarDeclSyntax+SwiftInterface.swift b/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/VarDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..fab0d76 --- /dev/null +++ b/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/VarDeclSyntax+SwiftInterface.swift @@ -0,0 +1,31 @@ +import SwiftSyntax +import SwiftParser + +/// See: https://swiftpackageindex.com/swiftlang/swift-syntax/documentation/swiftsyntax/structdeclsyntax +extension VariableDeclSyntax { + + func toInterfaceElement() -> [SwiftInterfaceVar] { + + let declarationAttributes = self.attributes.map { $0.trimmedDescription } + let modifiers = self.modifiers.map { $0.trimmedDescription } + let bindingSpecifier = self.bindingSpecifier.trimmedDescription + + // Transforming: + // - final public let a = 0, b = 1, c: Double = 5.0 + // Into: + // - final public let a: Int = 0 + // - final public let b: Int = 1 + // - final public let c: Double = 5.0 + return bindings.map { + return SwiftInterfaceVar( + declarationAttributes: declarationAttributes, + modifiers: modifiers, + bindingSpecifier: bindingSpecifier, + name: $0.pattern.trimmedDescription, + typeAnnotation: $0.typeAnnotation?.type.trimmedDescription, + initializerValue: $0.initializer?.value.trimmedDescription, + accessors: $0.accessorBlock?.accessors.trimmedDescription + ) + } + } +} diff --git a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+AssociatedType.swift b/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+AssociatedType.swift new file mode 100644 index 0000000..3585e88 --- /dev/null +++ b/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+AssociatedType.swift @@ -0,0 +1,73 @@ +@testable import public_api_diff +import Foundation + +struct SwiftInterfaceAssociatedType: SwiftInterfaceElement { + + var type: SDKDump.DeclarationKind { .struct } + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let declarationAttributes: [String] + + let name: String + + let inheritance: [String]? + + /// e.g. any Swift.Equatable + let initializerValue: String? + + /// e.g. public, private, package, open, internal + let modifiers: [String] + + /// e.g. where T : Equatable + let genericWhereClauseDescription: String? + + /// A associatedtype does not have children + let children: [any SwiftInterfaceElement] = [] + + var description: String { + compileDescription() + } + + init( + declarationAttributes: [String], + modifiers: [String], + name: String, + inheritance: [String]?, + initializerValue: String?, + genericWhereClauseDescription: String? + ) { + self.declarationAttributes = declarationAttributes + self.modifiers = modifiers + self.name = name + self.inheritance = inheritance + self.initializerValue = initializerValue + self.genericWhereClauseDescription = genericWhereClauseDescription + } +} + +private extension SwiftInterfaceAssociatedType { + + func compileDescription() -> String { + + var components = [String]() + + components += declarationAttributes + components += modifiers + components += ["associatedtype"] + + components += { + // Joining name + inheritance without a space + var components = [name] + if let inheritance, !inheritance.isEmpty { + components += [": \(inheritance.joined(separator: ", "))"] + } + return [components.joined()] + }() + + initializerValue.map { components += ["= \($0)"] } + + genericWhereClauseDescription.map { components += [$0] } + + return components.joined(separator: " ") + } +} diff --git a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Class.swift b/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Class.swift new file mode 100644 index 0000000..ef91839 --- /dev/null +++ b/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Class.swift @@ -0,0 +1,75 @@ +@testable import public_api_diff +import Foundation + +struct SwiftInterfaceClass: SwiftInterfaceElement { + + var type: SDKDump.DeclarationKind { .struct } + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let declarationAttributes: [String] + + let name: String + + /// e.g. + let genericParameterDescription: String? + + let inheritance: [String]? + + /// e.g. public, private, package, open, internal + let modifiers: [String] + + /// e.g. where T : Equatable + let genericWhereClauseDescription: String? + + /// The members, declarations, ... inside of the body of the struct + let children: [any SwiftInterfaceElement] + + var description: String { + compileDescription() + } + + init( + declarationAttributes: [String], + modifiers: [String], + name: String, + genericParameterDescription: String?, + inheritance: [String]?, + genericWhereClauseDescription: String?, + children: [any SwiftInterfaceElement] + ) { + self.declarationAttributes = declarationAttributes + self.name = name + self.genericParameterDescription = genericParameterDescription + self.inheritance = inheritance + self.modifiers = modifiers + self.genericWhereClauseDescription = genericWhereClauseDescription + self.children = children + } +} + +private extension SwiftInterfaceClass { + + func compileDescription() -> String { + + var components = [String]() + + components += declarationAttributes + components += modifiers + components += ["class"] + + components += [ + [ + name, + genericParameterDescription + ].compactMap { $0 }.joined() + ] + + if let inheritance, !inheritance.isEmpty { + components += [": \(inheritance.joined(separator: ", "))"] + } + + genericWhereClauseDescription.map { components += [$0] } + + return components.joined(separator: " ") + } +} diff --git a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Enum.swift b/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Enum.swift new file mode 100644 index 0000000..cdc592e --- /dev/null +++ b/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Enum.swift @@ -0,0 +1,75 @@ +@testable import public_api_diff +import Foundation + +struct SwiftInterfaceEnum: SwiftInterfaceElement { + + var type: SDKDump.DeclarationKind { .enum } + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let declarationAttributes: [String] + + /// e.g. public, private, package, open, internal + let modifiers: [String] + + let name: String + + /// e.g. + let genericParameterDescription: String? + + let inheritance: [String]? + + /// e.g. where T : Equatable + let genericWhereClauseDescription: String? + + /// The members, declarations, ... inside of the body of the struct + let children: [any SwiftInterfaceElement] + + var description: String { + compileDescription() + } + + init( + declarationAttributes: [String], + modifiers: [String], + name: String, + genericParameterDescription: String?, + inheritance: [String]?, + genericWhereClauseDescription: String?, + children: [any SwiftInterfaceElement] + ) { + self.declarationAttributes = declarationAttributes + self.name = name + self.genericParameterDescription = genericParameterDescription + self.inheritance = inheritance + self.modifiers = modifiers + self.genericWhereClauseDescription = genericWhereClauseDescription + self.children = children + } +} + +private extension SwiftInterfaceEnum { + + func compileDescription() -> String { + + var components = [String]() + + components += declarationAttributes + components += modifiers + components += ["enum"] + + components += [ + [ + name, + genericParameterDescription + ].compactMap { $0 }.joined() + ] + + if let inheritance, !inheritance.isEmpty { + components += [": \(inheritance.joined(separator: ", "))"] + } + + genericWhereClauseDescription.map { components += [$0] } + + return components.joined(separator: " ") + } +} diff --git a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+EnumCase.swift b/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+EnumCase.swift new file mode 100644 index 0000000..3f4a744 --- /dev/null +++ b/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+EnumCase.swift @@ -0,0 +1,93 @@ +@testable import public_api_diff +import Foundation + +extension SwiftInterfaceEnumCase { + + struct Parameter { + + let firstName: String? + + let secondName: String? + + let type: String + + let defaultValue: String? + + var description: String { + var description = [ + firstName, + secondName + ].compactMap { $0 }.joined(separator: " ") + + if description.isEmpty { + description += "\(type)" + } else { + description += ": \(type)" + } + + if let defaultValue { + description += " = \(defaultValue)" + } + + return description + } + } +} + +struct SwiftInterfaceEnumCase: SwiftInterfaceElement { + + var type: SDKDump.DeclarationKind { .case } + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let declarationAttributes: [String] + + /// e.g. public, private, package, open, internal + let modifiers: [String] + + let name: String + + let parameters: [Parameter]? + + let rawValue: String? + + /// A typealias does not have children + let children: [any SwiftInterfaceElement] = [] + + var description: String { + compileDescription() + } + + init( + declarationAttributes: [String], + modifiers: [String], + name: String, + parameters: [Parameter]?, + rawValue: String? + ) { + self.declarationAttributes = declarationAttributes + self.modifiers = modifiers + self.name = name + self.parameters = parameters + self.rawValue = rawValue + } +} + +private extension SwiftInterfaceEnumCase { + + func compileDescription() -> String { + + var components = [String]() + + components += declarationAttributes + components += modifiers + components += ["case"] + + if let parameters { + components += ["\(name)(\(parameters.map { $0.description }.joined(separator: ", ")))"] + } else { + components += [name] + } + + return components.joined(separator: " ") + } +} diff --git a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Function.swift b/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Function.swift new file mode 100644 index 0000000..ebe73f4 --- /dev/null +++ b/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Function.swift @@ -0,0 +1,114 @@ +@testable import public_api_diff +import Foundation + +extension SwiftInterfaceFunction { + + struct Parameter { + + let firstName: String + + /// optional second "internal" name - can be ignored + let secondName: String? + + let type: String + + let defaultValue: String? + + var description: String { + var description = [ + firstName, + secondName + ].compactMap { $0 }.joined(separator: " ") + + if description.isEmpty { + description += "\(type)" + } else { + description += ": \(type)" + } + + if let defaultValue { + description += " = \(defaultValue)" + } + + return description + } + } +} + +struct SwiftInterfaceFunction: SwiftInterfaceElement { + var type: SDKDump.DeclarationKind { .func } + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let declarationAttributes: [String] + + let name: String + + /// e.g. + let genericParameterDescription: String? + + let parameters: [Parameter] + + /// e.g. async, throws, rethrows + let effectSpecifiers: [String] + + /// e.g. public, private, package, open, internal + let modifiers: [String] + + let returnType: String + + /// e.g. where T : Equatable + let genericWhereClauseDescription: String? + + /// A function does not have children + let children: [any SwiftInterfaceElement] = [] + + var description: String { + compileDescription() + } + + init( + declarationAttributes: [String], + modifiers: [String], + name: String, + genericParameterDescription: String?, + parameters: [Parameter], + effectSpecifiers: [String], + returnType: String?, + genericWhereClauseDescription: String? + ) { + self.declarationAttributes = declarationAttributes + self.modifiers = modifiers + self.name = name + self.genericParameterDescription = genericParameterDescription + self.parameters = parameters + self.effectSpecifiers = effectSpecifiers + self.returnType = returnType ?? "Swift.Void" + self.genericWhereClauseDescription = genericWhereClauseDescription + } +} + +private extension SwiftInterfaceFunction { + + func compileDescription() -> String { + var components = [String]() + + components += declarationAttributes + components += modifiers + components += ["func"] + + components += [ + [ + name, + genericParameterDescription, + "(\(parameters.map { $0.description }.joined(separator: ", ")))" + ].compactMap { $0 }.joined() + ] + + components += effectSpecifiers + components += ["-> \(returnType)"] + + genericWhereClauseDescription.map { components += [$0] } + + return components.joined(separator: " ") + } +} diff --git a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Protocol.swift b/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Protocol.swift new file mode 100644 index 0000000..63f0b23 --- /dev/null +++ b/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Protocol.swift @@ -0,0 +1,74 @@ +@testable import public_api_diff +import Foundation + +struct SwiftInterfaceProtocol: SwiftInterfaceElement { + + var type: SDKDump.DeclarationKind { .protocol } + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let declarationAttributes: [String] + + let name: String + + let primaryAssociatedTypes: [String]? + + let inheritance: [String]? + + /// e.g. public, private, package, open, internal + let modifiers: [String] + + /// e.g. where T : Equatable + let genericWhereClauseDescription: String? + + /// The members, declarations, ... inside of the body of the struct + let children: [any SwiftInterfaceElement] + + var description: String { + compileDescription() + } + + init( + declarationAttributes: [String], + modifiers: [String], + name: String, + primaryAssociatedTypes: [String]?, + inheritance: [String]?, + genericWhereClauseDescription: String?, + children: [any SwiftInterfaceElement] + ) { + self.declarationAttributes = declarationAttributes + self.name = name + self.primaryAssociatedTypes = primaryAssociatedTypes + self.inheritance = inheritance + self.modifiers = modifiers + self.genericWhereClauseDescription = genericWhereClauseDescription + self.children = children + } +} + +private extension SwiftInterfaceProtocol { + + func compileDescription() -> String { + + var components = [String]() + + components += declarationAttributes + components += modifiers + components += ["protocol"] + + components += [ + [ + name, + primaryAssociatedTypes.map { "<\($0.joined(separator: ", "))>"} + ].compactMap { $0 }.joined() + ] + + if let inheritance, !inheritance.isEmpty { + components += [": \(inheritance.joined(separator: ", "))"] + } + + genericWhereClauseDescription.map { components += [$0] } + + return components.joined(separator: " ") + } +} diff --git a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Struct.swift b/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Struct.swift new file mode 100644 index 0000000..2bcb8db --- /dev/null +++ b/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Struct.swift @@ -0,0 +1,75 @@ +@testable import public_api_diff +import Foundation + +struct SwiftInterfaceStruct: SwiftInterfaceElement { + + var type: SDKDump.DeclarationKind { .struct } + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let declarationAttributes: [String] + + let name: String + + /// e.g. + let genericParameterDescription: String? + + let inheritance: [String]? + + /// e.g. public, private, package, open, internal + let modifiers: [String] + + /// e.g. where T : Equatable + let genericWhereClauseDescription: String? + + /// The members, declarations, ... inside of the body of the struct + let children: [any SwiftInterfaceElement] + + var description: String { + compileDescription() + } + + init( + declarationAttributes: [String], + modifiers: [String], + name: String, + genericParameterDescription: String?, + inheritance: [String]?, + genericWhereClauseDescription: String?, + children: [any SwiftInterfaceElement] + ) { + self.declarationAttributes = declarationAttributes + self.name = name + self.genericParameterDescription = genericParameterDescription + self.inheritance = inheritance + self.modifiers = modifiers + self.genericWhereClauseDescription = genericWhereClauseDescription + self.children = children + } +} + +private extension SwiftInterfaceStruct { + + func compileDescription() -> String { + + var components = [String]() + + components += declarationAttributes + components += modifiers + components += ["struct"] + + components += [ + [ + name, + genericParameterDescription + ].compactMap { $0 }.joined() + ] + + if let inheritance, !inheritance.isEmpty { + components += [": \(inheritance.joined(separator: ", "))"] + } + + genericWhereClauseDescription.map { components += [$0] } + + return components.joined(separator: " ") + } +} diff --git a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+TypeAlias.swift b/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+TypeAlias.swift new file mode 100644 index 0000000..b84af12 --- /dev/null +++ b/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+TypeAlias.swift @@ -0,0 +1,72 @@ +@testable import public_api_diff +import Foundation + +struct SwiftInterfaceTypeAlias: SwiftInterfaceElement { + + var type: SDKDump.DeclarationKind { .struct } + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let declarationAttributes: [String] + + let name: String + + /// e.g. + let genericParameterDescription: String? + + /// e.g. any Swift.Equatable + let initializerValue: String + + /// e.g. public, private, package, open, internal + let modifiers: [String] + + /// e.g. where T : Equatable + let genericWhereClauseDescription: String? + + /// A typealias does not have children + let children: [any SwiftInterfaceElement] = [] + + var description: String { + compileDescription() + } + + init( + declarationAttributes: [String], + modifiers: [String], + name: String, + genericParameterDescription: String?, + initializerValue: String, + genericWhereClauseDescription: String? + ) { + self.declarationAttributes = declarationAttributes + self.name = name + self.genericParameterDescription = genericParameterDescription + self.initializerValue = initializerValue + self.modifiers = modifiers + self.genericWhereClauseDescription = genericWhereClauseDescription + } +} + +private extension SwiftInterfaceTypeAlias { + + func compileDescription() -> String { + + var components = [String]() + + components += declarationAttributes + components += modifiers + components += ["typealias"] + + components += [ + [ + name, + genericParameterDescription + ].compactMap { $0 }.joined() + ] + + components += ["= \(initializerValue)"] + + genericWhereClauseDescription.map { components += [$0] } + + return components.joined(separator: " ") + } +} diff --git a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Var.swift b/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Var.swift new file mode 100644 index 0000000..d9a246c --- /dev/null +++ b/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Var.swift @@ -0,0 +1,67 @@ +@testable import public_api_diff +import Foundation + +struct SwiftInterfaceVar: SwiftInterfaceElement { + + var type: SDKDump.DeclarationKind { .struct } + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let declarationAttributes: [String] + + /// e.g. public, private, package, open, internal + let modifiers: [String] + + /// e.g. let | var | inout | _mutating | _borrowing | _consuming + let bindingSpecifier: String + + let name: String + + let typeAnnotation: String + + let initializerValue: String? + + let accessors: String? + + /// A var does not have children + let children: [any SwiftInterfaceElement] = [] + + var description: String { + compileDescription() + } + + init( + declarationAttributes: [String], + modifiers: [String], + bindingSpecifier: String, + name: String, + typeAnnotation: String?, + initializerValue: String?, + accessors: String? + ) { + self.declarationAttributes = declarationAttributes + self.modifiers = modifiers + self.bindingSpecifier = bindingSpecifier + self.name = name + self.typeAnnotation = typeAnnotation ?? "UNKNOWN_TYPE" + self.initializerValue = initializerValue + self.accessors = accessors + } +} + +private extension SwiftInterfaceVar { + + func compileDescription() -> String { + + var components = [String]() + + components += declarationAttributes + components += modifiers + components += [bindingSpecifier] + components += ["\(name): \(typeAnnotation)"] + + initializerValue.map { components += ["= \($0)"] } + accessors.map { components += ["{ \($0) }"] } + + return components.joined(separator: " ") + } +} diff --git a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement.swift b/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement.swift new file mode 100644 index 0000000..db69992 --- /dev/null +++ b/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement.swift @@ -0,0 +1,43 @@ +@testable import public_api_diff +import Foundation + +protocol SwiftInterfaceElement: CustomStringConvertible { + var type: SDKDump.DeclarationKind { get } + var description: String { get } + var children: [any SwiftInterfaceElement] { get } +} + +extension SwiftInterfaceElement { + func recursiveDescription(indentation: Int = 0) -> String { + let spacer = " " + var recursiveDescription = "\(String(repeating: spacer, count: indentation))\(description)" + if !self.children.isEmpty { + recursiveDescription.append("\n\(String(repeating: spacer, count: indentation)){") + for child in self.children { + recursiveDescription.append("\n\(String(repeating: spacer, count: indentation))\(child.recursiveDescription(indentation: indentation + 1))") + } + recursiveDescription.append("\n\(String(repeating: spacer, count: indentation))}") + } + return recursiveDescription + } +} + +extension SwiftInterfaceElement { + var isSpiInternal: Bool { + description.range(of: "@_spi(") != nil + } +} + +struct Placeholder: SwiftInterfaceElement { + let type: SDKDump.DeclarationKind + let children: [any SwiftInterfaceElement] + + var description: String { + return "\(type) Placeholder" + } + + init(type: SDKDump.DeclarationKind, children: [any SwiftInterfaceElement] = []) { + self.type = type + self.children = children + } +} diff --git a/Tests/UnitTests/SwiftInterface/SwiftInterfaceParser.swift b/Tests/UnitTests/SwiftInterface/SwiftInterfaceParser.swift new file mode 100644 index 0000000..4db6d74 --- /dev/null +++ b/Tests/UnitTests/SwiftInterface/SwiftInterfaceParser.swift @@ -0,0 +1,184 @@ +@testable import public_api_diff +import Foundation +import SwiftSyntax +import SwiftParser + +/** + Inspired by: https://github.com/sdidla/Hatch/blob/main/Sources/Hatch/SymbolParser.swift + Documentation about DeclSyntax: + - https://swiftpackageindex.com/swiftlang/swift-syntax/600.0.1/documentation/swiftsyntax/declsyntax + */ +class SwiftInterfaceParser: SyntaxVisitor { + + private var scope: Scope = .root(symbols: []) + + static public func parse(source: String) -> [any SwiftInterfaceElement] { + let visitor = Self() + visitor.walk(Parser.parse(source: source)) + return visitor.scope.symbols + } + + /// Designated initializer + required public init() { + super.init(viewMode: .sourceAccurate) + } + + /// Starts a new scope which can contain zero or more nested symbols + public func startScope() -> SyntaxVisitorContinueKind { + scope.start() + return .visitChildren + } + + /// Ends the current scope and adds the symbol returned by the closure to the symbol tree + /// - Parameter makeSymbolWithChildrenInScope: Closure that return a new ``Symbol`` + /// + /// Call in `visitPost(_ node:)` methods + public func endScopeAndAddSymbol(makeSymbolsWithChildrenInScope: (_ children: [any SwiftInterfaceElement]) -> [any SwiftInterfaceElement]) { + scope.end(makeSymbolsWithChildrenInScope: makeSymbolsWithChildrenInScope) + } + + // TODO: + // - InitializerDeclSyntax + // - DeinitializerDeclSyntax + // - ActorDeclSyntax + // - AccessorDeclSyntax + // - ExtensionDeclSyntax + // + // Nice to have: + // - PrecedenceGroupDeclSyntax + // - OperatorDeclSyntax + // - SubscriptDeclSyntax + // - IfConfigClauseListSyntax + // - ... (There are more but not important right now) + + // MARK: - Class + + open override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind { + startScope() + } + + open override func visitPost(_ node: ClassDeclSyntax) { + endScopeAndAddSymbol { [node.toInterfaceElement(children: $0)] } + } + + // MARK: - Struct + + open override func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind { + startScope() + } + + open override func visitPost(_ node: StructDeclSyntax) { + endScopeAndAddSymbol { [node.toInterfaceElement(children: $0)] } + } + + // MARK: - TypeAlias + + open override func visit(_ node: TypeAliasDeclSyntax) -> SyntaxVisitorContinueKind { + startScope() + } + + open override func visitPost(_ node: TypeAliasDeclSyntax) { + endScopeAndAddSymbol { [node.toInterfaceElement(children: $0)] } + } + + // MARK: - Function + + open override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind { + startScope() + } + + open override func visitPost(_ node: FunctionDeclSyntax) { + endScopeAndAddSymbol { _ in [node.toInterfaceElement()] } + } + + // MARK: - Var + + open override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind { + startScope() + } + + open override func visitPost(_ node: VariableDeclSyntax) { + endScopeAndAddSymbol { _ in node.toInterfaceElement() } + } + + // MARK: - AssociatedType + + open override func visit(_ node: AssociatedTypeDeclSyntax) -> SyntaxVisitorContinueKind { + startScope() + } + + open override func visitPost(_ node: AssociatedTypeDeclSyntax) { + endScopeAndAddSymbol { _ in [node.toInterfaceElement()] } + } + + // MARK: - Protocol + + open override func visit(_ node: ProtocolDeclSyntax) -> SyntaxVisitorContinueKind { + startScope() + } + + open override func visitPost(_ node: ProtocolDeclSyntax) { + endScopeAndAddSymbol { [node.toInterfaceElement(children: $0)] } + } + + // MARK: - Enum + + open override func visit(_ node: EnumDeclSyntax) -> SyntaxVisitorContinueKind { + startScope() + } + + open override func visitPost(_ node: EnumDeclSyntax) { + endScopeAndAddSymbol { [node.toInterfaceElement(children: $0)] } + } + + // MARK: - EnumCase + + open override func visit(_ node: EnumCaseDeclSyntax) -> SyntaxVisitorContinueKind { + startScope() + } + + open override func visitPost(_ node: EnumCaseDeclSyntax) { + endScopeAndAddSymbol { node.toInterfaceElement(children: $0) } + } +} + +// MARK: - Models + +/// Inspired by: https://github.com/sdidla/Hatch/blob/main/Sources/Hatch/SymbolParser.swift +indirect enum Scope { + + /// The root scope of a file + case root(symbols: [any SwiftInterfaceElement]) + /// A nested scope, within a parent scope + case nested(parent: Scope, symbols: [any SwiftInterfaceElement]) + + /// Starts a new nested scope + mutating func start() { + self = .nested(parent: self, symbols: []) + } + + /// Ends the current scope by adding a new symbol to the scope tree. + /// The children provided in the closure are the symbols in the scope to be ended + mutating func end(makeSymbolsWithChildrenInScope: (_ children: [any SwiftInterfaceElement]) -> [any SwiftInterfaceElement]) { + let newSymbols = makeSymbolsWithChildrenInScope(symbols) + + switch self { + case .root: + fatalError("Unbalanced calls to start() and end(_:)") + + case .nested(.root(let rootSymbols), _): + self = .root(symbols: rootSymbols + newSymbols) + + case .nested(.nested(let parent, let parentSymbols), _): + self = .nested(parent: parent, symbols: parentSymbols + newSymbols) + } + } + + /// Symbols at current scope + var symbols: [any SwiftInterfaceElement] { + switch self { + case .root(let symbols): return symbols + case .nested(_, let symbols): return symbols + } + } +} diff --git a/Tests/UnitTests/SwiftInterfaceTests.swift b/Tests/UnitTests/SwiftInterfaceTests.swift index 99ff4b7..734a14a 100644 --- a/Tests/UnitTests/SwiftInterfaceTests.swift +++ b/Tests/UnitTests/SwiftInterfaceTests.swift @@ -8,9 +8,6 @@ @testable import public_api_diff import XCTest -import SwiftSyntax -import SwiftParser - class SwiftInterfaceTests: XCTestCase { func test_swiftinterface() throws { @@ -30,19 +27,30 @@ class SwiftInterfaceTests: XCTestCase { }() let oldSource: String = try { + let oldReferencePackageDirectory = referencePackagesRoot.appending(path: "ReferencePackage") - let interfaceFilePath = try XCTUnwrap(oldReferencePackageDirectory.appending(path: "Sources/ReferencePackage/ReferencePackage.swift")) + let interfaceFilePath = try XCTUnwrap(oldReferencePackageDirectory.appending(path: "_build/Build/Products/Debug-iphoneos/ReferencePackage.swiftmodule/arm64-apple-ios.private.swiftinterface")) let interfaceFileContent = try XCTUnwrap(FileManager.default.contents(atPath: interfaceFilePath.path())) return try XCTUnwrap(String(data: interfaceFileContent, encoding: .utf8)) }() let newSource: String = try { let newReferencePackageDirectory = referencePackagesRoot.appending(path: "UpdatedPackage") - let interfaceFilePath = try XCTUnwrap(newReferencePackageDirectory.appending(path: "Sources/ReferencePackage/ReferencePackage.swift")) + let interfaceFilePath = try XCTUnwrap(newReferencePackageDirectory.appending(path: "_build/Build/Products/Debug-iphoneos/ReferencePackage.swiftmodule/arm64-apple-ios.private.swiftinterface")) let interfaceFileContent = try XCTUnwrap(FileManager.default.contents(atPath: interfaceFilePath.path())) return try XCTUnwrap(String(data: interfaceFileContent, encoding: .utf8)) }() + + print("----- OLD -----") + SwiftInterfaceParser.parse(source: oldSource).forEach { element in + print(element.recursiveDescription()) + } + print("----- NEW -----") + SwiftInterfaceParser.parse(source: newSource).forEach { element in + print(element.recursiveDescription()) + } + /* let oldRoot = SDKDump( root: .init( kind: .root, @@ -62,6 +70,7 @@ class SwiftInterfaceTests: XCTestCase { ) let changes = SDKDumpAnalyzer().analyze(old: oldRoot, new: newRoot) + let markdownOutput = MarkdownOutputGenerator().generate( from: ["ReferencePackage": changes], allTargets: ["ReferencePackage"], @@ -71,293 +80,6 @@ class SwiftInterfaceTests: XCTestCase { ) XCTAssertEqual(markdownOutput, expectedOutput) - } -} - -/** - Inspired by: https://github.com/sdidla/Hatch/blob/main/Sources/Hatch/SymbolParser.swift - */ -class SwiftInterfaceVisitor: SyntaxVisitor { - - /* - if hasDiscardableResult { components += ["@discardableResult"] } - if isObjcAccessible { components += ["@objc"] } - if isInlinable { components += ["@inlinable"] } - if isOverride { components += ["override"] } - if declKind != .import && declKind != .case { - if isOpen { - components += ["open"] - } else if isInternal { - components += ["internal"] - } else { - components += ["public"] - } - } - if isFinal { components += ["final"] } - if isIndirect { components += ["indirect"] } - if isRequired { components += ["required"] } - if isStatic { components += ["static"] } - if isConvenienceInit { components += ["convenience"] } - if isDynamic { components += ["dynamic"] } - if isPrefix { components += ["prefix"] } - if isPostfix { components += ["postfix"] } - if isInfix { components += ["infix"] } - */ - - private var scope: Scope = .root(symbols: []) - - static public func parse(source: String) -> [SDKDump.Element] { - let visitor = Self() - visitor.walk(Parser.parse(source: source)) - return visitor.scope.symbols - } - - /// Designated initializer - required public init() { - super.init(viewMode: .sourceAccurate) - } - - /// Starts a new scope which can contain zero or more nested symbols - public func startScope() -> SyntaxVisitorContinueKind { - scope.start() - return .visitChildren - } - - /// Ends the current scope and adds the symbol returned by the closure to the symbol tree - /// - Parameter makeSymbolWithChildrenInScope: Closure that return a new ``Symbol`` - /// - /// Call in `visitPost(_ node:)` methods - public func endScopeAndAddSymbol(makeSymbolWithChildrenInScope: (_ children: [SDKDump.Element]) -> SDKDump.Element) { - scope.end(makeSymbolWithChildrenInScope: makeSymbolWithChildrenInScope) - } - - // MARK: Class - - open override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind { - startScope() - } - - open override func visitPost(_ node: ClassDeclSyntax) { - let name: String = node.name.text - - endScopeAndAddSymbol { children in - SDKDump.Element( - kind: .class, - name: name, - printedName: name, - declKind: .class, - children: children, - spiGroupNames: node.attributes.spiGroupNames, - declAttributes: node.attributes.declAttributes, - conformances: node.inheritanceClause?.inheritedTypes.conformances - ) - } - } - - // MARK: Struct - - open override func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind { - startScope() - } - - open override func visitPost(_ node: StructDeclSyntax) { - let name: String = node.name.text - - endScopeAndAddSymbol { children in - SDKDump.Element( - kind: .struct, - name: name, - printedName: name, - declKind: .struct, - children: children, - spiGroupNames: node.attributes.spiGroupNames, - declAttributes: node.attributes.declAttributes, - conformances: node.inheritanceClause?.inheritedTypes.conformances - ) - } - } - - // MARK: Var - - open override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind { - startScope() - } - - open override func visitPost(_ node: VariableDeclSyntax) { - let components = node.bindings.description.split(separator: ":") - guard components.count == 2 else { return } - let name = components[0].trimmingCharacters(in: .whitespacesAndNewlines) - let type = components[1].trimmingCharacters(in: .whitespacesAndNewlines) - - endScopeAndAddSymbol { children in - let varElement = SDKDump.Element( - kind: .var, - name: name, - printedName: name, - declKind: .var, - isLet: node.bindingSpecifier.text == "let", - children: [.init(kind: .typeNominal, name: type, printedName: type)], - spiGroupNames: node.attributes.spiGroupNames, - declAttributes: node.attributes.declAttributes - ) - return varElement - } - } - - // MARK: TypeAlias - - open override func visit(_ node: TypeAliasDeclSyntax) -> SyntaxVisitorContinueKind { - startScope() - } - - open override func visitPost(_ node: TypeAliasDeclSyntax) { - let type = SDKDump.Element( - kind: .typeNominal, - name: node.initializer.value.description, - printedName: node.initializer.value.description - ) - - endScopeAndAddSymbol { children in - let varElement = SDKDump.Element( - kind: .typeAlias, - name: node.name.text, - printedName: node.name.text, - declKind: .typeAlias, - children: [type], - spiGroupNames: node.attributes.spiGroupNames, - declAttributes: node.attributes.declAttributes - ) - return varElement - } - } - - // MARK: AssociatedType - - open override func visit(_ node: AssociatedTypeDeclSyntax) -> SyntaxVisitorContinueKind { - startScope() - } - - open override func visitPost(_ node: AssociatedTypeDeclSyntax) { - endScopeAndAddSymbol { children in - let varElement = SDKDump.Element( - kind: .associatedtype, - name: node.name.text, - printedName: node.name.text, - declKind: .associatedType, - children: children, - spiGroupNames: node.attributes.spiGroupNames, - declAttributes: node.attributes.declAttributes - ) - return varElement - } - } - - // MARK: Function - - open override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind { - startScope() - } - - open override func visitPost(_ node: FunctionDeclSyntax) { - endScopeAndAddSymbol { children in - let varElement = SDKDump.Element( - kind: .func, - name: node.name.text, - printedName: node.name.text, - declKind: .func, - isThrowing: node.signature.isThrowing, - children: children, - spiGroupNames: node.attributes.spiGroupNames, - declAttributes: node.attributes.declAttributes - ) - return varElement - } - } -} - -// MARK: - Convenience - -extension AttributeListSyntax { - private static var spiKeyword: String { "@_spi" } - - var spiGroupNames: [String] { - return self - .map { $0.trimmedDescription } - .filter { $0.starts(with: Self.spiKeyword) } - .map { element in - element - .replacingOccurrences(of: "\(Self.spiKeyword)(", with: "") - .replacingOccurrences(of: ")", with: "") - } - } - - var declAttributes: [String] { - return self - .map { $0.trimmedDescription } - .filter { !$0.starts(with: Self.spiKeyword) } - } -} - -extension InheritedTypeListSyntax { - - var conformances: [SDKDump.Element.Conformance] { - trimmedDescription - .split(separator: ",") - .map { .init(printedName: String($0).trimmingCharacters(in: .whitespacesAndNewlines)) } - } -} - -extension FunctionSignatureSyntax { - - var isThrowing: Bool { - trimmedDescription.range(of: "throws") != nil - } - - var isAsync: Bool { - trimmedDescription.range(of: "async") != nil - } -} - -// MARK: - Models - -public protocol Symbol { - var children: [Symbol] { get } -} - -indirect enum Scope { - - /// The root scope of a file - case root(symbols: [SDKDump.Element]) - /// A nested scope, within a parent scope - case nested(parent: Scope, symbols: [SDKDump.Element]) - - /// Starts a new nested scope - mutating func start() { - self = .nested(parent: self, symbols: []) - } - - /// Ends the current scope by adding a new symbol to the scope tree. - /// The children provided in the closure are the symbols in the scope to be ended - mutating func end(makeSymbolWithChildrenInScope: (_ children: [SDKDump.Element]) -> SDKDump.Element) { - let newSymbol = makeSymbolWithChildrenInScope(symbols) - - switch self { - case .root: - fatalError("Unbalanced calls to start() and end(_:)") - - case .nested(.root(let rootSymbols), _): - self = .root(symbols: rootSymbols + [newSymbol]) - - case .nested(.nested(let parent, let parentSymbols), _): - self = .nested(parent: parent, symbols: parentSymbols + [newSymbol]) - } - } - - /// Symbols at current scope - var symbols: [SDKDump.Element] { - switch self { - case .root(let symbols): return symbols - case .nested(_, let symbols): return symbols - } + */ } } diff --git a/Tests/public-api-diff.xctestplan b/Tests/public-api-diff.xctestplan new file mode 100644 index 0000000..6c20474 --- /dev/null +++ b/Tests/public-api-diff.xctestplan @@ -0,0 +1,78 @@ +{ + "configurations" : [ + { + "id" : "9DDDA981-B384-431F-8F11-E82A5CD39CBA", + "name" : "Test Scheme Action", + "options" : { + + } + } + ], + "defaultOptions" : { + "commandLineArgumentEntries" : [ + { + "argument" : "--new 5.10.0~https:\/\/github.com\/Adyen\/adyen-ios" + }, + { + "argument" : "--old 5.0.0~https:\/\/github.com\/Adyen\/adyen-ios" + }, + { + "argument" : "--new main~https:\/\/github.com\/Adyen\/adyen-pos-mobile-ios", + "enabled" : false + }, + { + "argument" : "--old v2.0.0~https:\/\/github.com\/Adyen\/adyen-pos-mobile-ios", + "enabled" : false + }, + { + "argument" : "--new \/Users\/alexandergu\/Code\/adyen-3ds2-ios_new", + "enabled" : false + }, + { + "argument" : "--old \/Users\/alexandergu\/Code\/adyen-3ds2-ios", + "enabled" : false + }, + { + "argument" : "--scheme Adyen3DS2_Swift", + "enabled" : false + } + ], + "targetForVariableExpansion" : { + "containerPath" : "container:", + "identifier" : "public-api-diff", + "name" : "public-api-diff" + } + }, + "testTargets" : [ + { + "enabled" : false, + "target" : { + "containerPath" : "container:", + "identifier" : "IntegrationTests", + "name" : "IntegrationTests" + } + }, + { + "skippedTests" : [ + "ABIGeneratorTests", + "FileHandlingTests", + "GitTests", + "OutputGeneratorTests", + "PipelineTests", + "ProjectBuilderTests", + "ProjectSourceTests", + "SDKDumpAnalyzerTests", + "SDKDumpGeneratorTests", + "SDKDumpTests", + "SwiftPackageFileAnalyzerTests", + "XcodeToolsTests" + ], + "target" : { + "containerPath" : "container:", + "identifier" : "UnitTests", + "name" : "UnitTests" + } + } + ], + "version" : 1 +} From 8414daec2fc746e949bb801cd511abaac97d451e Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Tue, 1 Oct 2024 20:32:08 +0200 Subject: [PATCH 03/45] Started work on change detection --- .../ReferencePackage/ReferencePackage.swift | 50 ++++++- Sources/Helpers/Models/Change.swift | 2 +- .../Helpers/Models/IndependentChange.swift | 32 +++- .../AccessorBlockSyntax+Convenience.swift | 7 + .../SyntaxCollection+Convenience.swift | 7 + .../ActorDeclSyntax+SwiftInterface.swift | 17 +++ ...ociatedTypeDeclSyntax+SwiftInterface.swift | 6 +- .../ClassDeclSyntac+SwiftInterface.swift | 6 +- .../EnumCaseDeclSyntax+SwiftInterface.swift | 8 +- .../EnumDeclSyntax+SwiftInterface.swift | 6 +- .../ExtensionDeclSyntax+SwiftInterface.swift | 17 +++ .../FunctionDeclSyntax+SwiftInterface.swift | 6 +- ...InitializerDeclSyntax+SwiftInterface.swift | 40 +++++ .../ProtocolDeclSyntax+SwiftInterface.swift | 6 +- .../StructDeclSyntax+SwiftInterface.swift | 6 +- .../SubscriptDeclSyntax+SwiftInterface.swift | 28 ++++ .../TypeAliasDeclSyntax+SwiftInterface.swift | 4 +- .../VarDeclSyntax+SwiftInterface.swift | 8 +- .../SwiftInterfaceElement+Actor.swift | 86 +++++++++++ ...SwiftInterfaceElement+AssociatedType.swift | 38 +++-- .../SwiftInterfaceElement+Class.swift | 41 ++++-- .../SwiftInterfaceElement+Enum.swift | 41 ++++-- .../SwiftInterfaceElement+EnumCase.swift | 25 +++- .../SwiftInterfaceElement+Extension.swift | 75 ++++++++++ .../SwiftInterfaceElement+Function.swift | 24 ++- .../SwiftInterfaceElement+Initializer.swift | 120 +++++++++++++++ .../SwiftInterfaceElement+Protocol.swift | 41 ++++-- .../SwiftInterfaceElement+Struct.swift | 41 ++++-- .../SwiftInterfaceElement+Subscript.swift | 121 +++++++++++++++ .../SwiftInterfaceElement+TypeAlias.swift | 25 +++- .../SwiftInterfaceElement+Var.swift | 25 +++- .../SwiftInterfaceElement.swift | 95 ++++++++++++ .../Modules/MarkdownOutputGenerator.swift | 2 +- .../SDKDumpAnalyzer/SDKDumpAnalyzer.swift | 23 ++- ....swift => SDKDumpChangeConsolidator.swift} | 25 ++-- .../SwiftInterfaceAnalyzer.swift | 125 ++++++++++++++++ .../SwiftInterfaceChangeConsolidator.swift | 138 ++++++++++++++++++ .../SwiftInterfaceParser.swift | 129 +++++++++++----- .../Modules/SwiftPackageFileAnalyzer.swift | 4 +- Sources/Pipeline/Pipeline.swift | 4 +- .../ReferencePackageTests.swift | 2 + Tests/UnitTests/OutputGeneratorTests.swift | 10 +- Tests/UnitTests/PipelineTests.swift | 8 +- Tests/UnitTests/SDKDumpAnalyzerTests.swift | 24 +-- .../SwiftInterfaceElement.swift | 43 ------ Tests/UnitTests/SwiftInterfaceTests.swift | 22 ++- .../SwiftPackageFileAnalyzerTests.swift | 4 +- 47 files changed, 1340 insertions(+), 277 deletions(-) create mode 100644 Sources/Helpers/Models/SwiftInterface/DeclSyntax+Convenience/AccessorBlockSyntax+Convenience.swift create mode 100644 Sources/Helpers/Models/SwiftInterface/DeclSyntax+Convenience/SyntaxCollection+Convenience.swift create mode 100644 Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/ActorDeclSyntax+SwiftInterface.swift rename {Tests/UnitTests => Sources/Helpers/Models}/SwiftInterface/DeclSyntax+SwiftInterface/AssociatedTypeDeclSyntax+SwiftInterface.swift (76%) rename {Tests/UnitTests => Sources/Helpers/Models}/SwiftInterface/DeclSyntax+SwiftInterface/ClassDeclSyntac+SwiftInterface.swift (77%) rename {Tests/UnitTests => Sources/Helpers/Models}/SwiftInterface/DeclSyntax+SwiftInterface/EnumCaseDeclSyntax+SwiftInterface.swift (76%) rename {Tests/UnitTests => Sources/Helpers/Models}/SwiftInterface/DeclSyntax+SwiftInterface/EnumDeclSyntax+SwiftInterface.swift (77%) create mode 100644 Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/ExtensionDeclSyntax+SwiftInterface.swift rename {Tests/UnitTests => Sources/Helpers/Models}/SwiftInterface/DeclSyntax+SwiftInterface/FunctionDeclSyntax+SwiftInterface.swift (86%) create mode 100644 Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/InitializerDeclSyntax+SwiftInterface.swift rename {Tests/UnitTests => Sources/Helpers/Models}/SwiftInterface/DeclSyntax+SwiftInterface/ProtocolDeclSyntax+SwiftInterface.swift (79%) rename {Tests/UnitTests => Sources/Helpers/Models}/SwiftInterface/DeclSyntax+SwiftInterface/StructDeclSyntax+SwiftInterface.swift (77%) create mode 100644 Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/SubscriptDeclSyntax+SwiftInterface.swift rename {Tests/UnitTests => Sources/Helpers/Models}/SwiftInterface/DeclSyntax+SwiftInterface/TypeAliasDeclSyntax+SwiftInterface.swift (80%) rename {Tests/UnitTests => Sources/Helpers/Models}/SwiftInterface/DeclSyntax+SwiftInterface/VarDeclSyntax+SwiftInterface.swift (76%) create mode 100644 Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Actor.swift rename {Tests/UnitTests => Sources/Helpers/Models}/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+AssociatedType.swift (69%) rename {Tests/UnitTests => Sources/Helpers/Models}/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Class.swift (68%) rename {Tests/UnitTests => Sources/Helpers/Models}/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Enum.swift (69%) rename {Tests/UnitTests => Sources/Helpers/Models}/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+EnumCase.swift (82%) create mode 100644 Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Extension.swift rename {Tests/UnitTests => Sources/Helpers/Models}/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Function.swift (84%) create mode 100644 Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Initializer.swift rename {Tests/UnitTests => Sources/Helpers/Models}/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Protocol.swift (69%) rename {Tests/UnitTests => Sources/Helpers/Models}/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Struct.swift (70%) create mode 100644 Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Subscript.swift rename {Tests/UnitTests => Sources/Helpers/Models}/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+TypeAlias.swift (78%) rename {Tests/UnitTests => Sources/Helpers/Models}/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Var.swift (77%) create mode 100644 Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement.swift rename Sources/Pipeline/Modules/SDKDumpAnalyzer/{ChangeConsolidator.swift => SDKDumpChangeConsolidator.swift} (88%) create mode 100644 Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceAnalyzer.swift create mode 100644 Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceChangeConsolidator.swift rename {Tests/UnitTests/SwiftInterface => Sources/Pipeline/Modules/SwiftInterfaceParser}/SwiftInterfaceParser.swift (56%) delete mode 100644 Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement.swift diff --git a/ReferencePackages/UpdatedPackage/Sources/ReferencePackage/ReferencePackage.swift b/ReferencePackages/UpdatedPackage/Sources/ReferencePackage/ReferencePackage.swift index d2e367d..0922d71 100644 --- a/ReferencePackages/UpdatedPackage/Sources/ReferencePackage/ReferencePackage.swift +++ b/ReferencePackages/UpdatedPackage/Sources/ReferencePackage/ReferencePackage.swift @@ -22,6 +22,8 @@ import Foundation // MARK: - Protocol with associatedtype +public protocol SimpleProtocol {} + public protocol ParentProtocol { associatedtype ParentType: Equatable associatedtype Iterator: Collection where Iterator.Element == ParentType @@ -60,7 +62,7 @@ public struct CustomStruct: CustomProtocol { public class CustomClass { public weak var weakObject: CustomClass? - lazy var lazyVar: String = { "I am a lazy" }() + public lazy var lazyVar: String = { "I am a lazy" }() @_spi(SomeSpi) @_spi(AnotherSpi) open var computedVar: String { "I am computed" } @@ -76,13 +78,27 @@ public class CustomClass { public init(weakObject: CustomClass? = nil, optionalVar: T? = nil) { self.weakObject = weakObject self.optionalVar = optionalVar + + lazyVar = "Great!" } - public init() {} + public init?() {} - public convenience init(value: T) { + public convenience init!(value: T) { self.init(optionalVar: value) } + + public subscript(index: Int) -> T? { + get { optionalVar } + set { optionalVar = newValue } + } +} + +extension Array { + public subscript(safe index: Int) -> Element? { + guard index >= 0, index < self.count else { return nil } + return self[index] + } } // MARK: - Generic open class with Protocol conformance and @_spi constraint @@ -122,7 +138,7 @@ public class ObjcClass: NSObject { // MARK: - Actor -public actor CustomActor {} +public actor CustomActor: SimpleProtocol {} // MARK: - Operators @@ -154,12 +170,12 @@ precedencegroup CustomPrecedence { // MARK: - Enums -public enum CustomEnum { +public enum CustomEnum { case normalCase - case caseWithNamedString(title: String) + case caseWithNamedString(title: T) case caseWithTuple(_ foo: String, bar: Int) case caseWithBlock((Int) throws -> Void) - case a, b, c, d, e(Int) + case a, b, c, d, e(NestedStructInExtension) indirect case recursive(CustomEnum) } @@ -168,3 +184,23 @@ public enum RawValueEnum: String { case one case two = "three" } + +extension CustomEnum: SimpleProtocol { + + public struct NestedStructInExtension { + public let string: String + public init(string: String = "Hello") { + self.string = string + } + } +} + +public extension CustomEnum where T == String { + + var titleOfCaseWithNamedString: String? { + if case let .caseWithNamedString(title) = self { + return title + } + return nil + } +} diff --git a/Sources/Helpers/Models/Change.swift b/Sources/Helpers/Models/Change.swift index 9fd9bac..cd0807c 100644 --- a/Sources/Helpers/Models/Change.swift +++ b/Sources/Helpers/Models/Change.swift @@ -15,7 +15,7 @@ struct Change: Equatable { } var changeType: ChangeType - var parentName: String + var parentPath: String? var listOfChanges: [String] = [] } diff --git a/Sources/Helpers/Models/IndependentChange.swift b/Sources/Helpers/Models/IndependentChange.swift index 3d324df..ebe6fd0 100644 --- a/Sources/Helpers/Models/IndependentChange.swift +++ b/Sources/Helpers/Models/IndependentChange.swift @@ -10,7 +10,7 @@ import Foundation /// /// This intermediate structure helps gathering a list of additions and removals /// that are later consolidated to a ``Change`` -struct IndependentChange: Equatable { +struct IndependentSDKDumpChange: Equatable { enum ChangeType: Equatable { case addition(_ description: String) case removal(_ description: String) @@ -27,5 +27,33 @@ struct IndependentChange: Equatable { let element: SDKDump.Element let oldFirst: Bool - var parentName: String { element.parentPath } + var parentPath: String { element.parentPath } +} + +struct IndependentSwiftInterfaceChange: Equatable { + + enum ChangeType: Equatable { + case addition(_ description: String) + case removal(_ description: String) + + var description: String { + switch self { + case let .addition(description): description + case let .removal(description): description + } + } + } + + let changeType: ChangeType + let element: any SwiftInterfaceElement + + let oldFirst: Bool + var parentPath: String? { element.parentPath } + + static func == (lhs: IndependentSwiftInterfaceChange, rhs: IndependentSwiftInterfaceChange) -> Bool { + lhs.changeType == rhs.changeType && + lhs.element.description == rhs.element.description && + lhs.oldFirst == rhs.oldFirst && + lhs.parentPath == rhs.parentPath + } } diff --git a/Sources/Helpers/Models/SwiftInterface/DeclSyntax+Convenience/AccessorBlockSyntax+Convenience.swift b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+Convenience/AccessorBlockSyntax+Convenience.swift new file mode 100644 index 0000000..e92abf5 --- /dev/null +++ b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+Convenience/AccessorBlockSyntax+Convenience.swift @@ -0,0 +1,7 @@ +import SwiftSyntax + +extension AccessorBlockSyntax { + var sanitizedDescription: String { + accessors.trimmedDescription.replacingOccurrences(of: "[\n ]+", with: " ", options: .regularExpression) + } +} diff --git a/Sources/Helpers/Models/SwiftInterface/DeclSyntax+Convenience/SyntaxCollection+Convenience.swift b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+Convenience/SyntaxCollection+Convenience.swift new file mode 100644 index 0000000..d0a5495 --- /dev/null +++ b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+Convenience/SyntaxCollection+Convenience.swift @@ -0,0 +1,7 @@ +import SwiftSyntax + +extension SyntaxCollection { + var sanitizedList: [String] { + self.map { $0.trimmedDescription } + } +} diff --git a/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/ActorDeclSyntax+SwiftInterface.swift b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/ActorDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..598bfae --- /dev/null +++ b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/ActorDeclSyntax+SwiftInterface.swift @@ -0,0 +1,17 @@ +import SwiftSyntax +import SwiftParser + +/// See: https://swiftpackageindex.com/swiftlang/swift-syntax/documentation/swiftsyntax/actordeclsyntax +extension ActorDeclSyntax { + func toInterfaceElement(children: [any SwiftInterfaceElement]) -> SwiftInterfaceActor { + SwiftInterfaceActor( + attributes: self.attributes.sanitizedList, + modifiers: self.modifiers.sanitizedList, + name: self.name.trimmedDescription, + genericParameterDescription: self.genericParameterClause?.trimmedDescription, + inheritance: self.inheritanceClause?.inheritedTypes.sanitizedList, + genericWhereClauseDescription: self.genericWhereClause?.trimmedDescription, + children: children + ) + } +} diff --git a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/AssociatedTypeDeclSyntax+SwiftInterface.swift b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/AssociatedTypeDeclSyntax+SwiftInterface.swift similarity index 76% rename from Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/AssociatedTypeDeclSyntax+SwiftInterface.swift rename to Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/AssociatedTypeDeclSyntax+SwiftInterface.swift index 244e1f5..b1de1f3 100644 --- a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/AssociatedTypeDeclSyntax+SwiftInterface.swift +++ b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/AssociatedTypeDeclSyntax+SwiftInterface.swift @@ -6,10 +6,10 @@ extension AssociatedTypeDeclSyntax { func toInterfaceElement() -> SwiftInterfaceAssociatedType { SwiftInterfaceAssociatedType( - declarationAttributes: self.attributes.map { $0.trimmedDescription }, - modifiers: self.modifiers.map { $0.trimmedDescription }, + attributes: self.attributes.sanitizedList, + modifiers: self.modifiers.sanitizedList, name: self.name.trimmedDescription, - inheritance: self.inheritanceClause?.inheritedTypes.map { $0.trimmedDescription }, + inheritance: self.inheritanceClause?.inheritedTypes.sanitizedList, initializerValue: self.initializer?.value.trimmedDescription, genericWhereClauseDescription: self.genericWhereClause?.trimmedDescription ) diff --git a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/ClassDeclSyntac+SwiftInterface.swift b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/ClassDeclSyntac+SwiftInterface.swift similarity index 77% rename from Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/ClassDeclSyntac+SwiftInterface.swift rename to Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/ClassDeclSyntac+SwiftInterface.swift index ce56c2e..f06c225 100644 --- a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/ClassDeclSyntac+SwiftInterface.swift +++ b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/ClassDeclSyntac+SwiftInterface.swift @@ -6,11 +6,11 @@ extension ClassDeclSyntax { func toInterfaceElement(children: [any SwiftInterfaceElement]) -> SwiftInterfaceClass { SwiftInterfaceClass( - declarationAttributes: self.attributes.map { $0.trimmedDescription }, - modifiers: self.modifiers.map { $0.trimmedDescription }, + attributes: self.attributes.sanitizedList, + modifiers: self.modifiers.sanitizedList, name: self.name.trimmedDescription, genericParameterDescription: self.genericParameterClause?.trimmedDescription, - inheritance: self.inheritanceClause?.inheritedTypes.map { $0.trimmedDescription }, + inheritance: self.inheritanceClause?.inheritedTypes.sanitizedList, genericWhereClauseDescription: self.genericWhereClause?.trimmedDescription, children: children ) diff --git a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/EnumCaseDeclSyntax+SwiftInterface.swift b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/EnumCaseDeclSyntax+SwiftInterface.swift similarity index 76% rename from Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/EnumCaseDeclSyntax+SwiftInterface.swift rename to Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/EnumCaseDeclSyntax+SwiftInterface.swift index e6f0ab3..1c9beea 100644 --- a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/EnumCaseDeclSyntax+SwiftInterface.swift +++ b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/EnumCaseDeclSyntax+SwiftInterface.swift @@ -6,12 +6,12 @@ extension EnumCaseDeclSyntax { func toInterfaceElement(children: [any SwiftInterfaceElement]) -> [SwiftInterfaceEnumCase] { - let attributes = self.attributes.map { $0.trimmedDescription } - let modifiers = self.modifiers.map { $0.trimmedDescription } + let attributes = self.attributes.sanitizedList + let modifiers = self.modifiers.sanitizedList return elements.map { SwiftInterfaceEnumCase( - declarationAttributes: attributes, + attributes: attributes, modifiers: modifiers, name: $0.name.trimmedDescription, parameters: $0.parameterClause?.parameters.map { @@ -19,7 +19,7 @@ extension EnumCaseDeclSyntax { firstName: $0.firstName?.trimmedDescription, secondName: $0.secondName?.trimmedDescription, type: $0.type.trimmedDescription, - defaultValue: $0.defaultValue?.trimmedDescription + defaultValue: $0.defaultValue?.value.description ) }, rawValue: $0.rawValue?.value.trimmedDescription diff --git a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/EnumDeclSyntax+SwiftInterface.swift b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/EnumDeclSyntax+SwiftInterface.swift similarity index 77% rename from Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/EnumDeclSyntax+SwiftInterface.swift rename to Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/EnumDeclSyntax+SwiftInterface.swift index 16c5496..44761ce 100644 --- a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/EnumDeclSyntax+SwiftInterface.swift +++ b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/EnumDeclSyntax+SwiftInterface.swift @@ -6,11 +6,11 @@ extension EnumDeclSyntax { func toInterfaceElement(children: [any SwiftInterfaceElement]) -> SwiftInterfaceEnum { SwiftInterfaceEnum( - declarationAttributes: self.attributes.map { $0.trimmedDescription }, - modifiers: self.modifiers.map { $0.trimmedDescription }, + attributes: self.attributes.sanitizedList, + modifiers: self.modifiers.sanitizedList, name: self.name.trimmedDescription, genericParameterDescription: self.genericParameterClause?.trimmedDescription, - inheritance: self.inheritanceClause?.inheritedTypes.map { $0.trimmedDescription }, + inheritance: self.inheritanceClause?.inheritedTypes.sanitizedList, genericWhereClauseDescription: self.genericWhereClause?.trimmedDescription, children: children ) diff --git a/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/ExtensionDeclSyntax+SwiftInterface.swift b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/ExtensionDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..1ab496b --- /dev/null +++ b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/ExtensionDeclSyntax+SwiftInterface.swift @@ -0,0 +1,17 @@ +import SwiftSyntax +import SwiftParser + +/// See: https://swiftpackageindex.com/swiftlang/swift-syntax/documentation/swiftsyntax/extensiondeclsyntax +extension ExtensionDeclSyntax { + + func toInterfaceElement(children: [any SwiftInterfaceElement]) -> SwiftInterfaceExtension { + return SwiftInterfaceExtension( + attributes: self.attributes.sanitizedList, + modifiers: self.modifiers.sanitizedList, + extendedType: self.extendedType.trimmedDescription, + inheritance: self.inheritanceClause?.inheritedTypes.sanitizedList, + genericWhereClauseDescription: self.genericWhereClause?.trimmedDescription, + children: children + ) + } +} diff --git a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/FunctionDeclSyntax+SwiftInterface.swift b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/FunctionDeclSyntax+SwiftInterface.swift similarity index 86% rename from Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/FunctionDeclSyntax+SwiftInterface.swift rename to Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/FunctionDeclSyntax+SwiftInterface.swift index 421099d..0896027 100644 --- a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/FunctionDeclSyntax+SwiftInterface.swift +++ b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/FunctionDeclSyntax+SwiftInterface.swift @@ -22,13 +22,13 @@ extension FunctionDeclSyntax { firstName: $0.firstName.trimmedDescription, secondName: $0.secondName?.trimmedDescription, type: $0.type.trimmedDescription, - defaultValue: $0.defaultValue?.trimmedDescription + defaultValue: $0.defaultValue?.value.description ) } return SwiftInterfaceFunction( - declarationAttributes: self.attributes.map { $0.trimmedDescription }, - modifiers: self.modifiers.map { $0.trimmedDescription }, + attributes: self.attributes.sanitizedList, + modifiers: self.modifiers.sanitizedList, name: self.name.trimmedDescription, genericParameterDescription: self.genericParameterClause?.trimmedDescription, parameters: parameters, diff --git a/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/InitializerDeclSyntax+SwiftInterface.swift b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/InitializerDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..82f2b69 --- /dev/null +++ b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/InitializerDeclSyntax+SwiftInterface.swift @@ -0,0 +1,40 @@ +import SwiftSyntax +import SwiftParser + +/// See: https://swiftpackageindex.com/swiftlang/swift-syntax/documentation/swiftsyntax/initializerdeclsyntax +extension InitializerDeclSyntax { + + func toInterfaceElement() -> SwiftInterfaceInitializer { + + var effectSpecifiers = [String]() + + if let effects = signature.effectSpecifiers { + if let asyncSpecifier = effects.asyncSpecifier { + effectSpecifiers.append(asyncSpecifier.trimmedDescription) + } + if let throwsClause = effects.throwsClause { + effectSpecifiers.append(throwsClause.trimmedDescription) + } + } + + let parameters: [SwiftInterfaceInitializer.Parameter] = self.signature.parameterClause.parameters.map { + .init( + firstName: $0.firstName.trimmedDescription, + secondName: $0.secondName?.trimmedDescription, + type: $0.type.trimmedDescription, + defaultValue: $0.defaultValue?.value.description + ) + } + + return SwiftInterfaceInitializer( + attributes: self.attributes.sanitizedList, + modifiers: self.modifiers.sanitizedList, + optionalMark: optionalMark?.trimmedDescription, + genericParameterDescription: self.genericParameterClause?.trimmedDescription, + parameters: parameters, + effectSpecifiers: effectSpecifiers, + returnType: signature.returnClause?.type.trimmedDescription, + genericWhereClauseDescription: self.genericWhereClause?.trimmedDescription + ) + } +} diff --git a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/ProtocolDeclSyntax+SwiftInterface.swift b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/ProtocolDeclSyntax+SwiftInterface.swift similarity index 79% rename from Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/ProtocolDeclSyntax+SwiftInterface.swift rename to Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/ProtocolDeclSyntax+SwiftInterface.swift index fa5f760..981c834 100644 --- a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/ProtocolDeclSyntax+SwiftInterface.swift +++ b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/ProtocolDeclSyntax+SwiftInterface.swift @@ -6,11 +6,11 @@ extension ProtocolDeclSyntax { func toInterfaceElement(children: [any SwiftInterfaceElement]) -> SwiftInterfaceProtocol { SwiftInterfaceProtocol( - declarationAttributes: self.attributes.map { $0.trimmedDescription }, - modifiers: self.modifiers.map { $0.trimmedDescription }, + attributes: self.attributes.sanitizedList, + modifiers: self.modifiers.sanitizedList, name: self.name.trimmedDescription, primaryAssociatedTypes: self.primaryAssociatedTypeClause?.primaryAssociatedTypes.map { $0.name.trimmedDescription }, - inheritance: self.inheritanceClause?.inheritedTypes.map { $0.trimmedDescription }, + inheritance: self.inheritanceClause?.inheritedTypes.sanitizedList, genericWhereClauseDescription: self.genericWhereClause?.trimmedDescription, children: children ) diff --git a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/StructDeclSyntax+SwiftInterface.swift b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/StructDeclSyntax+SwiftInterface.swift similarity index 77% rename from Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/StructDeclSyntax+SwiftInterface.swift rename to Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/StructDeclSyntax+SwiftInterface.swift index f1c9fc2..5a78bc1 100644 --- a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/StructDeclSyntax+SwiftInterface.swift +++ b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/StructDeclSyntax+SwiftInterface.swift @@ -6,11 +6,11 @@ extension StructDeclSyntax { func toInterfaceElement(children: [any SwiftInterfaceElement]) -> SwiftInterfaceStruct { SwiftInterfaceStruct( - declarationAttributes: self.attributes.map { $0.trimmedDescription }, - modifiers: self.modifiers.map { $0.trimmedDescription }, + attributes: self.attributes.sanitizedList, + modifiers: self.modifiers.sanitizedList, name: self.name.trimmedDescription, genericParameterDescription: self.genericParameterClause?.trimmedDescription, - inheritance: self.inheritanceClause?.inheritedTypes.map { $0.trimmedDescription }, + inheritance: self.inheritanceClause?.inheritedTypes.sanitizedList, genericWhereClauseDescription: self.genericWhereClause?.trimmedDescription, children: children ) diff --git a/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/SubscriptDeclSyntax+SwiftInterface.swift b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/SubscriptDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..1a26fe5 --- /dev/null +++ b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/SubscriptDeclSyntax+SwiftInterface.swift @@ -0,0 +1,28 @@ +import SwiftSyntax +import SwiftParser + +/// See: https://swiftpackageindex.com/swiftlang/swift-syntax/documentation/swiftsyntax/subscriptdeclsyntax +extension SubscriptDeclSyntax { + + func toInterfaceElement() -> SwiftInterfaceSubscript { + + let parameters: [SwiftInterfaceSubscript.Parameter] = self.parameterClause.parameters.map { + .init( + firstName: $0.firstName.trimmedDescription, + secondName: $0.secondName?.trimmedDescription, + type: $0.type.trimmedDescription, + defaultValue: $0.defaultValue?.value.description + ) + } + + return SwiftInterfaceSubscript( + attributes: self.attributes.sanitizedList, + modifiers: self.modifiers.sanitizedList, + genericParameterDescription: self.genericParameterClause?.trimmedDescription, + parameters: parameters, + returnType: returnClause.type.trimmedDescription, + genericWhereClauseDescription: self.genericWhereClause?.trimmedDescription, + accessors: self.accessorBlock?.sanitizedDescription + ) + } +} diff --git a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/TypeAliasDeclSyntax+SwiftInterface.swift b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/TypeAliasDeclSyntax+SwiftInterface.swift similarity index 80% rename from Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/TypeAliasDeclSyntax+SwiftInterface.swift rename to Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/TypeAliasDeclSyntax+SwiftInterface.swift index 5bcff1f..3f17c66 100644 --- a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/TypeAliasDeclSyntax+SwiftInterface.swift +++ b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/TypeAliasDeclSyntax+SwiftInterface.swift @@ -6,8 +6,8 @@ extension TypeAliasDeclSyntax { func toInterfaceElement(children: [any SwiftInterfaceElement]) -> SwiftInterfaceTypeAlias { SwiftInterfaceTypeAlias( - declarationAttributes: self.attributes.map { $0.trimmedDescription }, - modifiers: self.modifiers.map { $0.trimmedDescription }, + attributes: self.attributes.sanitizedList, + modifiers: self.modifiers.sanitizedList, name: self.name.trimmedDescription, genericParameterDescription: self.genericParameterClause?.trimmedDescription, initializerValue: self.initializer.value.trimmedDescription, diff --git a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/VarDeclSyntax+SwiftInterface.swift b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/VarDeclSyntax+SwiftInterface.swift similarity index 76% rename from Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/VarDeclSyntax+SwiftInterface.swift rename to Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/VarDeclSyntax+SwiftInterface.swift index fab0d76..e81a9b0 100644 --- a/Tests/UnitTests/SwiftInterface/DeclSyntax+SwiftInterface/VarDeclSyntax+SwiftInterface.swift +++ b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/VarDeclSyntax+SwiftInterface.swift @@ -6,8 +6,8 @@ extension VariableDeclSyntax { func toInterfaceElement() -> [SwiftInterfaceVar] { - let declarationAttributes = self.attributes.map { $0.trimmedDescription } - let modifiers = self.modifiers.map { $0.trimmedDescription } + let declarationAttributes = self.attributes.sanitizedList + let modifiers = self.modifiers.sanitizedList let bindingSpecifier = self.bindingSpecifier.trimmedDescription // Transforming: @@ -18,13 +18,13 @@ extension VariableDeclSyntax { // - final public let c: Double = 5.0 return bindings.map { return SwiftInterfaceVar( - declarationAttributes: declarationAttributes, + attributes: declarationAttributes, modifiers: modifiers, bindingSpecifier: bindingSpecifier, name: $0.pattern.trimmedDescription, typeAnnotation: $0.typeAnnotation?.type.trimmedDescription, initializerValue: $0.initializer?.value.trimmedDescription, - accessors: $0.accessorBlock?.accessors.trimmedDescription + accessors: $0.accessorBlock?.sanitizedDescription ) } } diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Actor.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Actor.swift new file mode 100644 index 0000000..e2d9bca --- /dev/null +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Actor.swift @@ -0,0 +1,86 @@ +import Foundation + +class SwiftInterfaceActor: SwiftInterfaceElement { + + var childGroupName: String { name } + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let attributes: [String] + + let name: String + + /// e.g. + let genericParameterDescription: String? + + let inheritance: [String]? + + /// e.g. public, private, package, open, internal + let modifiers: [String] + + /// e.g. where T : Equatable + let genericWhereClauseDescription: String? + + /// The members, declarations, ... inside of the body of the struct + let children: [any SwiftInterfaceElement] + + var parent: (any SwiftInterfaceElement)? = nil + + var diffableSignature: String { + name + } + + var consolidatableName: String { + name + } + + var description: String { + compileDescription() + } + + init( + attributes: [String], + modifiers: [String], + name: String, + genericParameterDescription: String?, + inheritance: [String]?, + genericWhereClauseDescription: String?, + children: [any SwiftInterfaceElement] + ) { + self.attributes = attributes + self.name = name + self.genericParameterDescription = genericParameterDescription + self.inheritance = inheritance + self.modifiers = modifiers + self.genericWhereClauseDescription = genericWhereClauseDescription + self.children = children + } +} + +private extension SwiftInterfaceActor { + + func compileDescription() -> String { + + var components = [String]() + + components += attributes + components += modifiers + components += ["actor"] + + components += [{ + var components = [ + name, + genericParameterDescription + ].compactMap { $0 }.joined() + + if let inheritance, !inheritance.isEmpty { + components += ": \(inheritance.joined(separator: ", "))" + } + + return components + }()] + + genericWhereClauseDescription.map { components += [$0] } + + return components.joined(separator: " ") + } +} diff --git a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+AssociatedType.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+AssociatedType.swift similarity index 69% rename from Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+AssociatedType.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+AssociatedType.swift index 3585e88..09855db 100644 --- a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+AssociatedType.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+AssociatedType.swift @@ -1,12 +1,9 @@ -@testable import public_api_diff import Foundation -struct SwiftInterfaceAssociatedType: SwiftInterfaceElement { - - var type: SDKDump.DeclarationKind { .struct } +class SwiftInterfaceAssociatedType: SwiftInterfaceElement { /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... - let declarationAttributes: [String] + let attributes: [String] let name: String @@ -21,22 +18,34 @@ struct SwiftInterfaceAssociatedType: SwiftInterfaceElement { /// e.g. where T : Equatable let genericWhereClauseDescription: String? + var childGroupName: String { "" } // Not relevant as only used to group children + /// A associatedtype does not have children let children: [any SwiftInterfaceElement] = [] + var parent: (any SwiftInterfaceElement)? = nil + + var diffableSignature: String { + name + } + + var consolidatableName: String { + name + } + var description: String { compileDescription() } init( - declarationAttributes: [String], + attributes: [String], modifiers: [String], name: String, inheritance: [String]?, initializerValue: String?, genericWhereClauseDescription: String? ) { - self.declarationAttributes = declarationAttributes + self.attributes = attributes self.modifiers = modifiers self.name = name self.inheritance = inheritance @@ -51,18 +60,15 @@ private extension SwiftInterfaceAssociatedType { var components = [String]() - components += declarationAttributes + components += attributes components += modifiers components += ["associatedtype"] - components += { - // Joining name + inheritance without a space - var components = [name] - if let inheritance, !inheritance.isEmpty { - components += [": \(inheritance.joined(separator: ", "))"] - } - return [components.joined()] - }() + if let inheritance, !inheritance.isEmpty { + components += ["\(name): \(inheritance.joined(separator: ", "))"] + } else { + components += [name] + } initializerValue.map { components += ["= \($0)"] } diff --git a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Class.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Class.swift similarity index 68% rename from Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Class.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Class.swift index ef91839..41258c9 100644 --- a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Class.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Class.swift @@ -1,12 +1,9 @@ -@testable import public_api_diff import Foundation -struct SwiftInterfaceClass: SwiftInterfaceElement { - - var type: SDKDump.DeclarationKind { .struct } +class SwiftInterfaceClass: SwiftInterfaceElement { /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... - let declarationAttributes: [String] + let attributes: [String] let name: String @@ -21,15 +18,27 @@ struct SwiftInterfaceClass: SwiftInterfaceElement { /// e.g. where T : Equatable let genericWhereClauseDescription: String? + var childGroupName: String { name } // Not relevant as only used to group children + /// The members, declarations, ... inside of the body of the struct let children: [any SwiftInterfaceElement] + var parent: (any SwiftInterfaceElement)? = nil + + var diffableSignature: String { + return name + } + + var consolidatableName: String { + name + } + var description: String { compileDescription() } init( - declarationAttributes: [String], + attributes: [String], modifiers: [String], name: String, genericParameterDescription: String?, @@ -37,7 +46,7 @@ struct SwiftInterfaceClass: SwiftInterfaceElement { genericWhereClauseDescription: String?, children: [any SwiftInterfaceElement] ) { - self.declarationAttributes = declarationAttributes + self.attributes = attributes self.name = name self.genericParameterDescription = genericParameterDescription self.inheritance = inheritance @@ -53,20 +62,22 @@ private extension SwiftInterfaceClass { var components = [String]() - components += declarationAttributes + components += attributes components += modifiers components += ["class"] - components += [ - [ + components += [{ + var components = [ name, genericParameterDescription ].compactMap { $0 }.joined() - ] - - if let inheritance, !inheritance.isEmpty { - components += [": \(inheritance.joined(separator: ", "))"] - } + + if let inheritance, !inheritance.isEmpty { + components += ": \(inheritance.joined(separator: ", "))" + } + + return components + }()] genericWhereClauseDescription.map { components += [$0] } diff --git a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Enum.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Enum.swift similarity index 69% rename from Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Enum.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Enum.swift index cdc592e..6c3d89a 100644 --- a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Enum.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Enum.swift @@ -1,12 +1,9 @@ -@testable import public_api_diff import Foundation -struct SwiftInterfaceEnum: SwiftInterfaceElement { - - var type: SDKDump.DeclarationKind { .enum } +class SwiftInterfaceEnum: SwiftInterfaceElement { /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... - let declarationAttributes: [String] + let attributes: [String] /// e.g. public, private, package, open, internal let modifiers: [String] @@ -21,15 +18,27 @@ struct SwiftInterfaceEnum: SwiftInterfaceElement { /// e.g. where T : Equatable let genericWhereClauseDescription: String? + var childGroupName: String { name } // Not relevant as only used to group children + /// The members, declarations, ... inside of the body of the struct let children: [any SwiftInterfaceElement] + var parent: (any SwiftInterfaceElement)? = nil + + var diffableSignature: String { + name + } + + var consolidatableName: String { + name + } + var description: String { compileDescription() } init( - declarationAttributes: [String], + attributes: [String], modifiers: [String], name: String, genericParameterDescription: String?, @@ -37,7 +46,7 @@ struct SwiftInterfaceEnum: SwiftInterfaceElement { genericWhereClauseDescription: String?, children: [any SwiftInterfaceElement] ) { - self.declarationAttributes = declarationAttributes + self.attributes = attributes self.name = name self.genericParameterDescription = genericParameterDescription self.inheritance = inheritance @@ -53,20 +62,22 @@ private extension SwiftInterfaceEnum { var components = [String]() - components += declarationAttributes + components += attributes components += modifiers components += ["enum"] - components += [ - [ + components += [{ + var components = [ name, genericParameterDescription ].compactMap { $0 }.joined() - ] - - if let inheritance, !inheritance.isEmpty { - components += [": \(inheritance.joined(separator: ", "))"] - } + + if let inheritance, !inheritance.isEmpty { + components += ": \(inheritance.joined(separator: ", "))" + } + + return components + }()] genericWhereClauseDescription.map { components += [$0] } diff --git a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+EnumCase.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+EnumCase.swift similarity index 82% rename from Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+EnumCase.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+EnumCase.swift index 3f4a744..42c44b9 100644 --- a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+EnumCase.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+EnumCase.swift @@ -1,4 +1,3 @@ -@testable import public_api_diff import Foundation extension SwiftInterfaceEnumCase { @@ -34,12 +33,10 @@ extension SwiftInterfaceEnumCase { } } -struct SwiftInterfaceEnumCase: SwiftInterfaceElement { - - var type: SDKDump.DeclarationKind { .case } +class SwiftInterfaceEnumCase: SwiftInterfaceElement { /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... - let declarationAttributes: [String] + let attributes: [String] /// e.g. public, private, package, open, internal let modifiers: [String] @@ -50,21 +47,33 @@ struct SwiftInterfaceEnumCase: SwiftInterfaceElement { let rawValue: String? + var childGroupName: String { "" } + /// A typealias does not have children let children: [any SwiftInterfaceElement] = [] + var parent: (any SwiftInterfaceElement)? = nil + + var diffableSignature: String { + name + } + + var consolidatableName: String { + name + } + var description: String { compileDescription() } init( - declarationAttributes: [String], + attributes: [String], modifiers: [String], name: String, parameters: [Parameter]?, rawValue: String? ) { - self.declarationAttributes = declarationAttributes + self.attributes = attributes self.modifiers = modifiers self.name = name self.parameters = parameters @@ -78,7 +87,7 @@ private extension SwiftInterfaceEnumCase { var components = [String]() - components += declarationAttributes + components += attributes components += modifiers components += ["case"] diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Extension.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Extension.swift new file mode 100644 index 0000000..6083106 --- /dev/null +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Extension.swift @@ -0,0 +1,75 @@ +import Foundation + +class SwiftInterfaceExtension: SwiftInterfaceElement { + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let attributes: [String] + + /// e.g. public, private, package, open, internal + let modifiers: [String] + + let extendedType: String + + let inheritance: [String]? + + /// e.g. where T : Equatable + let genericWhereClauseDescription: String? + + // TODO: The extensions show up independently on the root - find a way so we can nest them inside the parent (find a way to find the parent) + var childGroupName: String { extendedType } // Grouping in extended type + + /// The members, declarations, ... inside of the body of the struct + let children: [any SwiftInterfaceElement] + + var parent: (any SwiftInterfaceElement)? = nil + + var diffableSignature: String { + extendedType + } + + var consolidatableName: String { + extendedType + } + + var description: String { + compileDescription() + } + + init( + attributes: [String], + modifiers: [String], + extendedType: String, + inheritance: [String]?, + genericWhereClauseDescription: String?, + children: [any SwiftInterfaceElement] + ) { + self.attributes = attributes + self.modifiers = modifiers + self.extendedType = extendedType + self.inheritance = inheritance + self.genericWhereClauseDescription = genericWhereClauseDescription + self.children = children + } +} + +private extension SwiftInterfaceExtension { + + func compileDescription() -> String { + + var components = [String]() + + components += attributes + components += modifiers + components += ["extension"] + + if let inheritance, !inheritance.isEmpty { + components += ["\(extendedType): \(inheritance.joined(separator: ", "))"] + } else { + components += [extendedType] + } + + genericWhereClauseDescription.map { components += [$0] } + + return components.joined(separator: " ") + } +} diff --git a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Function.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Function.swift similarity index 84% rename from Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Function.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Function.swift index ebe73f4..7e5af85 100644 --- a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Function.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Function.swift @@ -1,4 +1,3 @@ -@testable import public_api_diff import Foundation extension SwiftInterfaceFunction { @@ -35,11 +34,10 @@ extension SwiftInterfaceFunction { } } -struct SwiftInterfaceFunction: SwiftInterfaceElement { - var type: SDKDump.DeclarationKind { .func } +class SwiftInterfaceFunction: SwiftInterfaceElement { /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... - let declarationAttributes: [String] + let attributes: [String] let name: String @@ -59,15 +57,27 @@ struct SwiftInterfaceFunction: SwiftInterfaceElement { /// e.g. where T : Equatable let genericWhereClauseDescription: String? + var childGroupName: String { "" } // Not relevant as only used to group children + /// A function does not have children let children: [any SwiftInterfaceElement] = [] + var parent: (any SwiftInterfaceElement)? = nil + + var diffableSignature: String { + "\(name)(\(parameters.map { "\($0.firstName):" }.joined()))" + } + + var consolidatableName: String { + name + } + var description: String { compileDescription() } init( - declarationAttributes: [String], + attributes: [String], modifiers: [String], name: String, genericParameterDescription: String?, @@ -76,7 +86,7 @@ struct SwiftInterfaceFunction: SwiftInterfaceElement { returnType: String?, genericWhereClauseDescription: String? ) { - self.declarationAttributes = declarationAttributes + self.attributes = attributes self.modifiers = modifiers self.name = name self.genericParameterDescription = genericParameterDescription @@ -92,7 +102,7 @@ private extension SwiftInterfaceFunction { func compileDescription() -> String { var components = [String]() - components += declarationAttributes + components += attributes components += modifiers components += ["func"] diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Initializer.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Initializer.swift new file mode 100644 index 0000000..b2c78bc --- /dev/null +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Initializer.swift @@ -0,0 +1,120 @@ +import Foundation + +extension SwiftInterfaceInitializer { + + struct Parameter { + + let firstName: String + + /// optional second "internal" name - can be ignored + let secondName: String? + + let type: String + + let defaultValue: String? + + var description: String { + var description = [ + firstName, + secondName + ].compactMap { $0 }.joined(separator: " ") + + if description.isEmpty { + description += "\(type)" + } else { + description += ": \(type)" + } + + if let defaultValue { + description += " = \(defaultValue)" + } + + return description + } + } +} + +class SwiftInterfaceInitializer: SwiftInterfaceElement { + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let attributes: [String] + + let optionalMark: String? + + /// e.g. + let genericParameterDescription: String? + + let parameters: [Parameter] + + /// e.g. async, throws, rethrows + let effectSpecifiers: [String] + + /// e.g. public, private, package, open, internal + let modifiers: [String] + + /// e.g. where T : Equatable + let genericWhereClauseDescription: String? + + var childGroupName: String { "" } // Not relevant as only used to group children + + /// A function does not have children + let children: [any SwiftInterfaceElement] = [] + + var parent: (any SwiftInterfaceElement)? = nil + + var diffableSignature: String { + "init(\(parameters.map { "\($0.firstName):" }.joined()))" + } + + var consolidatableName: String { + "init" + } + + var description: String { + compileDescription() + } + + init( + attributes: [String], + modifiers: [String], + optionalMark: String?, + genericParameterDescription: String?, + parameters: [Parameter], + effectSpecifiers: [String], + returnType: String?, + genericWhereClauseDescription: String? + ) { + self.attributes = attributes + self.modifiers = modifiers + self.optionalMark = optionalMark + self.genericParameterDescription = genericParameterDescription + self.parameters = parameters + self.effectSpecifiers = effectSpecifiers + self.genericWhereClauseDescription = genericWhereClauseDescription + } +} + +private extension SwiftInterfaceInitializer { + + func compileDescription() -> String { + var components = [String]() + + components += attributes + components += modifiers + + components += [ + [ + "init", + optionalMark, + genericParameterDescription, + "(\(parameters.map { $0.description }.joined(separator: ", ")))" + ].compactMap { $0 }.joined() + ] + + components += effectSpecifiers + + genericWhereClauseDescription.map { components += [$0] } + + return components.joined(separator: " ") + } +} diff --git a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Protocol.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Protocol.swift similarity index 69% rename from Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Protocol.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Protocol.swift index 63f0b23..5a9e4d3 100644 --- a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Protocol.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Protocol.swift @@ -1,12 +1,9 @@ -@testable import public_api_diff import Foundation -struct SwiftInterfaceProtocol: SwiftInterfaceElement { - - var type: SDKDump.DeclarationKind { .protocol } +class SwiftInterfaceProtocol: SwiftInterfaceElement { /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... - let declarationAttributes: [String] + let attributes: [String] let name: String @@ -20,15 +17,27 @@ struct SwiftInterfaceProtocol: SwiftInterfaceElement { /// e.g. where T : Equatable let genericWhereClauseDescription: String? + var childGroupName: String { name } // Not relevant as only used to group children + /// The members, declarations, ... inside of the body of the struct let children: [any SwiftInterfaceElement] + + var parent: (any SwiftInterfaceElement)? = nil + + var diffableSignature: String { + name + } + + var consolidatableName: String { + name + } var description: String { compileDescription() } init( - declarationAttributes: [String], + attributes: [String], modifiers: [String], name: String, primaryAssociatedTypes: [String]?, @@ -36,7 +45,7 @@ struct SwiftInterfaceProtocol: SwiftInterfaceElement { genericWhereClauseDescription: String?, children: [any SwiftInterfaceElement] ) { - self.declarationAttributes = declarationAttributes + self.attributes = attributes self.name = name self.primaryAssociatedTypes = primaryAssociatedTypes self.inheritance = inheritance @@ -52,20 +61,22 @@ private extension SwiftInterfaceProtocol { var components = [String]() - components += declarationAttributes + components += attributes components += modifiers components += ["protocol"] - components += [ - [ + components += [{ + var components = [ name, primaryAssociatedTypes.map { "<\($0.joined(separator: ", "))>"} ].compactMap { $0 }.joined() - ] - - if let inheritance, !inheritance.isEmpty { - components += [": \(inheritance.joined(separator: ", "))"] - } + + if let inheritance, !inheritance.isEmpty { + components += ": \(inheritance.joined(separator: ", "))" + } + + return components + }()] genericWhereClauseDescription.map { components += [$0] } diff --git a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Struct.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Struct.swift similarity index 70% rename from Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Struct.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Struct.swift index 2bcb8db..0c5a4f4 100644 --- a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Struct.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Struct.swift @@ -1,12 +1,9 @@ -@testable import public_api_diff import Foundation -struct SwiftInterfaceStruct: SwiftInterfaceElement { - - var type: SDKDump.DeclarationKind { .struct } +class SwiftInterfaceStruct: SwiftInterfaceElement { /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... - let declarationAttributes: [String] + let attributes: [String] let name: String @@ -21,15 +18,27 @@ struct SwiftInterfaceStruct: SwiftInterfaceElement { /// e.g. where T : Equatable let genericWhereClauseDescription: String? + var childGroupName: String { name } + /// The members, declarations, ... inside of the body of the struct let children: [any SwiftInterfaceElement] + var parent: (any SwiftInterfaceElement)? = nil + + var diffableSignature: String { + name + } + + var consolidatableName: String { + name + } + var description: String { compileDescription() } init( - declarationAttributes: [String], + attributes: [String], modifiers: [String], name: String, genericParameterDescription: String?, @@ -37,7 +46,7 @@ struct SwiftInterfaceStruct: SwiftInterfaceElement { genericWhereClauseDescription: String?, children: [any SwiftInterfaceElement] ) { - self.declarationAttributes = declarationAttributes + self.attributes = attributes self.name = name self.genericParameterDescription = genericParameterDescription self.inheritance = inheritance @@ -53,20 +62,22 @@ private extension SwiftInterfaceStruct { var components = [String]() - components += declarationAttributes + components += attributes components += modifiers components += ["struct"] - components += [ - [ + components += [{ + var components = [ name, genericParameterDescription ].compactMap { $0 }.joined() - ] - - if let inheritance, !inheritance.isEmpty { - components += [": \(inheritance.joined(separator: ", "))"] - } + + if let inheritance, !inheritance.isEmpty { + components += ": \(inheritance.joined(separator: ", "))" + } + + return components + }()] genericWhereClauseDescription.map { components += [$0] } diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Subscript.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Subscript.swift new file mode 100644 index 0000000..f4bdfa2 --- /dev/null +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Subscript.swift @@ -0,0 +1,121 @@ +import Foundation + +extension SwiftInterfaceSubscript { + + struct Parameter { + + let firstName: String + + /// optional second "internal" name - can be ignored + let secondName: String? + + let type: String + + let defaultValue: String? + + var description: String { + var description = [ + firstName, + secondName + ].compactMap { $0 }.joined(separator: " ") + + if description.isEmpty { + description += "\(type)" + } else { + description += ": \(type)" + } + + if let defaultValue { + description += " = \(defaultValue)" + } + + return description + } + } +} + +class SwiftInterfaceSubscript: SwiftInterfaceElement { + + let name: String = "subscript" + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let attributes: [String] + + /// e.g. public, private, package, open, internal + let modifiers: [String] + + /// e.g. + let genericParameterDescription: String? + + let parameters: [Parameter] + + let returnType: String + + /// e.g. where T : Equatable + let genericWhereClauseDescription: String? + + let accessors: String? + + var childGroupName: String { "" } + + /// A function does not have children + let children: [any SwiftInterfaceElement] = [] + + var parent: (any SwiftInterfaceElement)? = nil + + var diffableSignature: String { + parameters.description + } + + var consolidatableName: String { + name + } + + var description: String { + compileDescription() + } + + init( + attributes: [String], + modifiers: [String], + genericParameterDescription: String?, + parameters: [Parameter], + returnType: String, + genericWhereClauseDescription: String?, + accessors: String? + ) { + self.attributes = attributes + self.modifiers = modifiers + self.genericParameterDescription = genericParameterDescription + self.parameters = parameters + self.returnType = returnType + self.genericWhereClauseDescription = genericWhereClauseDescription + self.accessors = accessors + } +} + +private extension SwiftInterfaceSubscript { + + func compileDescription() -> String { + var components = [String]() + + components += attributes + components += modifiers + + components += [ + [ + "subscript", + genericParameterDescription, + "(\(parameters.map { $0.description }.joined(separator: ", ")))" + ].compactMap { $0 }.joined() + ] + + components += ["-> \(returnType)"] + + genericWhereClauseDescription.map { components += [$0] } + + accessors.map { components += ["{ \($0) }"] } + + return components.joined(separator: " ") + } +} diff --git a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+TypeAlias.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+TypeAlias.swift similarity index 78% rename from Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+TypeAlias.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+TypeAlias.swift index b84af12..c0ec8cc 100644 --- a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+TypeAlias.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+TypeAlias.swift @@ -1,12 +1,9 @@ -@testable import public_api_diff import Foundation -struct SwiftInterfaceTypeAlias: SwiftInterfaceElement { - - var type: SDKDump.DeclarationKind { .struct } +class SwiftInterfaceTypeAlias: SwiftInterfaceElement { /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... - let declarationAttributes: [String] + let attributes: [String] let name: String @@ -22,22 +19,34 @@ struct SwiftInterfaceTypeAlias: SwiftInterfaceElement { /// e.g. where T : Equatable let genericWhereClauseDescription: String? + var childGroupName: String { "" } // Not relevant as only used to group children + /// A typealias does not have children let children: [any SwiftInterfaceElement] = [] + var parent: (any SwiftInterfaceElement)? = nil + + var diffableSignature: String { + name + } + + var consolidatableName: String { + name + } + var description: String { compileDescription() } init( - declarationAttributes: [String], + attributes: [String], modifiers: [String], name: String, genericParameterDescription: String?, initializerValue: String, genericWhereClauseDescription: String? ) { - self.declarationAttributes = declarationAttributes + self.attributes = attributes self.name = name self.genericParameterDescription = genericParameterDescription self.initializerValue = initializerValue @@ -52,7 +61,7 @@ private extension SwiftInterfaceTypeAlias { var components = [String]() - components += declarationAttributes + components += attributes components += modifiers components += ["typealias"] diff --git a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Var.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Var.swift similarity index 77% rename from Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Var.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Var.swift index d9a246c..39792ac 100644 --- a/Tests/UnitTests/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Var.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Var.swift @@ -1,12 +1,9 @@ -@testable import public_api_diff import Foundation -struct SwiftInterfaceVar: SwiftInterfaceElement { - - var type: SDKDump.DeclarationKind { .struct } +class SwiftInterfaceVar: SwiftInterfaceElement { /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... - let declarationAttributes: [String] + let attributes: [String] /// e.g. public, private, package, open, internal let modifiers: [String] @@ -22,15 +19,27 @@ struct SwiftInterfaceVar: SwiftInterfaceElement { let accessors: String? + var childGroupName: String { "" } // Not relevant as only used to group children + /// A var does not have children let children: [any SwiftInterfaceElement] = [] + var parent: (any SwiftInterfaceElement)? = nil + + var diffableSignature: String { + name + } + + var consolidatableName: String { + name + } + var description: String { compileDescription() } init( - declarationAttributes: [String], + attributes: [String], modifiers: [String], bindingSpecifier: String, name: String, @@ -38,7 +47,7 @@ struct SwiftInterfaceVar: SwiftInterfaceElement { initializerValue: String?, accessors: String? ) { - self.declarationAttributes = declarationAttributes + self.attributes = attributes self.modifiers = modifiers self.bindingSpecifier = bindingSpecifier self.name = name @@ -54,7 +63,7 @@ private extension SwiftInterfaceVar { var components = [String]() - components += declarationAttributes + components += attributes components += modifiers components += [bindingSpecifier] components += ["\(name): \(typeAnnotation)"] diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement.swift new file mode 100644 index 0000000..25af9bc --- /dev/null +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement.swift @@ -0,0 +1,95 @@ +import Foundation + +protocol SwiftInterfaceElement: CustomStringConvertible, Equatable, AnyObject { + + /// Used to group output together + var childGroupName: String { get } + + var description: String { get } + + var children: [any SwiftInterfaceElement] { get } + + /// A reduced signature of the element to be used to find 2 versions of the same element in a diff + /// by deliberately omitting specifics like types and other decorators. + /// + /// e.g. `func foo(bar: Int = 0, baz: String)` would have a diffable signature of `foo(bar:baz)` + var diffableSignature: String { get } + + /// A very reduced signature that allows consolidating changes + /// + /// e.g. `func foo(bar: Int = 0, baz: String)` would have a consolidatable name of `foo` + var consolidatableName: String { get } + + var parent: (any SwiftInterfaceElement)? { get set } +} + +extension SwiftInterfaceElement { + + func setupParentRelationships(parent: (any SwiftInterfaceElement)? = nil) { + self.parent = parent + children.forEach { + $0.setupParentRelationships(parent: self) + } + } + + var parentPath: String { + var parent = self.parent + var path = [parent?.childGroupName] + + while parent != nil { + parent = parent?.parent + path += [parent?.childGroupName] + } + + var sanitizedPath = path.compactMap { $0 } + + if sanitizedPath.last == "TopLevel" { + sanitizedPath.removeLast() + } + + return sanitizedPath.reversed().joined(separator: ".") + } +} + +extension SwiftInterfaceElement { + static func == (lhs: Self, rhs: Self) -> Bool { + // The description is the unique representation of an element and thus used for the equality check + lhs.description == rhs.description + } +} + +extension SwiftInterfaceElement { + /// Checks whether or not 2 elements can be compared based on their `printedName`, `type` and `parentPath` + /// + /// If the `printedName`, `type` + `parentPath` is the same we can assume that it's the same element but altered + /// We're using the `printedName` and not the `name` as for example there could be multiple functions with the same name but different parameters. + /// In this specific case we want to find an exact match of the signature. + /// + /// e.g. if we have a function `init(foo: Int, bar: Int) -> Void` the `name` would be `init` and `printedName` would be `init(foo:bar:)`. + /// If we used the `name` it could cause a false positive with other functions named `init` (e.g. convenience inits) when trying to find matching elements during this finding phase. + /// In a later consolidation phase removals/additions are compared again based on their `name` to combine them to a `change` + func isDiffable(with otherElement: any SwiftInterfaceElement) -> Bool { + return parentPath == otherElement.parentPath && type(of: self) == type(of: otherElement) && diffableSignature == otherElement.diffableSignature + } +} + +extension SwiftInterfaceElement { + func recursiveDescription(indentation: Int = 0) -> String { + let spacer = " " + var recursiveDescription = "\(String(repeating: spacer, count: indentation))\(description)" + if !self.children.isEmpty { + recursiveDescription.append("\n\(String(repeating: spacer, count: indentation)){") + for child in self.children { + recursiveDescription.append("\n\(String(repeating: spacer, count: indentation))\(child.recursiveDescription(indentation: indentation + 1))") + } + recursiveDescription.append("\n\(String(repeating: spacer, count: indentation))}") + } + return recursiveDescription + } +} + +extension SwiftInterfaceElement { + var isSpiInternal: Bool { + description.range(of: "@_spi(") != nil + } +} diff --git a/Sources/Pipeline/Modules/MarkdownOutputGenerator.swift b/Sources/Pipeline/Modules/MarkdownOutputGenerator.swift index 9f77c00..c40d014 100644 --- a/Sources/Pipeline/Modules/MarkdownOutputGenerator.swift +++ b/Sources/Pipeline/Modules/MarkdownOutputGenerator.swift @@ -82,7 +82,7 @@ private extension MarkdownOutputGenerator { var groupedChanges = [String: [Change]]() changesForTarget.forEach { - groupedChanges[$0.parentName] = (groupedChanges[$0.parentName] ?? []) + [$0] + groupedChanges[$0.parentPath ?? ""] = (groupedChanges[$0.parentPath ?? ""] ?? []) + [$0] } groupedChanges.keys.sorted().forEach { parent in diff --git a/Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpAnalyzer.swift b/Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpAnalyzer.swift index 35a3769..ce560fc 100644 --- a/Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpAnalyzer.swift +++ b/Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpAnalyzer.swift @@ -8,10 +8,10 @@ import Foundation struct SDKDumpAnalyzer: SDKDumpAnalyzing { - let changeConsolidator: ChangeConsolidating + let changeConsolidator: SDKDumpChangeConsolidating init( - changeConsolidator: ChangeConsolidating = ChangeConsolidator() + changeConsolidator: SDKDumpChangeConsolidating = SDKDumpChangeConsolidator() ) { self.changeConsolidator = changeConsolidator } @@ -39,7 +39,7 @@ struct SDKDumpAnalyzer: SDKDumpAnalyzing { element lhs: SDKDump.Element, to rhs: SDKDump.Element, oldFirst: Bool - ) -> [IndependentChange] { + ) -> [IndependentSDKDumpChange] { if lhs == rhs { return [] } @@ -49,7 +49,7 @@ struct SDKDumpAnalyzer: SDKDumpAnalyzing { // If both elements are internal we can ignore them as they are not in the public interface if lhs.isInternal, rhs.isInternal { return [] } - var changes = [IndependentChange]() + var changes = [IndependentSDKDumpChange]() if oldFirst, lhs.description != rhs.description { changes += independentChanges(from: lhs, and: rhs, oldFirst: oldFirst) @@ -80,7 +80,7 @@ struct SDKDumpAnalyzer: SDKDumpAnalyzing { // An (spi-)internal element was added/removed which we do not count as a public change if lhsElement.isSpiInternal || lhsElement.isInternal { return [] } - let changeType: IndependentChange.ChangeType = oldFirst ? + let changeType: IndependentSDKDumpChange.ChangeType = oldFirst ? .removal(lhsElement.description) : .addition(lhsElement.description) @@ -100,9 +100,9 @@ struct SDKDumpAnalyzer: SDKDumpAnalyzing { from lhs: SDKDump.Element, and rhs: SDKDump.Element, oldFirst: Bool - ) -> [IndependentChange] { + ) -> [IndependentSDKDumpChange] { - var changes: [IndependentChange] = [ + var changes: [IndependentSDKDumpChange] = [ .from( changeType: .removal(lhs.description), element: lhs, @@ -137,7 +137,14 @@ private extension SDKDump.Element { /// If we used the `name` it could cause a false positive with other functions named `init` (e.g. convenience inits) when trying to find matching elements during this finding phase. /// In a later consolidation phase removals/additions are compared again based on their `name` to combine them to a `change` func isComparable(to otherElement: SDKDump.Element) -> Bool { - printedName == otherElement.printedName && + + if declKind == .func && otherElement.declKind == .func { + print(printedName) + print(otherElement.printedName) + print("-----------------------------") + } + + return printedName == otherElement.printedName && declKind == otherElement.declKind && parentPath == otherElement.parentPath } diff --git a/Sources/Pipeline/Modules/SDKDumpAnalyzer/ChangeConsolidator.swift b/Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpChangeConsolidator.swift similarity index 88% rename from Sources/Pipeline/Modules/SDKDumpAnalyzer/ChangeConsolidator.swift rename to Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpChangeConsolidator.swift index 1d68f14..b8adf58 100644 --- a/Sources/Pipeline/Modules/SDKDumpAnalyzer/ChangeConsolidator.swift +++ b/Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpChangeConsolidator.swift @@ -7,16 +7,16 @@ import Foundation /// A helper to consolidate a `removal` and `addition` to `change` -protocol ChangeConsolidating { +protocol SDKDumpChangeConsolidating { /// Tries to match a `removal` and `addition` to a `change` /// /// - Parameters: /// - changes: The independent changes (`addition`/`removal`) to try to match - func consolidate(_ changes: [IndependentChange]) -> [Change] + func consolidate(_ changes: [IndependentSDKDumpChange]) -> [Change] } -struct ChangeConsolidator: ChangeConsolidating { +struct SDKDumpChangeConsolidator: SDKDumpChangeConsolidating { /// Tries to match a `removal` and `addition` to a `change` /// @@ -31,7 +31,7 @@ struct ChangeConsolidator: ChangeConsolidating { /// e.g. a second `addition` `init(unrelated: String)` might be matched as a change of `init(foo: Int, bar: Int)` /// as they share the same comparison features but might not be an actual change but a genuine addition. /// This is acceptable for now but might be improved in the future (e.g. calculating a matching-percentage) - func consolidate(_ changes: [IndependentChange]) -> [Change] { + func consolidate(_ changes: [IndependentSDKDumpChange]) -> [Change] { var independentChanges = changes var consolidatedChanges = [Change]() @@ -56,7 +56,7 @@ struct ChangeConsolidator: ChangeConsolidating { oldDescription: oldDescription, newDescription: newDescription ), - parentName: match.parentName, + parentPath: match.parentPath, listOfChanges: listOfChanges ) ) @@ -66,7 +66,7 @@ struct ChangeConsolidator: ChangeConsolidating { } /// Compiles a list of changes between 2 independent changes - func listOfChanges(between lhs: IndependentChange, and rhs: IndependentChange) -> [String] { + func listOfChanges(between lhs: IndependentSDKDumpChange, and rhs: IndependentSDKDumpChange) -> [String] { if lhs.oldFirst { lhs.element.differences(to: rhs.element) } else { @@ -75,7 +75,7 @@ struct ChangeConsolidator: ChangeConsolidating { } } -extension IndependentChange { +extension IndependentSDKDumpChange { var toConsolidatedChange: Change { let changeType: Change.ChangeType = { @@ -89,14 +89,17 @@ extension IndependentChange { return .init( changeType: changeType, - parentName: parentName, + parentPath: parentPath, listOfChanges: [] ) } /// Helper method to construct an IndependentChange from the changeType & element static func from(changeType: ChangeType, element: SDKDump.Element, oldFirst: Bool) -> Self { - .init( + if element.printedName.range(of: "asyncThrowingFunc") != nil { + print("Hello") + } + return .init( changeType: changeType, element: element, oldFirst: oldFirst @@ -114,7 +117,7 @@ extension IndependentChange { /// It could cause a false positive with other functions named `init` (e.g. convenience inits) when trying to find matching elements during the finding phase. /// Here we already found the matching elements and thus are looking for combining a removal/addition to a change and thus we can loosen the filter to use the `name`. /// It could potentially still lead to false positives when having multiple functions with changes and the same name and parent but this is acceptable in this phase. - func isConsolidatable(with otherChange: IndependentChange) -> Bool { + func isConsolidatable(with otherChange: IndependentSDKDumpChange) -> Bool { element.name == otherChange.element.name && element.declKind == otherChange.element.declKind && element.parentPath == otherChange.element.parentPath && @@ -122,7 +125,7 @@ extension IndependentChange { } } -private extension IndependentChange.ChangeType { +private extension IndependentSDKDumpChange.ChangeType { /// The name of the type (without associated value) as String var name: String { diff --git a/Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceAnalyzer.swift b/Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceAnalyzer.swift new file mode 100644 index 0000000..a665884 --- /dev/null +++ b/Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceAnalyzer.swift @@ -0,0 +1,125 @@ +// +// Copyright (c) 2024 Adyen N.V. +// +// This file is open source and available under the MIT license. See the LICENSE file for more info. +// + +import Foundation + +// TODO: Add a protocol for this + +struct SwiftInterfaceAnalyzer { + + let changeConsolidator: SwiftInterfaceChangeConsolidating + + init( + changeConsolidator: SwiftInterfaceChangeConsolidating = SwiftInterfaceChangeConsolidator() + ) { + self.changeConsolidator = changeConsolidator + } + + func analyze( + old: SwiftInterfaceParser.Root, + new: SwiftInterfaceParser.Root + ) -> [Change] { + + let individualChanges = Self.recursiveCompare( + element: old, + to: new, + oldFirst: true, + isRoot: true + ) + Self.recursiveCompare( + element: new, + to: old, + oldFirst: false, + isRoot: true + ) + + // Matching removals/additions to changes when applicable + return changeConsolidator.consolidate(individualChanges) + } + + private static func recursiveCompare( + element lhs: some SwiftInterfaceElement, + to rhs: some SwiftInterfaceElement, + oldFirst: Bool, + isRoot: Bool = false + ) -> [IndependentSwiftInterfaceChange] { + + if lhs.recursiveDescription() == rhs.recursiveDescription() { return [] } + + // If both elements are spi internal we can ignore them as they are not in the public interface + if !isRoot, lhs.isSpiInternal, rhs.isSpiInternal { return [] } + + var changes = [IndependentSwiftInterfaceChange]() + + if !isRoot, oldFirst, lhs.description != rhs.description { + changes += independentChanges(from: lhs, and: rhs, oldFirst: oldFirst) + } + + changes += lhs.children.flatMap { lhsElement in + + // Trying to find a matching element + + // First checking if we found an exact match based on the description + // as we don't want to match a non-change with a change + if let exactMatch = rhs.children.first(where: { $0.description == lhsElement.description }) { + // We found an exact match so we check if the children changed + return Self.recursiveCompare(element: lhsElement, to: exactMatch, oldFirst: oldFirst) + } + + // ... then losening the criteria to find a comparable element + if let rhsChildForName = rhs.children.first(where: { $0.isDiffable(with: lhsElement) }) { + // We found a comparable element so we check if the children changed + return Self.recursiveCompare(element: lhsElement, to: rhsChildForName, oldFirst: oldFirst) + } + + // No matching element was found so either it was removed or added + + // An (spi-)internal element was added/removed which we do not count as a public change + if lhsElement.isSpiInternal { return [IndependentSwiftInterfaceChange]() } + + let changeType: IndependentSwiftInterfaceChange.ChangeType = oldFirst ? + .removal(lhsElement.description) : + .addition(lhsElement.recursiveDescription()) + + return [ + .from( + changeType: changeType, + element: lhsElement, + oldFirst: oldFirst + ) + ] + } + + return changes + } + + private static func independentChanges( + from lhs: any SwiftInterfaceElement, + and rhs: any SwiftInterfaceElement, + oldFirst: Bool + ) -> [IndependentSwiftInterfaceChange] { + + var changes: [IndependentSwiftInterfaceChange] = [ + .from( + changeType: .removal(lhs.description), + element: lhs, + oldFirst: oldFirst + ) + ] + + if !rhs.isSpiInternal { + // We only report additions if they are not @_spi + changes += [ + .from( + changeType: .addition(rhs.recursiveDescription()), + element: rhs, + oldFirst: oldFirst + ) + ] + } + + return changes + } +} diff --git a/Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceChangeConsolidator.swift b/Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceChangeConsolidator.swift new file mode 100644 index 0000000..c931952 --- /dev/null +++ b/Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceChangeConsolidator.swift @@ -0,0 +1,138 @@ +// +// Copyright (c) 2024 Adyen N.V. +// +// This file is open source and available under the MIT license. See the LICENSE file for more info. +// + +import Foundation + +/// A helper to consolidate a `removal` and `addition` to `change` +protocol SwiftInterfaceChangeConsolidating { + + /// Tries to match a `removal` and `addition` to a `change` + /// + /// - Parameters: + /// - changes: The independent changes (`addition`/`removal`) to try to match + func consolidate(_ changes: [IndependentSwiftInterfaceChange]) -> [Change] +} + +struct SwiftInterfaceChangeConsolidator: SwiftInterfaceChangeConsolidating { + + /// Tries to match a `removal` and `addition` to a `change` + /// + /// - Parameters: + /// - changes: The independent changes (`addition`/`removal`) to try to match + /// + /// e.g. if we have a `removal` `init(foo: Int, bar: Int)` and an `addition` `init(foo: Int, bar: Int, baz: String)` + /// It will get consolidated to a `change` based on the `name`, `parent` & `declKind` + /// The changeType will be also respected so `removals` only get matched with `additions` and vice versa. + /// + /// This can lead to false positive matches in cases where one `removal` could potentially be matched to multiple `additions` or vice versa. + /// e.g. a second `addition` `init(unrelated: String)` might be matched as a change of `init(foo: Int, bar: Int)` + /// as they share the same comparison features but might not be an actual change but a genuine addition. + /// This is acceptable for now but might be improved in the future (e.g. calculating a matching-percentage) + func consolidate(_ changes: [IndependentSwiftInterfaceChange]) -> [Change] { + + var independentChanges = changes + var consolidatedChanges = [Change]() + + while !independentChanges.isEmpty { + let change = independentChanges.removeFirst() + + // Trying to find 2 independent changes that could actually have been a change instead of an addition/removal + guard let nameAndTypeMatchIndex = independentChanges.firstIndex(where: { $0.isConsolidatable(with: change) }) else { + consolidatedChanges.append(change.toConsolidatedChange) + continue + } + + let match = independentChanges.remove(at: nameAndTypeMatchIndex) + let oldDescription = change.oldFirst ? change.element.description : match.element.description + let newDescription = change.oldFirst ? match.element.description : change.element.description + let listOfChanges = listOfChanges(between: change, and: match) + + consolidatedChanges.append( + .init( + changeType: .change( + oldDescription: oldDescription, + newDescription: newDescription + ), + parentPath: match.parentPath, + listOfChanges: listOfChanges + ) + ) + } + + return consolidatedChanges + } + + /// Compiles a list of changes between 2 independent changes + func listOfChanges(between lhs: IndependentSwiftInterfaceChange, and rhs: IndependentSwiftInterfaceChange) -> [String] { + return [String]() + // TODO: Enable again + /* + if lhs.oldFirst { + lhs.element.differences(to: rhs.element) + } else { + rhs.element.differences(to: lhs.element) + } + */ + } +} + +extension IndependentSwiftInterfaceChange { + + var toConsolidatedChange: Change { + let changeType: Change.ChangeType = { + switch self.changeType { + case let .addition(description): + .addition(description: description) + case let .removal(description): + .removal(description: description) + } + }() + + return .init( + changeType: changeType, + parentPath: parentPath, + listOfChanges: [] + ) + } + + /// Helper method to construct an IndependentChange from the changeType & element + static func from(changeType: ChangeType, element: some SwiftInterfaceElement, oldFirst: Bool) -> Self { + .init( + changeType: changeType, + element: element, + oldFirst: oldFirst + ) + } + + /// Checks whether or not 2 changes can be diffed based on their elements `consolidatableName`, `declKind` and `parentPath`. + /// It also checks if the `changeType` is different to not compare 2 additions/removals with eachother. + /// + /// If the `consolidatableName`, `type`, `parentPath` of the element is the same we can assume that it's the same element but altered. + /// We're using the `name` and not the `printedName` is intended to be used to figure out if an addition & removal is actually a change. + /// `name` is more generic than `diffableSignature` as it (for functions) does not take the arguments into account. + /// + /// e.g. if we have a function `init(foo: Int, bar: Int) -> Void` the `name` would be `init` and `printedName` would be `init(foo:bar:)`. + /// It could cause a false positive with other functions named `init` (e.g. convenience inits) when trying to find matching elements during the finding phase. + /// Here we already found the matching elements and thus are looking for combining a removal/addition to a change and thus we can loosen the filter to use the `name`. + /// It could potentially still lead to false positives when having multiple functions with changes and the same name and parent but this is acceptable in this phase. + func isConsolidatable(with otherChange: IndependentSwiftInterfaceChange) -> Bool { + element.consolidatableName == otherChange.element.consolidatableName && + type(of: element) == type(of: otherChange.element) && + element.parentPath == otherChange.element.parentPath && + changeType.name != otherChange.changeType.name // We only want to match independent changes that are hava a different changeType + } +} + +private extension IndependentSwiftInterfaceChange.ChangeType { + + /// The name of the type (without associated value) as String + var name: String { + switch self { + case .addition: "addition" + case .removal: "removal" + } + } +} diff --git a/Tests/UnitTests/SwiftInterface/SwiftInterfaceParser.swift b/Sources/Pipeline/Modules/SwiftInterfaceParser/SwiftInterfaceParser.swift similarity index 56% rename from Tests/UnitTests/SwiftInterface/SwiftInterfaceParser.swift rename to Sources/Pipeline/Modules/SwiftInterfaceParser/SwiftInterfaceParser.swift index 4db6d74..42eb95d 100644 --- a/Tests/UnitTests/SwiftInterface/SwiftInterfaceParser.swift +++ b/Sources/Pipeline/Modules/SwiftInterfaceParser/SwiftInterfaceParser.swift @@ -1,4 +1,3 @@ -@testable import public_api_diff import Foundation import SwiftSyntax import SwiftParser @@ -10,12 +9,46 @@ import SwiftParser */ class SwiftInterfaceParser: SyntaxVisitor { - private var scope: Scope = .root(symbols: []) + class Root: SwiftInterfaceElement, Equatable { + + var parent: (any SwiftInterfaceElement)? = nil + + var diffableSignature: String { "" } + + var consolidatableName: String { "" } + + var description: String { + var description = "" + children.forEach { child in + description.append(child.recursiveDescription()) + description.append("\n") + } + return description + } + + var childGroupName: String { "Root" } + + let children: [any SwiftInterfaceElement] + + init(elements: [any SwiftInterfaceElement]) { + elements.forEach { $0.setupParentRelationships() } + self.children = elements + } + } + + // TODO: Handle (Nice to have) + // - DeinitializerDeclSyntax + // - PrecedenceGroupDeclSyntax + // - OperatorDeclSyntax + // - IfConfigClauseListSyntax + // - ... (There are more but not important right now) - static public func parse(source: String) -> [any SwiftInterfaceElement] { + private var scope: Scope = .root(elements: []) + + static public func parse(source: String) -> Root { let visitor = Self() visitor.walk(Parser.parse(source: source)) - return visitor.scope.symbols + return Root(elements: visitor.scope.elements) } /// Designated initializer @@ -33,24 +66,10 @@ class SwiftInterfaceParser: SyntaxVisitor { /// - Parameter makeSymbolWithChildrenInScope: Closure that return a new ``Symbol`` /// /// Call in `visitPost(_ node:)` methods - public func endScopeAndAddSymbol(makeSymbolsWithChildrenInScope: (_ children: [any SwiftInterfaceElement]) -> [any SwiftInterfaceElement]) { - scope.end(makeSymbolsWithChildrenInScope: makeSymbolsWithChildrenInScope) + public func endScopeAndAddSymbol(makeElementsWithChildrenInScope: (_ children: [any SwiftInterfaceElement]) -> [any SwiftInterfaceElement]) { + scope.end(makeElementsWithChildrenInScope: makeElementsWithChildrenInScope) } - // TODO: - // - InitializerDeclSyntax - // - DeinitializerDeclSyntax - // - ActorDeclSyntax - // - AccessorDeclSyntax - // - ExtensionDeclSyntax - // - // Nice to have: - // - PrecedenceGroupDeclSyntax - // - OperatorDeclSyntax - // - SubscriptDeclSyntax - // - IfConfigClauseListSyntax - // - ... (There are more but not important right now) - // MARK: - Class open override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind { @@ -140,45 +159,85 @@ class SwiftInterfaceParser: SyntaxVisitor { open override func visitPost(_ node: EnumCaseDeclSyntax) { endScopeAndAddSymbol { node.toInterfaceElement(children: $0) } } + + // MARK: - Extension + + open override func visit(_ node: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind { + startScope() + } + + open override func visitPost(_ node: ExtensionDeclSyntax) { + endScopeAndAddSymbol { [node.toInterfaceElement(children: $0)] } + } + + // MARK: - Initializer + + open override func visit(_ node: InitializerDeclSyntax) -> SyntaxVisitorContinueKind { + startScope() + } + + open override func visitPost(_ node: InitializerDeclSyntax) { + endScopeAndAddSymbol { _ in [node.toInterfaceElement()] } + } + + // MARK: - Actor + + open override func visit(_ node: ActorDeclSyntax) -> SyntaxVisitorContinueKind { + startScope() + } + + open override func visitPost(_ node: ActorDeclSyntax) { + endScopeAndAddSymbol { [node.toInterfaceElement(children: $0)] } + } + + // MARK: - Subscript + + open override func visit(_ node: SubscriptDeclSyntax) -> SyntaxVisitorContinueKind { + startScope() + } + + open override func visitPost(_ node: SubscriptDeclSyntax) { + endScopeAndAddSymbol { _ in [node.toInterfaceElement()] } + } } // MARK: - Models /// Inspired by: https://github.com/sdidla/Hatch/blob/main/Sources/Hatch/SymbolParser.swift -indirect enum Scope { +fileprivate indirect enum Scope { /// The root scope of a file - case root(symbols: [any SwiftInterfaceElement]) + case root(elements: [any SwiftInterfaceElement]) + /// A nested scope, within a parent scope - case nested(parent: Scope, symbols: [any SwiftInterfaceElement]) + case nested(parent: Scope, elements: [any SwiftInterfaceElement]) /// Starts a new nested scope mutating func start() { - self = .nested(parent: self, symbols: []) + self = .nested(parent: self, elements: []) } - /// Ends the current scope by adding a new symbol to the scope tree. + /// Ends the current scope by adding new elements to the scope tree. /// The children provided in the closure are the symbols in the scope to be ended - mutating func end(makeSymbolsWithChildrenInScope: (_ children: [any SwiftInterfaceElement]) -> [any SwiftInterfaceElement]) { - let newSymbols = makeSymbolsWithChildrenInScope(symbols) + mutating func end(makeElementsWithChildrenInScope: (_ children: [any SwiftInterfaceElement]) -> [any SwiftInterfaceElement]) { + let newElements = makeElementsWithChildrenInScope(elements) switch self { case .root: fatalError("Unbalanced calls to start() and end(_:)") - case .nested(.root(let rootSymbols), _): - self = .root(symbols: rootSymbols + newSymbols) + case .nested(.root(let rootElements), _): + self = .root(elements: rootElements + newElements) - case .nested(.nested(let parent, let parentSymbols), _): - self = .nested(parent: parent, symbols: parentSymbols + newSymbols) + case .nested(.nested(let parent, let parentElements), _): + self = .nested(parent: parent, elements: parentElements + newElements) } } - /// Symbols at current scope - var symbols: [any SwiftInterfaceElement] { + var elements: [any SwiftInterfaceElement] { switch self { - case .root(let symbols): return symbols - case .nested(_, let symbols): return symbols + case .root(let elements): return elements // All child elements recursive from the root + case .nested(_, let elements): return elements // All child elements recursive from a nested element } } } diff --git a/Sources/Pipeline/Modules/SwiftPackageFileAnalyzer.swift b/Sources/Pipeline/Modules/SwiftPackageFileAnalyzer.swift index e4d374c..c503e0b 100644 --- a/Sources/Pipeline/Modules/SwiftPackageFileAnalyzer.swift +++ b/Sources/Pipeline/Modules/SwiftPackageFileAnalyzer.swift @@ -59,7 +59,7 @@ struct SwiftPackageFileAnalyzer: ProjectAnalyzing { packageChanges += removedLibaries.map { .init( changeType: .removal(description: ".library(name: \"\($0)\", ...)"), - parentName: "" + parentPath: "" ) } @@ -67,7 +67,7 @@ struct SwiftPackageFileAnalyzer: ProjectAnalyzing { packageChanges += addedLibraries.map { .init( changeType: .addition(description: ".library(name: \"\($0)\", ...)"), - parentName: "" + parentPath: "" ) } diff --git a/Sources/Pipeline/Pipeline.swift b/Sources/Pipeline/Pipeline.swift index 8ada744..8632164 100644 --- a/Sources/Pipeline/Pipeline.swift +++ b/Sources/Pipeline/Pipeline.swift @@ -199,11 +199,11 @@ private extension Pipeline { private extension Change { static var removedTarget: Self { - .init(changeType: .removal(description: "Target was removed"), parentName: "") + .init(changeType: .removal(description: "Target was removed"), parentPath: "") } static var addedTarget: Self { - .init(changeType: .addition(description: "Target was added"), parentName: "") + .init(changeType: .addition(description: "Target was added"), parentPath: "") } } diff --git a/Tests/IntegrationTests/ReferencePackageTests.swift b/Tests/IntegrationTests/ReferencePackageTests.swift index b0e73d6..3016eaf 100644 --- a/Tests/IntegrationTests/ReferencePackageTests.swift +++ b/Tests/IntegrationTests/ReferencePackageTests.swift @@ -46,6 +46,8 @@ class ReferencePackageTests: XCTestCase { let expectedLines = sanitizeOutput(expectedOutput).components(separatedBy: "\n") let pipelineOutputLines = sanitizeOutput(pipelineOutput).components(separatedBy: "\n") + print(pipelineOutput) + for i in 0.. String { - let spacer = " " - var recursiveDescription = "\(String(repeating: spacer, count: indentation))\(description)" - if !self.children.isEmpty { - recursiveDescription.append("\n\(String(repeating: spacer, count: indentation)){") - for child in self.children { - recursiveDescription.append("\n\(String(repeating: spacer, count: indentation))\(child.recursiveDescription(indentation: indentation + 1))") - } - recursiveDescription.append("\n\(String(repeating: spacer, count: indentation))}") - } - return recursiveDescription - } -} - -extension SwiftInterfaceElement { - var isSpiInternal: Bool { - description.range(of: "@_spi(") != nil - } -} - -struct Placeholder: SwiftInterfaceElement { - let type: SDKDump.DeclarationKind - let children: [any SwiftInterfaceElement] - - var description: String { - return "\(type) Placeholder" - } - - init(type: SDKDump.DeclarationKind, children: [any SwiftInterfaceElement] = []) { - self.type = type - self.children = children - } -} diff --git a/Tests/UnitTests/SwiftInterfaceTests.swift b/Tests/UnitTests/SwiftInterfaceTests.swift index 734a14a..fafa5a0 100644 --- a/Tests/UnitTests/SwiftInterfaceTests.swift +++ b/Tests/UnitTests/SwiftInterfaceTests.swift @@ -41,13 +41,21 @@ class SwiftInterfaceTests: XCTestCase { return try XCTUnwrap(String(data: interfaceFileContent, encoding: .utf8)) }() - print("----- OLD -----") - SwiftInterfaceParser.parse(source: oldSource).forEach { element in - print(element.recursiveDescription()) - } - print("----- NEW -----") - SwiftInterfaceParser.parse(source: newSource).forEach { element in - print(element.recursiveDescription()) + let oldInterface = SwiftInterfaceParser.parse(source: oldSource) + let newInterface = SwiftInterfaceParser.parse(source: newSource) + + let analyzer = SwiftInterfaceAnalyzer() + + if oldInterface != newInterface { + let changes = analyzer.analyze(old: oldInterface, new: newInterface) + let output = MarkdownOutputGenerator().generate( + from: ["": changes], + allTargets: ["Target"], + oldSource: .local(path: "old"), + newSource: .local(path: "new"), + warnings: [] + ) + print(output) } /* diff --git a/Tests/UnitTests/SwiftPackageFileAnalyzerTests.swift b/Tests/UnitTests/SwiftPackageFileAnalyzerTests.swift index 3642b03..e279c81 100644 --- a/Tests/UnitTests/SwiftPackageFileAnalyzerTests.swift +++ b/Tests/UnitTests/SwiftPackageFileAnalyzerTests.swift @@ -94,8 +94,8 @@ class SwiftPackageFileAnalyzerTests: XCTestCase { ) let expectedChanges: [Change] = [ - .init(changeType: .removal(description: ".library(name: \"OldLibrary\", ...)"), parentName: ""), - .init(changeType: .addition(description: ".library(name: \"NewLibrary\", ...)"), parentName: "") + .init(changeType: .removal(description: ".library(name: \"OldLibrary\", ...)"), parentPath: ""), + .init(changeType: .addition(description: ".library(name: \"NewLibrary\", ...)"), parentPath: "") ] XCTAssertEqual(changes.changes, expectedChanges) From 65202afedcf8ab33a99b847e3c2d165ce2e5cd86 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Wed, 2 Oct 2024 16:48:29 +0200 Subject: [PATCH 04/45] Adding full support for individual changes --- Package.swift | 12 +- .../ReferencePackage/ReferencePackage.swift | 7 + .../ElementDescriptions/EnumCaseElement.swift | 2 - .../SDKDump/IndependentSDKDumpChange.swift | 25 ++ .../SDKDump/SDKDump+Element+Description.swift | 3 - .../SyntaxCollection+Convenience.swift | 6 + ...InitializerDeclSyntax+SwiftInterface.swift | 1 - .../IndependentSwiftInterfaceChange.swift} | 30 +- .../SwiftInterfaceElement+Actor.swift | 14 + ...SwiftInterfaceElement+AssociatedType.swift | 14 + .../SwiftInterfaceElement+Class.swift | 16 +- .../SwiftInterfaceElement+Enum.swift | 16 +- .../SwiftInterfaceElement+EnumCase.swift | 13 + .../SwiftInterfaceElement+Extension.swift | 16 +- .../SwiftInterfaceElement+Function.swift | 16 + .../SwiftInterfaceElement+Initializer.swift | 17 +- .../SwiftInterfaceElement+Protocol.swift | 14 + .../SwiftInterfaceElement+Struct.swift | 14 + .../SwiftInterfaceElement+Subscript.swift | 16 + .../SwiftInterfaceElement+TypeAlias.swift | 14 + .../SwiftInterfaceElement+Var.swift | 15 + ...iftInterfaceElement+DifferenceHelper.swift | 77 +++++ .../SwiftInterfaceElement.swift | 33 +- .../SDKDumpChangeConsolidator.swift | 3 - .../SwiftInterfaceAnalyzer.swift | 32 +- .../SwiftInterfaceChangeConsolidator.swift | 8 +- .../SwiftInterfaceParser.swift | 22 +- .../ReferencePackageTests.swift | 117 +++++-- .../expected-reference-changes-sdk-dump.md | 264 +++++++++++++++ ...ference-changes-swift-interface-private.md | 319 ++++++++++++++++++ ...eference-changes-swift-interface-public.md | 265 +++++++++++++++ .../Resources/expected-reference-changes.md | 96 ------ Tests/UnitTests/SwiftInterfaceTests.swift | 93 ----- Tests/public-api-diff.xctestplan | 2 +- 34 files changed, 1293 insertions(+), 319 deletions(-) create mode 100644 Sources/Helpers/Models/SDKDump/IndependentSDKDumpChange.swift rename Sources/Helpers/Models/{IndependentChange.swift => SwiftInterface/IndependentSwiftInterfaceChange.swift} (61%) rename Sources/Helpers/Models/SwiftInterface/{SwiftInterfaceElement => SwiftInterfaceElement+Declaration}/SwiftInterfaceElement+Actor.swift (70%) rename Sources/Helpers/Models/SwiftInterface/{SwiftInterfaceElement => SwiftInterfaceElement+Declaration}/SwiftInterfaceElement+AssociatedType.swift (69%) rename Sources/Helpers/Models/SwiftInterface/{SwiftInterfaceElement => SwiftInterfaceElement+Declaration}/SwiftInterfaceElement+Class.swift (69%) rename Sources/Helpers/Models/SwiftInterface/{SwiftInterfaceElement => SwiftInterfaceElement+Declaration}/SwiftInterfaceElement+Enum.swift (69%) rename Sources/Helpers/Models/SwiftInterface/{SwiftInterfaceElement => SwiftInterfaceElement+Declaration}/SwiftInterfaceElement+EnumCase.swift (74%) rename Sources/Helpers/Models/SwiftInterface/{SwiftInterfaceElement => SwiftInterfaceElement+Declaration}/SwiftInterfaceElement+Extension.swift (69%) rename Sources/Helpers/Models/SwiftInterface/{SwiftInterfaceElement => SwiftInterfaceElement+Declaration}/SwiftInterfaceElement+Function.swift (72%) rename Sources/Helpers/Models/SwiftInterface/{SwiftInterfaceElement => SwiftInterfaceElement+Declaration}/SwiftInterfaceElement+Initializer.swift (71%) rename Sources/Helpers/Models/SwiftInterface/{SwiftInterfaceElement => SwiftInterfaceElement+Declaration}/SwiftInterfaceElement+Protocol.swift (71%) rename Sources/Helpers/Models/SwiftInterface/{SwiftInterfaceElement => SwiftInterfaceElement+Declaration}/SwiftInterfaceElement+Struct.swift (70%) rename Sources/Helpers/Models/SwiftInterface/{SwiftInterfaceElement => SwiftInterfaceElement+Declaration}/SwiftInterfaceElement+Subscript.swift (71%) rename Sources/Helpers/Models/SwiftInterface/{SwiftInterfaceElement => SwiftInterfaceElement+Declaration}/SwiftInterfaceElement+TypeAlias.swift (68%) rename Sources/Helpers/Models/SwiftInterface/{SwiftInterfaceElement => SwiftInterfaceElement+Declaration}/SwiftInterfaceElement+Var.swift (66%) create mode 100644 Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+DifferenceHelper.swift rename Sources/Helpers/Models/SwiftInterface/{SwiftInterfaceElement => }/SwiftInterfaceElement.swift (83%) create mode 100644 Tests/IntegrationTests/Resources/expected-reference-changes-sdk-dump.md create mode 100644 Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-private.md create mode 100644 Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-public.md delete mode 100644 Tests/IntegrationTests/Resources/expected-reference-changes.md delete mode 100644 Tests/UnitTests/SwiftInterfaceTests.swift diff --git a/Package.swift b/Package.swift index ba87e1c..3d7b1ee 100644 --- a/Package.swift +++ b/Package.swift @@ -19,16 +19,16 @@ let package = Package( .executableTarget( name: "public-api-diff", dependencies: [ - .product(name: "ArgumentParser", package: "swift-argument-parser") + .product(name: "ArgumentParser", package: "swift-argument-parser"), + .product(name: "SwiftSyntax", package: "swift-syntax"), + .product(name: "SwiftParser", package: "swift-syntax"), ], path: "Sources" ), .testTarget( name: "UnitTests", dependencies: [ - "public-api-diff", - .product(name: "SwiftSyntax", package: "swift-syntax"), - .product(name: "SwiftParser", package: "swift-syntax"), + "public-api-diff" ], resources: [ // Copy Tests/ExampleTests/Resources directories as-is. @@ -46,7 +46,9 @@ let package = Package( // Copy Tests/ExampleTests/Resources directories as-is. // Use to retain directory structure. // Will be at top level in bundle. - .copy("Resources/expected-reference-changes.md") + .copy("Resources/expected-reference-changes-sdk-dump.md"), + .copy("Resources/expected-reference-changes-swift-interface-private.md"), + .copy("Resources/expected-reference-changes-swift-interface-public.md") ] ) ] diff --git a/ReferencePackages/UpdatedPackage/Sources/ReferencePackage/ReferencePackage.swift b/ReferencePackages/UpdatedPackage/Sources/ReferencePackage/ReferencePackage.swift index 0922d71..13cd1c2 100644 --- a/ReferencePackages/UpdatedPackage/Sources/ReferencePackage/ReferencePackage.swift +++ b/ReferencePackages/UpdatedPackage/Sources/ReferencePackage/ReferencePackage.swift @@ -195,6 +195,13 @@ extension CustomEnum: SimpleProtocol { } } +extension CustomEnum.NestedStructInExtension { + + var description: String { + return string + } +} + public extension CustomEnum where T == String { var titleOfCaseWithNamedString: String? { diff --git a/Sources/Helpers/Models/SDKDump/ElementDescriptions/EnumCaseElement.swift b/Sources/Helpers/Models/SDKDump/ElementDescriptions/EnumCaseElement.swift index d04e1aa..60de61a 100644 --- a/Sources/Helpers/Models/SDKDump/ElementDescriptions/EnumCaseElement.swift +++ b/Sources/Helpers/Models/SDKDump/ElementDescriptions/EnumCaseElement.swift @@ -36,8 +36,6 @@ extension SDKDump { private extension SDKDump.EnumCaseElement { func compileDescription() -> String { - // TODO: Add support for: indirect - // See: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/declarations#Enumerations-with-Indirection let defaultDescription = "\(declaration) \(underlyingElement.printedName)" diff --git a/Sources/Helpers/Models/SDKDump/IndependentSDKDumpChange.swift b/Sources/Helpers/Models/SDKDump/IndependentSDKDumpChange.swift new file mode 100644 index 0000000..eda3371 --- /dev/null +++ b/Sources/Helpers/Models/SDKDump/IndependentSDKDumpChange.swift @@ -0,0 +1,25 @@ +import Foundation + +/// A change indicating an `addition` or `removal` of an element +/// +/// This intermediate structure helps gathering a list of additions and removals +/// that are later consolidated to a ``Change`` +struct IndependentSDKDumpChange: Equatable { + enum ChangeType: Equatable { + case addition(_ description: String) + case removal(_ description: String) + + var description: String { + switch self { + case let .addition(description): description + case let .removal(description): description + } + } + } + + let changeType: ChangeType + let element: SDKDump.Element + + let oldFirst: Bool + var parentPath: String { element.parentPath } +} diff --git a/Sources/Helpers/Models/SDKDump/SDKDump+Element+Description.swift b/Sources/Helpers/Models/SDKDump/SDKDump+Element+Description.swift index ff1e6f9..670f0ea 100644 --- a/Sources/Helpers/Models/SDKDump/SDKDump+Element+Description.swift +++ b/Sources/Helpers/Models/SDKDump/SDKDump+Element+Description.swift @@ -48,9 +48,6 @@ private extension SDKDump.Element { private var genericPrefixes: [String] { var components = [String]() - // TODO: Add support for: unowned, ... - // See: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/declarations#Declaration-Modifiers - spiGroupNames?.forEach { components += ["@_spi(\($0))"] } if hasDiscardableResult { components += ["@discardableResult"] } if isObjcAccessible { components += ["@objc"] } diff --git a/Sources/Helpers/Models/SwiftInterface/DeclSyntax+Convenience/SyntaxCollection+Convenience.swift b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+Convenience/SyntaxCollection+Convenience.swift index d0a5495..c43f15b 100644 --- a/Sources/Helpers/Models/SwiftInterface/DeclSyntax+Convenience/SyntaxCollection+Convenience.swift +++ b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+Convenience/SyntaxCollection+Convenience.swift @@ -5,3 +5,9 @@ extension SyntaxCollection { self.map { $0.trimmedDescription } } } + +extension InheritedTypeListSyntax { + var sanitizedList: [String] { + self.map { $0.type.trimmedDescription } + } +} diff --git a/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/InitializerDeclSyntax+SwiftInterface.swift b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/InitializerDeclSyntax+SwiftInterface.swift index 82f2b69..b4a3c73 100644 --- a/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/InitializerDeclSyntax+SwiftInterface.swift +++ b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/InitializerDeclSyntax+SwiftInterface.swift @@ -33,7 +33,6 @@ extension InitializerDeclSyntax { genericParameterDescription: self.genericParameterClause?.trimmedDescription, parameters: parameters, effectSpecifiers: effectSpecifiers, - returnType: signature.returnClause?.type.trimmedDescription, genericWhereClauseDescription: self.genericWhereClause?.trimmedDescription ) } diff --git a/Sources/Helpers/Models/IndependentChange.swift b/Sources/Helpers/Models/SwiftInterface/IndependentSwiftInterfaceChange.swift similarity index 61% rename from Sources/Helpers/Models/IndependentChange.swift rename to Sources/Helpers/Models/SwiftInterface/IndependentSwiftInterfaceChange.swift index ebe6fd0..bc0081e 100644 --- a/Sources/Helpers/Models/IndependentChange.swift +++ b/Sources/Helpers/Models/SwiftInterface/IndependentSwiftInterfaceChange.swift @@ -1,35 +1,9 @@ -// -// Copyright (c) 2024 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - import Foundation /// A change indicating an `addition` or `removal` of an element /// /// This intermediate structure helps gathering a list of additions and removals /// that are later consolidated to a ``Change`` -struct IndependentSDKDumpChange: Equatable { - enum ChangeType: Equatable { - case addition(_ description: String) - case removal(_ description: String) - - var description: String { - switch self { - case let .addition(description): description - case let .removal(description): description - } - } - } - - let changeType: ChangeType - let element: SDKDump.Element - - let oldFirst: Bool - var parentPath: String { element.parentPath } -} - struct IndependentSwiftInterfaceChange: Equatable { enum ChangeType: Equatable { @@ -56,4 +30,8 @@ struct IndependentSwiftInterfaceChange: Equatable { lhs.oldFirst == rhs.oldFirst && lhs.parentPath == rhs.parentPath } + + func differences(to otherIndependentChange: IndependentSwiftInterfaceChange) -> [String] { + element.differences(to: otherIndependentChange.element).sorted() + } } diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Actor.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Actor.swift similarity index 70% rename from Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Actor.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Actor.swift index e2d9bca..50302ac 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Actor.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Actor.swift @@ -56,6 +56,20 @@ class SwiftInterfaceActor: SwiftInterfaceElement { } } +extension SwiftInterfaceActor { + + func differences(to otherElement: T) -> [String] { + var changes = [String?]() + guard let other = otherElement as? Self else { return [] } + changes += diffDescription(propertyType: "attribute", oldValues: other.attributes, newValues: attributes) + changes += diffDescription(propertyType: "modifier", oldValues: other.modifiers, newValues: modifiers) + changes += diffDescription(propertyType: "generic parameter description", oldValue: other.genericParameterDescription, newValue: genericParameterDescription) + changes += diffDescription(propertyType: "inheritance", oldValues: other.inheritance, newValues: inheritance) + changes += diffDescription(propertyType: "generic where clause", oldValue: other.genericWhereClauseDescription, newValue: genericWhereClauseDescription) + return changes.compactMap { $0 } + } +} + private extension SwiftInterfaceActor { func compileDescription() -> String { diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+AssociatedType.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+AssociatedType.swift similarity index 69% rename from Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+AssociatedType.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+AssociatedType.swift index 09855db..40976a7 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+AssociatedType.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+AssociatedType.swift @@ -54,6 +54,20 @@ class SwiftInterfaceAssociatedType: SwiftInterfaceElement { } } +extension SwiftInterfaceAssociatedType { + + func differences(to otherElement: T) -> [String] { + var changes = [String?]() + guard let other = otherElement as? Self else { return [] } + changes += diffDescription(propertyType: "attribute", oldValues: other.attributes, newValues: attributes) + changes += diffDescription(propertyType: "modifier", oldValues: other.modifiers, newValues: modifiers) + changes += diffDescription(propertyType: "inheritance", oldValues: other.inheritance, newValues: inheritance) + changes += diffDescription(propertyType: "assignment", oldValue: other.initializerValue, newValue: initializerValue) + changes += diffDescription(propertyType: "generic where clause", oldValue: other.genericWhereClauseDescription, newValue: genericWhereClauseDescription) + return changes.compactMap { $0 } + } +} + private extension SwiftInterfaceAssociatedType { func compileDescription() -> String { diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Class.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Class.swift similarity index 69% rename from Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Class.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Class.swift index 41258c9..7ea4452 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Class.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Class.swift @@ -18,7 +18,7 @@ class SwiftInterfaceClass: SwiftInterfaceElement { /// e.g. where T : Equatable let genericWhereClauseDescription: String? - var childGroupName: String { name } // Not relevant as only used to group children + var childGroupName: String { name } /// The members, declarations, ... inside of the body of the struct let children: [any SwiftInterfaceElement] @@ -56,6 +56,20 @@ class SwiftInterfaceClass: SwiftInterfaceElement { } } +extension SwiftInterfaceClass { + + func differences(to otherElement: T) -> [String] { + var changes = [String?]() + guard let other = otherElement as? Self else { return [] } + changes += diffDescription(propertyType: "attribute", oldValues: other.attributes, newValues: attributes) + changes += diffDescription(propertyType: "modifier", oldValues: other.modifiers, newValues: modifiers) + changes += diffDescription(propertyType: "generic parameter description", oldValue: other.genericParameterDescription, newValue: genericParameterDescription) + changes += diffDescription(propertyType: "inheritance", oldValues: other.inheritance, newValues: inheritance) + changes += diffDescription(propertyType: "generic where clause", oldValue: other.genericWhereClauseDescription, newValue: genericWhereClauseDescription) + return changes.compactMap { $0 } + } +} + private extension SwiftInterfaceClass { func compileDescription() -> String { diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Enum.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Enum.swift similarity index 69% rename from Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Enum.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Enum.swift index 6c3d89a..259c0cd 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Enum.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Enum.swift @@ -18,7 +18,7 @@ class SwiftInterfaceEnum: SwiftInterfaceElement { /// e.g. where T : Equatable let genericWhereClauseDescription: String? - var childGroupName: String { name } // Not relevant as only used to group children + var childGroupName: String { name } /// The members, declarations, ... inside of the body of the struct let children: [any SwiftInterfaceElement] @@ -56,6 +56,20 @@ class SwiftInterfaceEnum: SwiftInterfaceElement { } } +extension SwiftInterfaceEnum { + + func differences(to otherElement: T) -> [String] { + var changes = [String?]() + guard let other = otherElement as? Self else { return [] } + changes += diffDescription(propertyType: "attribute", oldValues: other.attributes, newValues: attributes) + changes += diffDescription(propertyType: "modifier", oldValues: other.modifiers, newValues: modifiers) + changes += diffDescription(propertyType: "generic parameter description", oldValue: other.genericParameterDescription, newValue: genericParameterDescription) + changes += diffDescription(propertyType: "inheritance", oldValues: other.inheritance, newValues: inheritance) + changes += diffDescription(propertyType: "generic where clause", oldValue: other.genericWhereClauseDescription, newValue: genericWhereClauseDescription) + return changes.compactMap { $0 } + } +} + private extension SwiftInterfaceEnum { func compileDescription() -> String { diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+EnumCase.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+EnumCase.swift similarity index 74% rename from Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+EnumCase.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+EnumCase.swift index 42c44b9..47a8ab8 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+EnumCase.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+EnumCase.swift @@ -81,6 +81,19 @@ class SwiftInterfaceEnumCase: SwiftInterfaceElement { } } +extension SwiftInterfaceEnumCase { + + func differences(to otherElement: T) -> [String] { + var changes = [String?]() + guard let other = otherElement as? Self else { return [] } + changes += diffDescription(propertyType: "attribute", oldValues: other.attributes, newValues: attributes) + changes += diffDescription(propertyType: "modifier", oldValues: other.modifiers, newValues: modifiers) + changes += diffDescription(propertyType: "parameter", oldValues: other.parameters?.map { $0.description }, newValues: parameters?.map { $0.description }) // TODO: Maybe have a better way to show changes + changes += diffDescription(propertyType: "raw value", oldValue: other.rawValue, newValue: rawValue) + return changes.compactMap { $0 } + } +} + private extension SwiftInterfaceEnumCase { func compileDescription() -> String { diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Extension.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Extension.swift similarity index 69% rename from Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Extension.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Extension.swift index 6083106..ceafb2a 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Extension.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Extension.swift @@ -15,8 +15,7 @@ class SwiftInterfaceExtension: SwiftInterfaceElement { /// e.g. where T : Equatable let genericWhereClauseDescription: String? - // TODO: The extensions show up independently on the root - find a way so we can nest them inside the parent (find a way to find the parent) - var childGroupName: String { extendedType } // Grouping in extended type + var childGroupName: String { extendedType } // Grouping by extended type /// The members, declarations, ... inside of the body of the struct let children: [any SwiftInterfaceElement] @@ -52,6 +51,19 @@ class SwiftInterfaceExtension: SwiftInterfaceElement { } } +extension SwiftInterfaceExtension { + + func differences(to otherElement: T) -> [String] { + var changes = [String?]() + guard let other = otherElement as? Self else { return [] } + changes += diffDescription(propertyType: "attribute", oldValues: other.attributes, newValues: attributes) + changes += diffDescription(propertyType: "modifier", oldValues: other.modifiers, newValues: modifiers) + changes += diffDescription(propertyType: "inheritance", oldValues: other.inheritance, newValues: inheritance) + changes += diffDescription(propertyType: "generic where clause", oldValue: other.genericWhereClauseDescription, newValue: genericWhereClauseDescription) + return changes.compactMap { $0 } + } +} + private extension SwiftInterfaceExtension { func compileDescription() -> String { diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Function.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Function.swift similarity index 72% rename from Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Function.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Function.swift index 7e5af85..7f515f6 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Function.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Function.swift @@ -97,6 +97,22 @@ class SwiftInterfaceFunction: SwiftInterfaceElement { } } +extension SwiftInterfaceFunction { + + func differences(to otherElement: T) -> [String] { + var changes = [String?]() + guard let other = otherElement as? Self else { return [] } + changes += diffDescription(propertyType: "attribute", oldValues: other.attributes, newValues: attributes) + changes += diffDescription(propertyType: "modifier", oldValues: other.modifiers, newValues: modifiers) + changes += diffDescription(propertyType: "generic parameter description", oldValue: other.genericParameterDescription, newValue: genericParameterDescription) + changes += diffDescription(propertyType: "parameter", oldValues: other.parameters.map { $0.description }, newValues: parameters.map { $0.description }) // TODO: Maybe have a better way to show changes + changes += diffDescription(propertyType: "effect", oldValues: other.effectSpecifiers, newValues: effectSpecifiers) + changes += diffDescription(propertyType: "return type", oldValue: other.returnType, newValue: returnType) + changes += diffDescription(propertyType: "generic where clause", oldValue: other.genericWhereClauseDescription, newValue: genericWhereClauseDescription) + return changes.compactMap { $0 } + } +} + private extension SwiftInterfaceFunction { func compileDescription() -> String { diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Initializer.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Initializer.swift similarity index 71% rename from Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Initializer.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Initializer.swift index b2c78bc..6642fbb 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Initializer.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Initializer.swift @@ -81,7 +81,6 @@ class SwiftInterfaceInitializer: SwiftInterfaceElement { genericParameterDescription: String?, parameters: [Parameter], effectSpecifiers: [String], - returnType: String?, genericWhereClauseDescription: String? ) { self.attributes = attributes @@ -94,6 +93,22 @@ class SwiftInterfaceInitializer: SwiftInterfaceElement { } } +extension SwiftInterfaceInitializer { + + func differences(to otherElement: T) -> [String] { + var changes = [String?]() + guard let other = otherElement as? Self else { return [] } + changes += diffDescription(propertyType: "attribute", oldValues: other.attributes, newValues: attributes) + changes += diffDescription(propertyType: "modifier", oldValues: other.modifiers, newValues: modifiers) + changes += diffDescription(propertyType: "optional mark", oldValue: other.optionalMark, newValue: optionalMark) + changes += diffDescription(propertyType: "generic parameter description", oldValue: other.genericParameterDescription, newValue: genericParameterDescription) + changes += diffDescription(propertyType: "parameter", oldValues: other.parameters.map { $0.description }, newValues: parameters.map { $0.description }) // TODO: Maybe have a better way to show changes + changes += diffDescription(propertyType: "effect", oldValues: other.effectSpecifiers, newValues: effectSpecifiers) + changes += diffDescription(propertyType: "generic where clause", oldValue: other.genericWhereClauseDescription, newValue: genericWhereClauseDescription) + return changes.compactMap { $0 } + } +} + private extension SwiftInterfaceInitializer { func compileDescription() -> String { diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Protocol.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Protocol.swift similarity index 71% rename from Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Protocol.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Protocol.swift index 5a9e4d3..210a71c 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Protocol.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Protocol.swift @@ -55,6 +55,20 @@ class SwiftInterfaceProtocol: SwiftInterfaceElement { } } +extension SwiftInterfaceProtocol { + + func differences(to otherElement: T) -> [String] { + var changes = [String?]() + guard let other = otherElement as? Self else { return [] } + changes += diffDescription(propertyType: "attribute", oldValues: other.attributes, newValues: attributes) + changes += diffDescription(propertyType: "modifier", oldValues: other.modifiers, newValues: modifiers) + changes += diffDescription(propertyType: "primary associated type", oldValues: other.primaryAssociatedTypes, newValues: primaryAssociatedTypes) + changes += diffDescription(propertyType: "inheritance", oldValues: other.inheritance, newValues: inheritance) + changes += diffDescription(propertyType: "generic where clause", oldValue: other.genericWhereClauseDescription, newValue: genericWhereClauseDescription) + return changes.compactMap { $0 } + } +} + private extension SwiftInterfaceProtocol { func compileDescription() -> String { diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Struct.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Struct.swift similarity index 70% rename from Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Struct.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Struct.swift index 0c5a4f4..842fad7 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Struct.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Struct.swift @@ -56,6 +56,20 @@ class SwiftInterfaceStruct: SwiftInterfaceElement { } } +extension SwiftInterfaceStruct { + + func differences(to otherElement: T) -> [String] { + var changes = [String?]() + guard let other = otherElement as? Self else { return [] } + changes += diffDescription(propertyType: "attribute", oldValues: other.attributes, newValues: attributes) + changes += diffDescription(propertyType: "modifier", oldValues: other.modifiers, newValues: modifiers) + changes += diffDescription(propertyType: "generic parameter description", oldValue: other.genericParameterDescription, newValue: genericParameterDescription) + changes += diffDescription(propertyType: "inheritance", oldValues: other.inheritance, newValues: inheritance) + changes += diffDescription(propertyType: "generic where clause", oldValue: other.genericWhereClauseDescription, newValue: genericWhereClauseDescription) + return changes.compactMap { $0 } + } +} + private extension SwiftInterfaceStruct { func compileDescription() -> String { diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Subscript.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Subscript.swift similarity index 71% rename from Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Subscript.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Subscript.swift index f4bdfa2..b05db51 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Subscript.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Subscript.swift @@ -94,6 +94,22 @@ class SwiftInterfaceSubscript: SwiftInterfaceElement { } } +extension SwiftInterfaceSubscript { + + func differences(to otherElement: T) -> [String] { + var changes = [String?]() + guard let other = otherElement as? Self else { return [] } + changes += diffDescription(propertyType: "attribute", oldValues: other.attributes, newValues: attributes) + changes += diffDescription(propertyType: "modifier", oldValues: other.modifiers, newValues: modifiers) + changes += diffDescription(propertyType: "generic parameter description", oldValue: other.genericParameterDescription, newValue: genericParameterDescription) + changes += diffDescription(propertyType: "parameter", oldValues: other.parameters.map { $0.description }, newValues: parameters.map { $0.description }) // TODO: Maybe have a better way to show changes + changes += diffDescription(propertyType: "return type", oldValue: other.returnType, newValue: returnType) + changes += diffDescription(propertyType: "generic where clause", oldValue: other.genericWhereClauseDescription, newValue: genericWhereClauseDescription) + changes += diffDescription(propertyType: "accessors", oldValue: other.accessors, newValue: accessors) + return changes.compactMap { $0 } + } +} + private extension SwiftInterfaceSubscript { func compileDescription() -> String { diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+TypeAlias.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+TypeAlias.swift similarity index 68% rename from Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+TypeAlias.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+TypeAlias.swift index c0ec8cc..927e6c9 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+TypeAlias.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+TypeAlias.swift @@ -55,6 +55,20 @@ class SwiftInterfaceTypeAlias: SwiftInterfaceElement { } } +extension SwiftInterfaceTypeAlias { + + func differences(to otherElement: T) -> [String] { + var changes = [String?]() + guard let other = otherElement as? Self else { return [] } + changes += diffDescription(propertyType: "attribute", oldValues: other.attributes, newValues: attributes) + changes += diffDescription(propertyType: "modifier", oldValues: other.modifiers, newValues: modifiers) + changes += diffDescription(propertyType: "generic parameter description", oldValue: other.genericParameterDescription, newValue: genericParameterDescription) + changes += diffDescription(propertyType: "assignment", oldValue: other.initializerValue, newValue: initializerValue) + changes += diffDescription(propertyType: "generic where clause", oldValue: other.genericWhereClauseDescription, newValue: genericWhereClauseDescription) + return changes.compactMap { $0 } + } +} + private extension SwiftInterfaceTypeAlias { func compileDescription() -> String { diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Var.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Var.swift similarity index 66% rename from Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Var.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Var.swift index 39792ac..8221736 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement+Var.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Var.swift @@ -57,6 +57,21 @@ class SwiftInterfaceVar: SwiftInterfaceElement { } } +extension SwiftInterfaceVar { + + func differences(to otherElement: T) -> [String] { + var changes = [String?]() + guard let other = otherElement as? Self else { return [] } + changes += diffDescription(propertyType: "attribute", oldValues: other.attributes, newValues: attributes) + changes += diffDescription(propertyType: "modifier", oldValues: other.modifiers, newValues: modifiers) + changes += diffDescription(propertyType: nil, oldValue: other.bindingSpecifier, newValue: bindingSpecifier) + changes += diffDescription(propertyType: "type", oldValue: other.typeAnnotation, newValue: typeAnnotation) + changes += diffDescription(propertyType: "default value", oldValue: other.initializerValue, newValue: initializerValue) + changes += diffDescription(propertyType: "accessors", oldValue: other.accessors, newValue: accessors) + return changes.compactMap { $0 } + } +} + private extension SwiftInterfaceVar { func compileDescription() -> String { diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+DifferenceHelper.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+DifferenceHelper.swift new file mode 100644 index 0000000..43e81fc --- /dev/null +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+DifferenceHelper.swift @@ -0,0 +1,77 @@ +// +// File.swift +// +// +// Created by Alexander Guretzki on 02/10/2024. +// + +import Foundation + +fileprivate enum ChangeType { + case change(old: String, new: String) + case removal(String) + case addition(String) + + var title: String { + switch self { + case .change: "Changed" + case .removal: "Removed" + case .addition: "Added" + } + } + + static func `for`(oldValue: String?, newValue: String?) -> Self? { + if oldValue == newValue { return nil } + if let oldValue, let newValue { return .change(old: oldValue, new: newValue) } + if let oldValue { return .removal(oldValue) } + if let newValue { return .addition(newValue) } + return nil + } +} + +extension SwiftInterfaceElement { + + func diffDescription(propertyType: String?, oldValue: String?, newValue: String?) -> [String] { + + guard let changeType: ChangeType = .for(oldValue: oldValue, newValue: newValue) else { return [] } + + var diffDescription: String + if let propertyType { + diffDescription = "\(changeType.title) \(propertyType)" + } else { + diffDescription = "\(changeType.title)" + } + + switch changeType { + case .change(let old, let new): + diffDescription += " from `\(old)` to `\(new)`" + case .removal(let string): + diffDescription += " `\(string)`" + case .addition(let string): + diffDescription += " `\(string)`" + } + + return [diffDescription] + } + + func diffDescription(propertyType: String, oldValues: [String]?, newValues: [String]?) -> [String] { + + if let oldValues, let newValues { + let old = Set(oldValues) + let new = Set(newValues) + return old.symmetricDifference(new).map { + "\(new.contains($0) ? "Added" : "Removed") \(propertyType) `\($0)`" + } + } + + if let oldValues { + return oldValues.map { "Removed \(propertyType) `\($0)`" } + } + + if let newValues { + return newValues.map { "Added \(propertyType) `\($0)`" } + } + + return [] + } +} diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement.swift similarity index 83% rename from Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement.swift rename to Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement.swift index 25af9bc..6e976e2 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement/SwiftInterfaceElement.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement.swift @@ -1,8 +1,8 @@ import Foundation -protocol SwiftInterfaceElement: CustomStringConvertible, Equatable, AnyObject { +protocol SwiftInterfaceElement: CustomStringConvertible, AnyObject { - /// Used to group output together + /// Used to group children together var childGroupName: String { get } var description: String { get } @@ -20,7 +20,10 @@ protocol SwiftInterfaceElement: CustomStringConvertible, Equatable, AnyObject { /// e.g. `func foo(bar: Int = 0, baz: String)` would have a consolidatable name of `foo` var consolidatableName: String { get } + /// The parent of the element (setup by using ``setupParentRelationships(parent:)`` var parent: (any SwiftInterfaceElement)? { get set } + + func differences(to otherElement: T) -> [String] } extension SwiftInterfaceElement { @@ -33,6 +36,12 @@ extension SwiftInterfaceElement { } var parentPath: String { + if let extensionElement = self as? SwiftInterfaceExtension { + // We want to group all extensions under the type that they are extending + // so we return the extended type as the parent + return extensionElement.extendedType + } + var parent = self.parent var path = [parent?.childGroupName] @@ -41,23 +50,11 @@ extension SwiftInterfaceElement { path += [parent?.childGroupName] } - var sanitizedPath = path.compactMap { $0 } - - if sanitizedPath.last == "TopLevel" { - sanitizedPath.removeLast() - } - + let sanitizedPath = path.compactMap { $0 } return sanitizedPath.reversed().joined(separator: ".") } } -extension SwiftInterfaceElement { - static func == (lhs: Self, rhs: Self) -> Bool { - // The description is the unique representation of an element and thus used for the equality check - lhs.description == rhs.description - } -} - extension SwiftInterfaceElement { /// Checks whether or not 2 elements can be compared based on their `printedName`, `type` and `parentPath` /// @@ -87,9 +84,3 @@ extension SwiftInterfaceElement { return recursiveDescription } } - -extension SwiftInterfaceElement { - var isSpiInternal: Bool { - description.range(of: "@_spi(") != nil - } -} diff --git a/Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpChangeConsolidator.swift b/Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpChangeConsolidator.swift index b8adf58..f7c8f51 100644 --- a/Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpChangeConsolidator.swift +++ b/Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpChangeConsolidator.swift @@ -96,9 +96,6 @@ extension IndependentSDKDumpChange { /// Helper method to construct an IndependentChange from the changeType & element static func from(changeType: ChangeType, element: SDKDump.Element, oldFirst: Bool) -> Self { - if element.printedName.range(of: "asyncThrowingFunc") != nil { - print("Hello") - } return .init( changeType: changeType, element: element, diff --git a/Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceAnalyzer.swift b/Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceAnalyzer.swift index a665884..c4f712b 100644 --- a/Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceAnalyzer.swift +++ b/Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceAnalyzer.swift @@ -19,8 +19,8 @@ struct SwiftInterfaceAnalyzer { } func analyze( - old: SwiftInterfaceParser.Root, - new: SwiftInterfaceParser.Root + old: some SwiftInterfaceElement, + new: some SwiftInterfaceElement ) -> [Change] { let individualChanges = Self.recursiveCompare( @@ -48,9 +48,6 @@ struct SwiftInterfaceAnalyzer { if lhs.recursiveDescription() == rhs.recursiveDescription() { return [] } - // If both elements are spi internal we can ignore them as they are not in the public interface - if !isRoot, lhs.isSpiInternal, rhs.isSpiInternal { return [] } - var changes = [IndependentSwiftInterfaceChange]() if !isRoot, oldFirst, lhs.description != rhs.description { @@ -75,10 +72,6 @@ struct SwiftInterfaceAnalyzer { } // No matching element was found so either it was removed or added - - // An (spi-)internal element was added/removed which we do not count as a public change - if lhsElement.isSpiInternal { return [IndependentSwiftInterfaceChange]() } - let changeType: IndependentSwiftInterfaceChange.ChangeType = oldFirst ? .removal(lhsElement.description) : .addition(lhsElement.recursiveDescription()) @@ -100,26 +93,17 @@ struct SwiftInterfaceAnalyzer { and rhs: any SwiftInterfaceElement, oldFirst: Bool ) -> [IndependentSwiftInterfaceChange] { - - var changes: [IndependentSwiftInterfaceChange] = [ + [ .from( changeType: .removal(lhs.description), element: lhs, oldFirst: oldFirst + ), + .from( + changeType: .addition(rhs.recursiveDescription()), + element: rhs, + oldFirst: oldFirst ) ] - - if !rhs.isSpiInternal { - // We only report additions if they are not @_spi - changes += [ - .from( - changeType: .addition(rhs.recursiveDescription()), - element: rhs, - oldFirst: oldFirst - ) - ] - } - - return changes } } diff --git a/Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceChangeConsolidator.swift b/Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceChangeConsolidator.swift index c931952..3c0c317 100644 --- a/Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceChangeConsolidator.swift +++ b/Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceChangeConsolidator.swift @@ -67,15 +67,11 @@ struct SwiftInterfaceChangeConsolidator: SwiftInterfaceChangeConsolidating { /// Compiles a list of changes between 2 independent changes func listOfChanges(between lhs: IndependentSwiftInterfaceChange, and rhs: IndependentSwiftInterfaceChange) -> [String] { - return [String]() - // TODO: Enable again - /* if lhs.oldFirst { - lhs.element.differences(to: rhs.element) + rhs.differences(to: lhs) } else { - rhs.element.differences(to: lhs.element) + lhs.differences(to: rhs) } - */ } } diff --git a/Sources/Pipeline/Modules/SwiftInterfaceParser/SwiftInterfaceParser.swift b/Sources/Pipeline/Modules/SwiftInterfaceParser/SwiftInterfaceParser.swift index 42eb95d..0fd02b1 100644 --- a/Sources/Pipeline/Modules/SwiftInterfaceParser/SwiftInterfaceParser.swift +++ b/Sources/Pipeline/Modules/SwiftInterfaceParser/SwiftInterfaceParser.swift @@ -9,7 +9,7 @@ import SwiftParser */ class SwiftInterfaceParser: SyntaxVisitor { - class Root: SwiftInterfaceElement, Equatable { + class Root: SwiftInterfaceElement { var parent: (any SwiftInterfaceElement)? = nil @@ -26,13 +26,20 @@ class SwiftInterfaceParser: SyntaxVisitor { return description } - var childGroupName: String { "Root" } + var childGroupName: String { moduleName } + private let moduleName: String let children: [any SwiftInterfaceElement] - init(elements: [any SwiftInterfaceElement]) { - elements.forEach { $0.setupParentRelationships() } + init(moduleName: String, elements: [any SwiftInterfaceElement]) { + self.moduleName = moduleName self.children = elements + + elements.forEach { $0.setupParentRelationships(parent: self) } + } + + func differences(to otherElement: T) -> [String] { + return [] } } @@ -45,10 +52,13 @@ class SwiftInterfaceParser: SyntaxVisitor { private var scope: Scope = .root(elements: []) - static public func parse(source: String) -> Root { + static public func parse(source: String, moduleName: String) -> Root { let visitor = Self() visitor.walk(Parser.parse(source: source)) - return Root(elements: visitor.scope.elements) + return Root( + moduleName: moduleName, + elements: visitor.scope.elements + ) } /// Designated initializer diff --git a/Tests/IntegrationTests/ReferencePackageTests.swift b/Tests/IntegrationTests/ReferencePackageTests.swift index 3016eaf..4a4fdec 100644 --- a/Tests/IntegrationTests/ReferencePackageTests.swift +++ b/Tests/IntegrationTests/ReferencePackageTests.swift @@ -8,9 +8,65 @@ import XCTest class ReferencePackageTests: XCTestCase { + + func test_swiftInterface() throws { + + // TODO: Build + use the pipeline + + // Public interface + + try test(swiftInterface: .public) + + // @_spi interface + + try test(swiftInterface: .private) + } +} + +private extension ReferencePackageTests { - func test_defaultPipeline() async throws { + enum InterfaceType { + case `public` + case `private` + + var expectedOutputFileName: String { + switch self { + case .public: + "expected-reference-changes-swift-interface-public" + case .private: + "expected-reference-changes-swift-interface-private" + } + } + var interfaceFilePath: String { + switch self { + case .public: + "_build/Build/Products/Debug-iphoneos/ReferencePackage.swiftmodule/arm64-apple-ios.swiftinterface" + case .private: + "_build/Build/Products/Debug-iphoneos/ReferencePackage.swiftmodule/arm64-apple-ios.private.swiftinterface" + } + } + } + + func expectedOutput(for source: InterfaceType) throws -> String { + let expectedOutputFilePath = try XCTUnwrap(Bundle.module.path(forResource: source.expectedOutputFileName, ofType: "md")) + let expectedOutputData = try XCTUnwrap(FileManager.default.contents(atPath: expectedOutputFilePath)) + return try XCTUnwrap(String(data: expectedOutputData, encoding: .utf8)) + } + + func swiftInterfaceContent(referencePackagesRoot: URL, packageName: String, interfaceType: InterfaceType) throws-> String { + let oldReferencePackageDirectory = referencePackagesRoot.appending(path: packageName) + let interfaceFilePath = try XCTUnwrap(oldReferencePackageDirectory.appending(path: interfaceType.interfaceFilePath)) + let interfaceFileContent = try XCTUnwrap(FileManager.default.contents(atPath: interfaceFilePath.path())) + return try XCTUnwrap(String(data: interfaceFileContent, encoding: .utf8)) + } + + func content(atPath path: String) throws -> String { + let interfaceFileContent = try XCTUnwrap(FileManager.default.contents(atPath: path)) + return try XCTUnwrap(String(data: interfaceFileContent, encoding: .utf8)) + } + + func test(swiftInterface interface: InterfaceType) throws { // Unfortunately we can't use packages as Test Resources, so we put it in a `ReferencePackages` directory on root guard let projectRoot = #file.replacingOccurrences(of: "relatve/path/to/file", with: "").split(separator: "/Tests/").first else { XCTFail("Cannot find root directory") @@ -19,45 +75,52 @@ class ReferencePackageTests: XCTestCase { let referencePackagesRoot = URL(filePath: String(projectRoot)).appending(path: "ReferencePackages") - let oldReferencePackageDirectory = referencePackagesRoot.appending(path: "ReferencePackage") - let newReferencePackageDirectory = referencePackagesRoot.appending(path: "UpdatedPackage") + let expectedOutput = try expectedOutput(for: interface) - let expectedOutput: String = try { - let expectedOutputFilePath = try XCTUnwrap(Bundle.module.path(forResource: "expected-reference-changes", ofType: "md")) - let expectedOutputData = try XCTUnwrap(FileManager.default.contents(atPath: expectedOutputFilePath)) - return try XCTUnwrap(String(data: expectedOutputData, encoding: .utf8)) - }() + let oldSourceContent = try swiftInterfaceContent( + referencePackagesRoot: referencePackagesRoot, + packageName: "ReferencePackage", + interfaceType: interface + ) - let fileHandler: FileHandling = FileManager.default - let logger: any Logging = PipelineLogger(logLevel: .debug) + let newSourceContent = try swiftInterfaceContent( + referencePackagesRoot: referencePackagesRoot, + packageName: "UpdatedPackage", + interfaceType: interface + ) - let currentDirectory = fileHandler.currentDirectoryPath - let workingDirectoryPath = currentDirectory.appending("/tmp-public-api-diff") + /* + let oldSourceContent = try content(atPath: "/Users/alexandergu/Downloads/AdyenPOS.xcframework/ios-arm64_x86_64-simulator/AdyenPOS.framework/Modules/AdyenPOS.swiftmodule/arm64-apple-ios-simulator.swiftinterface") + let newSourceContent = try content(atPath: "/Users/alexandergu/Downloads/AdyenPOS/AdyenPOS_3.2.0.xcframework/ios-arm64_x86_64-simulator/AdyenPOS.framework/Modules/AdyenPOS.swiftmodule/arm64-apple-ios-simulator.swiftinterface") + */ - let pipelineOutput = try await Pipeline.run( - newSource: .local(path: newReferencePackageDirectory.path()), - oldSource: .local(path: oldReferencePackageDirectory.path()), - scheme: nil, - workingDirectoryPath: workingDirectoryPath, - fileHandler: fileHandler, - logger: logger + let oldInterface = SwiftInterfaceParser.parse(source: oldSourceContent, moduleName: "ReferencePackage") + let newInterface = SwiftInterfaceParser.parse(source: newSourceContent, moduleName: "ReferencePackage") + + let analyzer = SwiftInterfaceAnalyzer() + + let changes = analyzer.analyze(old: oldInterface, new: newInterface) + + let markdownOutput = MarkdownOutputGenerator().generate( + from: ["ReferencePackage": changes], + allTargets: ["ReferencePackage"], + oldSource: .local(path: "AdyenPOS 2.2.2"), + newSource: .local(path: "AdyenPOS 3.2.0"), + warnings: [] ) - let expectedLines = sanitizeOutput(expectedOutput).components(separatedBy: "\n") - let pipelineOutputLines = sanitizeOutput(pipelineOutput).components(separatedBy: "\n") + print(markdownOutput) - print(pipelineOutput) + let expectedLines = sanitizeOutput(expectedOutput).components(separatedBy: "\n") + let markdownOutputLines = sanitizeOutput(markdownOutput).components(separatedBy: "\n") for i in 0.. String { diff --git a/Tests/IntegrationTests/Resources/expected-reference-changes-sdk-dump.md b/Tests/IntegrationTests/Resources/expected-reference-changes-sdk-dump.md new file mode 100644 index 0000000..63c311c --- /dev/null +++ b/Tests/IntegrationTests/Resources/expected-reference-changes-sdk-dump.md @@ -0,0 +1,264 @@ +# πŸ‘€ 48 public changes detected +_Comparing `/.../.../UpdatedPackage` to `/.../.../ReferencePackage`_ + +--- +## `ReferencePackage` +#### ❇️ Added +```javascript +public enum RawValueEnum: Swift.String +{ + case one + case two + public init?(rawValue: Swift.String) + public typealias RawValue = Swift.String + public var rawValue: Swift.String { get } +} +``` +```javascript +public protocol ParentProtocol +{ + associatedtype ParentType: Swift.Equatable where Self.ParentType == Self.Iterator.Element + associatedtype Iterator: Swift.Collection +} +``` +```javascript +public protocol ParentProtocol +{ + associatedtype ParentType: Swift.Equatable where Self.ParentType == Self.Iterator.Element + associatedtype Iterator: Swift.Collection +} +``` +```javascript +public protocol SimpleProtocol +``` +#### πŸ”€ Changed +```javascript +// From +@_hasMissingDesignatedInitializers public actor CustomActor + +// To +@_hasMissingDesignatedInitializers public actor CustomActor: ReferencePackage.SimpleProtocol +``` +```javascript +// From +public enum CustomEnum + +// To +public enum CustomEnum +``` +```javascript +// From +public protocol CustomProtocol + +// To +public protocol CustomProtocol: ReferencePackage.ParentProtocol where Self.ParentType == Swift.Double +``` +```javascript +// From +public struct CustomStruct: ReferencePackage.CustomProtocol + +// To +public struct CustomStruct: ReferencePackage.CustomProtocol where T : Swift.Strideable +``` +### `CustomClass` +#### ❇️ Added +```javascript +final public let a: Swift.Int +``` +```javascript +final public let b: Swift.Int +``` +```javascript +final public let c: Swift.Int +``` +```javascript +final public let d: Swift.Double +``` +```javascript +public subscript(index: Swift.Int) -> T? { get set } +``` +```javascript +public var lazyVar: Swift.String { get set } +``` +#### πŸ”€ Changed +```javascript +// From +@_Concurrency.MainActor public func asyncThrowingFunc() async throws -> Swift.Void + +// To +@_Concurrency.MainActor public func asyncThrowingFunc(_ element: Element) async throws -> Swift.Void where Element : Swift.Strideable +``` +```javascript +// From +convenience public init(value: T) + +// To +convenience public init!(value: T) +``` +```javascript +// From +public init() + +// To +public init?() +``` +### `CustomEnum` +#### ❇️ Added +```javascript +case a +``` +```javascript +case b +``` +```javascript +case c +``` +```javascript +case caseWithNamedString(title: T) +``` +```javascript +case d +``` +```javascript +case e(ReferencePackage.CustomEnum.NestedStructInExtension) +``` +```javascript +extension ReferencePackage.CustomEnum where T == Swift.String +{ + public var titleOfCaseWithNamedString: Swift.String? { get } +} +``` +```javascript +extension ReferencePackage.CustomEnum: ReferencePackage.SimpleProtocol +{ + public struct NestedStructInExtension + { + public let string: Swift.String + public init(string: Swift.String = "Hello") + } +} +``` +#### πŸ”€ Changed +```javascript +// From +case caseWithTuple(Swift.String, Swift.Int) + +// To +case caseWithTuple(_: Swift.String, bar: Swift.Int) +``` +```javascript +// From +indirect case recursive(ReferencePackage.CustomEnum) + +// To +indirect case recursive(ReferencePackage.CustomEnum) +``` +#### πŸ˜Άβ€πŸŒ«οΈ Removed +```javascript +case caseWithString(Swift.String) +``` +### `CustomProtocol` +#### ❇️ Added +```javascript +associatedtype AnotherAssociatedType: Swift.Strideable +``` +```javascript +associatedtype AnotherAssociatedType: Swift.Strideable +``` +```javascript +associatedtype CustomAssociatedType: Swift.Equatable +``` +```javascript +associatedtype CustomAssociatedType: Swift.Equatable +``` +#### πŸ”€ Changed +```javascript +// From +func function() -> any Swift.Equatable + +// To +func function() -> Self.CustomAssociatedType +``` +```javascript +// From +var getSetVar: any Swift.Equatable { get set } + +// To +var getSetVar: Self.AnotherAssociatedType { get set } +``` +```javascript +// From +var getVar: any Swift.Equatable { get } + +// To +var getVar: Self.CustomAssociatedType { get } +``` +#### πŸ˜Άβ€πŸŒ«οΈ Removed +```javascript +typealias CustomAssociatedType = Swift.Equatable +``` +### `CustomStruct` +#### ❇️ Added +```javascript +@available(macOS, unavailable, message: "Unavailable on macOS") public struct NestedStruct +{ + @available(*, deprecated, renamed: "nestedVar") public let nestedLet: Swift.String + @available(swift 5.9) public let nestedVar: Swift.String +} +``` +```javascript +public typealias AnotherAssociatedType = Swift.Double +``` +```javascript +public typealias CustomAssociatedType = Swift.Int +``` +```javascript +public typealias Iterator = Swift.Array.AnotherAssociatedType> +``` +```javascript +public typealias ParentType = Swift.Double +``` +#### πŸ”€ Changed +```javascript +// From +@discardableResult public func function() -> any Swift.Equatable + +// To +@discardableResult public func function() -> Swift.Int +``` +```javascript +// From +public var getSetVar: any Swift.Equatable + +// To +public var getSetVar: Swift.Double +``` +```javascript +// From +public var getVar: any Swift.Equatable + +// To +public var getVar: Swift.Int +``` +### `RawValueEnum` +#### ❇️ Added +```javascript +extension ReferencePackage.RawValueEnum: Swift.Equatable +``` +```javascript +extension ReferencePackage.RawValueEnum: Swift.Hashable +``` +```javascript +extension ReferencePackage.RawValueEnum: Swift.RawRepresentable +``` +### `Swift.Array` +#### ❇️ Added +```javascript +extension Swift.Array +{ + public subscript(safe index: Swift.Int) -> Element? { get } +} +``` + +--- +**Analyzed targets:** ReferencePackage diff --git a/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-private.md b/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-private.md new file mode 100644 index 0000000..0becb5f --- /dev/null +++ b/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-private.md @@ -0,0 +1,319 @@ +# πŸ‘€ 57 public changes detected +_Comparing `/.../.../UpdatedPackage` to `/.../.../ReferencePackage`_ + +--- +## `ReferencePackage` +### `ReferencePackage` +#### ❇️ Added +```javascript +public enum RawValueEnum: Swift.String +{ + case one + case two + public init?(rawValue: Swift.String) + public typealias RawValue = Swift.String + public var rawValue: Swift.String { get } +} +``` +```javascript +public protocol ParentProtocol +{ + associatedtype ParentType: Swift.Equatable where Self.ParentType == Self.Iterator.Element + associatedtype Iterator: Swift.Collection +} +``` +```javascript +public protocol ParentProtocol +{ + associatedtype ParentType: Swift.Equatable where Self.ParentType == Self.Iterator.Element + associatedtype Iterator: Swift.Collection +} +``` +```javascript +public protocol SimpleProtocol +``` +#### πŸ”€ Changed +```javascript +// From +@_hasMissingDesignatedInitializers public actor CustomActor + +// To +@_hasMissingDesignatedInitializers public actor CustomActor: ReferencePackage.SimpleProtocol +``` +```javascript +// From +@_spi(SystemProgrammingInterface) open class OpenSpiConformingClass: ReferencePackage.CustomProtocol + +// To +@_spi(SystemProgrammingInterface) open class OpenSpiConformingClass: ReferencePackage.CustomProtocol where T : Swift.Strideable +``` +```javascript +// From +public enum CustomEnum + +// To +public enum CustomEnum +``` +```javascript +// From +public protocol CustomProtocol + +// To +public protocol CustomProtocol: ReferencePackage.ParentProtocol where Self.ParentType == Swift.Double +``` +```javascript +// From +public struct CustomStruct: ReferencePackage.CustomProtocol + +// To +public struct CustomStruct: ReferencePackage.CustomProtocol where T : Swift.Strideable +``` +### `ReferencePackage.CustomClass` +#### ❇️ Added +```javascript +final public let a: Swift.Int +``` +```javascript +final public let b: Swift.Int +``` +```javascript +final public let c: Swift.Int +``` +```javascript +final public let d: Swift.Double +``` +```javascript +public subscript(index: Swift.Int) -> T? { get set } +``` +```javascript +public var lazyVar: Swift.String { get set } +``` +#### πŸ”€ Changed +```javascript +// From +@_Concurrency.MainActor public func asyncThrowingFunc() async throws -> Swift.Void + +// To +@_Concurrency.MainActor public func asyncThrowingFunc(_ element: Element) async throws -> Swift.Void where Element : Swift.Strideable +``` +```javascript +// From +convenience public init(value: T) + +// To +convenience public init!(value: T) +``` +```javascript +// From +public init() + +// To +public init?() +``` +### `ReferencePackage.CustomEnum` +#### ❇️ Added +```javascript +case a +``` +```javascript +case b +``` +```javascript +case c +``` +```javascript +case caseWithNamedString(title: T) +``` +```javascript +case d +``` +```javascript +case e(ReferencePackage.CustomEnum.NestedStructInExtension) +``` +```javascript +extension ReferencePackage.CustomEnum where T == Swift.String +{ + public var titleOfCaseWithNamedString: Swift.String? { get } +} +``` +```javascript +extension ReferencePackage.CustomEnum: ReferencePackage.SimpleProtocol +{ + public struct NestedStructInExtension + { + public let string: Swift.String + public init(string: Swift.String = "Hello") + } +} +``` +#### πŸ”€ Changed +```javascript +// From +case caseWithTuple(Swift.String, Swift.Int) + +// To +case caseWithTuple(_: Swift.String, bar: Swift.Int) +``` +```javascript +// From +indirect case recursive(ReferencePackage.CustomEnum) + +// To +indirect case recursive(ReferencePackage.CustomEnum) +``` +#### πŸ˜Άβ€πŸŒ«οΈ Removed +```javascript +case caseWithString(Swift.String) +``` +### `ReferencePackage.CustomProtocol` +#### ❇️ Added +```javascript +associatedtype AnotherAssociatedType: Swift.Strideable +``` +```javascript +associatedtype AnotherAssociatedType: Swift.Strideable +``` +```javascript +associatedtype CustomAssociatedType: Swift.Equatable +``` +```javascript +associatedtype CustomAssociatedType: Swift.Equatable +``` +#### πŸ”€ Changed +```javascript +// From +func function() -> any Swift.Equatable + +// To +func function() -> Self.CustomAssociatedType +``` +```javascript +// From +var getSetVar: any Swift.Equatable { get set } + +// To +var getSetVar: Self.AnotherAssociatedType { get set } +``` +```javascript +// From +var getVar: any Swift.Equatable { get } + +// To +var getVar: Self.CustomAssociatedType { get } +``` +#### πŸ˜Άβ€πŸŒ«οΈ Removed +```javascript +typealias CustomAssociatedType = Swift.Equatable +``` +### `ReferencePackage.CustomStruct` +#### ❇️ Added +```javascript +@available(macOS, unavailable, message: "Unavailable on macOS") public struct NestedStruct +{ + @available(*, deprecated, renamed: "nestedVar") public let nestedLet: Swift.String + @available(swift 5.9) public let nestedVar: Swift.String +} +``` +```javascript +public typealias AnotherAssociatedType = Swift.Double +``` +```javascript +public typealias CustomAssociatedType = Swift.Int +``` +```javascript +public typealias Iterator = Swift.Array.AnotherAssociatedType> +``` +```javascript +public typealias ParentType = Swift.Double +``` +#### πŸ”€ Changed +```javascript +// From +@discardableResult public func function() -> any Swift.Equatable + +// To +@discardableResult public func function() -> Swift.Int +``` +```javascript +// From +public var getSetVar: any Swift.Equatable + +// To +public var getSetVar: Swift.Double +``` +```javascript +// From +public var getVar: any Swift.Equatable + +// To +public var getVar: Swift.Int +``` +### `ReferencePackage.OpenSpiConformingClass` +#### ❇️ Added +```javascript +@_spi(SystemProgrammingInterface) public typealias AnotherAssociatedType = T +``` +```javascript +@_spi(SystemProgrammingInterface) public typealias Iterator = Swift.Array +``` +```javascript +@_spi(SystemProgrammingInterface) public typealias ParentType = Swift.Double +``` +#### πŸ”€ Changed +```javascript +// From +@_spi(SystemProgrammingInterface) @inlinable public func function() -> ReferencePackage.OpenSpiConformingClass.CustomAssociatedType + +// To +@_spi(SystemProgrammingInterface) @inlinable public func function() -> T +``` +```javascript +// From +@_spi(SystemProgrammingInterface) public init(getSetVar: ReferencePackage.OpenSpiConformingClass.CustomAssociatedType, getVar: ReferencePackage.OpenSpiConformingClass.CustomAssociatedType) + +// To +@_spi(SystemProgrammingInterface) public init(getSetVar: T, getVar: T) +``` +```javascript +// From +@_spi(SystemProgrammingInterface) public typealias CustomAssociatedType = any Swift.Equatable + +// To +@_spi(SystemProgrammingInterface) public typealias CustomAssociatedType = T +``` +```javascript +// From +@_spi(SystemProgrammingInterface) public var getSetVar: ReferencePackage.OpenSpiConformingClass.CustomAssociatedType + +// To +@_spi(SystemProgrammingInterface) public var getSetVar: T +``` +```javascript +// From +@_spi(SystemProgrammingInterface) public var getVar: ReferencePackage.OpenSpiConformingClass.CustomAssociatedType + +// To +@_spi(SystemProgrammingInterface) public var getVar: T +``` +### `ReferencePackage.RawValueEnum` +#### ❇️ Added +```javascript +extension ReferencePackage.RawValueEnum: Swift.Equatable +``` +```javascript +extension ReferencePackage.RawValueEnum: Swift.Hashable +``` +```javascript +extension ReferencePackage.RawValueEnum: Swift.RawRepresentable +``` +### `Swift.Array` +#### ❇️ Added +```javascript +extension Swift.Array +{ + public subscript(safe index: Swift.Int) -> Element? { get } +} +``` + +--- +**Analyzed targets:** ReferencePackage diff --git a/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-public.md b/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-public.md new file mode 100644 index 0000000..c2bcd47 --- /dev/null +++ b/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-public.md @@ -0,0 +1,265 @@ +# πŸ‘€ 48 public changes detected +_Comparing `/.../.../UpdatedPackage` to `/.../.../ReferencePackage`_ + +--- +## `ReferencePackage` +### `ReferencePackage` +#### ❇️ Added +```javascript +public enum RawValueEnum: Swift.String +{ + case one + case two + public init?(rawValue: Swift.String) + public typealias RawValue = Swift.String + public var rawValue: Swift.String { get } +} +``` +```javascript +public protocol ParentProtocol +{ + associatedtype ParentType: Swift.Equatable where Self.ParentType == Self.Iterator.Element + associatedtype Iterator: Swift.Collection +} +``` +```javascript +public protocol ParentProtocol +{ + associatedtype ParentType: Swift.Equatable where Self.ParentType == Self.Iterator.Element + associatedtype Iterator: Swift.Collection +} +``` +```javascript +public protocol SimpleProtocol +``` +#### πŸ”€ Changed +```javascript +// From +@_hasMissingDesignatedInitializers public actor CustomActor + +// To +@_hasMissingDesignatedInitializers public actor CustomActor: ReferencePackage.SimpleProtocol +``` +```javascript +// From +public enum CustomEnum + +// To +public enum CustomEnum +``` +```javascript +// From +public protocol CustomProtocol + +// To +public protocol CustomProtocol: ReferencePackage.ParentProtocol where Self.ParentType == Swift.Double +``` +```javascript +// From +public struct CustomStruct: ReferencePackage.CustomProtocol + +// To +public struct CustomStruct: ReferencePackage.CustomProtocol where T : Swift.Strideable +``` +### `ReferencePackage.CustomClass` +#### ❇️ Added +```javascript +final public let a: Swift.Int +``` +```javascript +final public let b: Swift.Int +``` +```javascript +final public let c: Swift.Int +``` +```javascript +final public let d: Swift.Double +``` +```javascript +public subscript(index: Swift.Int) -> T? { get set } +``` +```javascript +public var lazyVar: Swift.String { get set } +``` +#### πŸ”€ Changed +```javascript +// From +@_Concurrency.MainActor public func asyncThrowingFunc() async throws -> Swift.Void + +// To +@_Concurrency.MainActor public func asyncThrowingFunc(_ element: Element) async throws -> Swift.Void where Element : Swift.Strideable +``` +```javascript +// From +convenience public init(value: T) + +// To +convenience public init!(value: T) +``` +```javascript +// From +public init() + +// To +public init?() +``` +### `ReferencePackage.CustomEnum` +#### ❇️ Added +```javascript +case a +``` +```javascript +case b +``` +```javascript +case c +``` +```javascript +case caseWithNamedString(title: T) +``` +```javascript +case d +``` +```javascript +case e(ReferencePackage.CustomEnum.NestedStructInExtension) +``` +```javascript +extension ReferencePackage.CustomEnum where T == Swift.String +{ + public var titleOfCaseWithNamedString: Swift.String? { get } +} +``` +```javascript +extension ReferencePackage.CustomEnum: ReferencePackage.SimpleProtocol +{ + public struct NestedStructInExtension + { + public let string: Swift.String + public init(string: Swift.String = "Hello") + } +} +``` +#### πŸ”€ Changed +```javascript +// From +case caseWithTuple(Swift.String, Swift.Int) + +// To +case caseWithTuple(_: Swift.String, bar: Swift.Int) +``` +```javascript +// From +indirect case recursive(ReferencePackage.CustomEnum) + +// To +indirect case recursive(ReferencePackage.CustomEnum) +``` +#### πŸ˜Άβ€πŸŒ«οΈ Removed +```javascript +case caseWithString(Swift.String) +``` +### `ReferencePackage.CustomProtocol` +#### ❇️ Added +```javascript +associatedtype AnotherAssociatedType: Swift.Strideable +``` +```javascript +associatedtype AnotherAssociatedType: Swift.Strideable +``` +```javascript +associatedtype CustomAssociatedType: Swift.Equatable +``` +```javascript +associatedtype CustomAssociatedType: Swift.Equatable +``` +#### πŸ”€ Changed +```javascript +// From +func function() -> any Swift.Equatable + +// To +func function() -> Self.CustomAssociatedType +``` +```javascript +// From +var getSetVar: any Swift.Equatable { get set } + +// To +var getSetVar: Self.AnotherAssociatedType { get set } +``` +```javascript +// From +var getVar: any Swift.Equatable { get } + +// To +var getVar: Self.CustomAssociatedType { get } +``` +#### πŸ˜Άβ€πŸŒ«οΈ Removed +```javascript +typealias CustomAssociatedType = Swift.Equatable +``` +### `ReferencePackage.CustomStruct` +#### ❇️ Added +```javascript +@available(macOS, unavailable, message: "Unavailable on macOS") public struct NestedStruct +{ + @available(*, deprecated, renamed: "nestedVar") public let nestedLet: Swift.String + @available(swift 5.9) public let nestedVar: Swift.String +} +``` +```javascript +public typealias AnotherAssociatedType = Swift.Double +``` +```javascript +public typealias CustomAssociatedType = Swift.Int +``` +```javascript +public typealias Iterator = Swift.Array.AnotherAssociatedType> +``` +```javascript +public typealias ParentType = Swift.Double +``` +#### πŸ”€ Changed +```javascript +// From +@discardableResult public func function() -> any Swift.Equatable + +// To +@discardableResult public func function() -> Swift.Int +``` +```javascript +// From +public var getSetVar: any Swift.Equatable + +// To +public var getSetVar: Swift.Double +``` +```javascript +// From +public var getVar: any Swift.Equatable + +// To +public var getVar: Swift.Int +``` +### `ReferencePackage.RawValueEnum` +#### ❇️ Added +```javascript +extension ReferencePackage.RawValueEnum: Swift.Equatable +``` +```javascript +extension ReferencePackage.RawValueEnum: Swift.Hashable +``` +```javascript +extension ReferencePackage.RawValueEnum: Swift.RawRepresentable +``` +### `Swift.Array` +#### ❇️ Added +```javascript +extension Swift.Array +{ + public subscript(safe index: Swift.Int) -> Element? { get } +} +``` + +--- +**Analyzed targets:** ReferencePackage diff --git a/Tests/IntegrationTests/Resources/expected-reference-changes.md b/Tests/IntegrationTests/Resources/expected-reference-changes.md deleted file mode 100644 index cccf9ee..0000000 --- a/Tests/IntegrationTests/Resources/expected-reference-changes.md +++ /dev/null @@ -1,96 +0,0 @@ -# πŸ‘€ 11 public changes detected -_Comparing `/.../.../UpdatedPackage` to `/.../.../ReferencePackage`_ - ---- -## `ReferencePackage` -#### πŸ”€ Changed -```javascript -// From -public protocol CustomProtocol - -// To -public protocol CustomProtocol - -/** -Changes: -- Added generic signature `` -*/ -``` -```javascript -// From -public struct CustomStruct : CustomProtocol - -// To -public struct CustomStruct : CustomProtocol - -/** -Changes: -- Added generic signature `` -*/ -``` -### `CustomProtocol` -#### ❇️ Added -```javascript -public associatedtype CustomAssociatedType -``` -#### πŸ”€ Changed -```javascript -// From -public func function() -> any Self.CustomAssociatedType - -// To -public func function() -> Self.CustomAssociatedType -``` -```javascript -// From -public var getSetVar: any Self.CustomAssociatedType { get set } - -// To -public var getSetVar: Self.CustomAssociatedType { get set } -``` -```javascript -// From -public var getVar: any Self.CustomAssociatedType { get } - -// To -public var getVar: Self.CustomAssociatedType { get } -``` -#### πŸ˜Άβ€πŸŒ«οΈ Removed -```javascript -public typealias CustomAssociatedType = Swift.Equatable -``` -### `CustomStruct` -#### ❇️ Added -```javascript -public typealias CustomAssociatedType = Swift.Int -``` -#### πŸ”€ Changed -```javascript -// From -@discardableResult public func function() -> any Swift.Equatable - -// To -@discardableResult public func function() -> Swift.Int - -/** -Changes: -- Added generic signature `` -*/ -``` -```javascript -// From -public var getSetVar: any Swift.Equatable { get set } - -// To -public var getSetVar: Swift.Int { get set } -``` -```javascript -// From -public var getVar: any Swift.Equatable { get set } - -// To -public var getVar: Swift.Int { get set } -``` - ---- -**Analyzed targets:** ReferencePackage diff --git a/Tests/UnitTests/SwiftInterfaceTests.swift b/Tests/UnitTests/SwiftInterfaceTests.swift deleted file mode 100644 index fafa5a0..0000000 --- a/Tests/UnitTests/SwiftInterfaceTests.swift +++ /dev/null @@ -1,93 +0,0 @@ -// -// File.swift -// -// -// Created by Alexander Guretzki on 16/09/2024. -// - -@testable import public_api_diff -import XCTest - -class SwiftInterfaceTests: XCTestCase { - - func test_swiftinterface() throws { - - // Unfortunately we can't use packages as Test Resources, so we put it in a `ReferencePackages` directory on root - guard let projectRoot = #file.replacingOccurrences(of: "relatve/path/to/file", with: "").split(separator: "/Tests/").first else { - XCTFail("Cannot find root directory") - return - } - - let referencePackagesRoot = URL(filePath: String(projectRoot)).appending(path: "ReferencePackages") - - let expectedOutput: String = try { - let expectedOutputFilePath = try XCTUnwrap(Bundle.module.path(forResource: "expected-reference-changes", ofType: "md")) - let expectedOutputData = try XCTUnwrap(FileManager.default.contents(atPath: expectedOutputFilePath)) - return try XCTUnwrap(String(data: expectedOutputData, encoding: .utf8)) - }() - - let oldSource: String = try { - - let oldReferencePackageDirectory = referencePackagesRoot.appending(path: "ReferencePackage") - let interfaceFilePath = try XCTUnwrap(oldReferencePackageDirectory.appending(path: "_build/Build/Products/Debug-iphoneos/ReferencePackage.swiftmodule/arm64-apple-ios.private.swiftinterface")) - let interfaceFileContent = try XCTUnwrap(FileManager.default.contents(atPath: interfaceFilePath.path())) - return try XCTUnwrap(String(data: interfaceFileContent, encoding: .utf8)) - }() - - let newSource: String = try { - let newReferencePackageDirectory = referencePackagesRoot.appending(path: "UpdatedPackage") - let interfaceFilePath = try XCTUnwrap(newReferencePackageDirectory.appending(path: "_build/Build/Products/Debug-iphoneos/ReferencePackage.swiftmodule/arm64-apple-ios.private.swiftinterface")) - let interfaceFileContent = try XCTUnwrap(FileManager.default.contents(atPath: interfaceFilePath.path())) - return try XCTUnwrap(String(data: interfaceFileContent, encoding: .utf8)) - }() - - let oldInterface = SwiftInterfaceParser.parse(source: oldSource) - let newInterface = SwiftInterfaceParser.parse(source: newSource) - - let analyzer = SwiftInterfaceAnalyzer() - - if oldInterface != newInterface { - let changes = analyzer.analyze(old: oldInterface, new: newInterface) - let output = MarkdownOutputGenerator().generate( - from: ["": changes], - allTargets: ["Target"], - oldSource: .local(path: "old"), - newSource: .local(path: "new"), - warnings: [] - ) - print(output) - } - - /* - let oldRoot = SDKDump( - root: .init( - kind: .root, - name: "TopLevel", - printedName: "TopLevel", - children: SwiftInterfaceVisitor.parse(source: oldSource) - ) - ) - - let newRoot = SDKDump( - root: .init( - kind: .root, - name: "TopLevel", - printedName: "TopLevel", - children: SwiftInterfaceVisitor.parse(source: newSource) - ) - ) - - let changes = SDKDumpAnalyzer().analyze(old: oldRoot, new: newRoot) - - let markdownOutput = MarkdownOutputGenerator().generate( - from: ["ReferencePackage": changes], - allTargets: ["ReferencePackage"], - oldSource: .local(path: "/.../.../ReferencePackage"), - newSource: .local(path: "/.../.../UpdatedPackage"), - warnings: [] - ) - - XCTAssertEqual(markdownOutput, expectedOutput) - */ - } -} diff --git a/Tests/public-api-diff.xctestplan b/Tests/public-api-diff.xctestplan index 6c20474..2d9ac7c 100644 --- a/Tests/public-api-diff.xctestplan +++ b/Tests/public-api-diff.xctestplan @@ -45,7 +45,6 @@ }, "testTargets" : [ { - "enabled" : false, "target" : { "containerPath" : "container:", "identifier" : "IntegrationTests", @@ -53,6 +52,7 @@ } }, { + "enabled" : false, "skippedTests" : [ "ABIGeneratorTests", "FileHandlingTests", From a51691fa851807a213d68c3004e415f35b0f6dda Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Fri, 4 Oct 2024 19:13:02 +0200 Subject: [PATCH 05/45] Wrapping up initial version of .swiftinterface --- .../SwiftInterfaceElement+Actor.swift | 3 +- ...SwiftInterfaceElement+AssociatedType.swift | 3 +- .../SwiftInterfaceElement+Class.swift | 3 +- .../SwiftInterfaceElement+Enum.swift | 3 +- .../SwiftInterfaceElement+EnumCase.swift | 2 +- .../SwiftInterfaceElement+Extension.swift | 2 +- .../SwiftInterfaceElement+Function.swift | 3 +- .../SwiftInterfaceElement+Initializer.swift | 2 +- .../SwiftInterfaceElement+Protocol.swift | 4 +- .../SwiftInterfaceElement+Struct.swift | 3 +- .../SwiftInterfaceElement+Subscript.swift | 3 +- .../SwiftInterfaceElement+TypeAlias.swift | 3 +- .../SwiftInterfaceElement+Var.swift | 3 +- .../SwiftInterfaceElement.swift | 28 +++- Sources/Helpers/XcodeTools.swift | 36 +++- .../Modules/ABIGenerator/ABIGenerator.swift | 2 +- .../ABIGenerator/ProjectABIProvider.swift | 5 - Sources/Pipeline/Modules/ProjectBuilder.swift | 3 +- .../Pipeline/Modules/ProjectSetupHelper.swift | 77 +++++++++ .../SDKDumpAnalyzer/SDKDumpAnalyzer.swift | 7 - .../SwiftInterfaceAnalyzer.swift | 30 ++-- .../SwiftInterfaceChangeConsolidator.swift | 6 +- .../Modules/SwiftInterfaceFileLocator.swift | 44 +++++ .../SwiftInterfaceParser.swift | 4 +- .../Modules/SwiftPackageFileAnalyzer.swift | 5 +- Sources/Pipeline/Pipeline+Protocols.swift | 17 ++ .../{Pipeline.swift => SDKDumpPipeline.swift} | 4 +- Sources/Pipeline/SwiftInterfacePipeline.swift | 61 +++++++ Sources/public-api-diff.swift | 155 ++++++++++++++++-- .../ReferencePackageTests.swift | 137 ++++++++-------- Tests/UnitTests/PipelineTests.swift | 2 +- 31 files changed, 524 insertions(+), 136 deletions(-) create mode 100644 Sources/Pipeline/Modules/ProjectSetupHelper.swift create mode 100644 Sources/Pipeline/Modules/SwiftInterfaceFileLocator.swift rename Sources/Pipeline/{Pipeline.swift => SDKDumpPipeline.swift} (99%) create mode 100644 Sources/Pipeline/SwiftInterfacePipeline.swift diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Actor.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Actor.swift index 50302ac..e41e27d 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Actor.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Actor.swift @@ -20,8 +20,7 @@ class SwiftInterfaceActor: SwiftInterfaceElement { /// e.g. where T : Equatable let genericWhereClauseDescription: String? - /// The members, declarations, ... inside of the body of the struct - let children: [any SwiftInterfaceElement] + var children: [any SwiftInterfaceElement] var parent: (any SwiftInterfaceElement)? = nil diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+AssociatedType.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+AssociatedType.swift index 40976a7..89d832f 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+AssociatedType.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+AssociatedType.swift @@ -20,8 +20,7 @@ class SwiftInterfaceAssociatedType: SwiftInterfaceElement { var childGroupName: String { "" } // Not relevant as only used to group children - /// A associatedtype does not have children - let children: [any SwiftInterfaceElement] = [] + var children: [any SwiftInterfaceElement] = [] var parent: (any SwiftInterfaceElement)? = nil diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Class.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Class.swift index 7ea4452..3b587b4 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Class.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Class.swift @@ -20,8 +20,7 @@ class SwiftInterfaceClass: SwiftInterfaceElement { var childGroupName: String { name } - /// The members, declarations, ... inside of the body of the struct - let children: [any SwiftInterfaceElement] + var children: [any SwiftInterfaceElement] var parent: (any SwiftInterfaceElement)? = nil diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Enum.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Enum.swift index 259c0cd..01c42c1 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Enum.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Enum.swift @@ -20,8 +20,7 @@ class SwiftInterfaceEnum: SwiftInterfaceElement { var childGroupName: String { name } - /// The members, declarations, ... inside of the body of the struct - let children: [any SwiftInterfaceElement] + var children: [any SwiftInterfaceElement] var parent: (any SwiftInterfaceElement)? = nil diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+EnumCase.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+EnumCase.swift index 47a8ab8..362e666 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+EnumCase.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+EnumCase.swift @@ -50,7 +50,7 @@ class SwiftInterfaceEnumCase: SwiftInterfaceElement { var childGroupName: String { "" } /// A typealias does not have children - let children: [any SwiftInterfaceElement] = [] + var children: [any SwiftInterfaceElement] = [] var parent: (any SwiftInterfaceElement)? = nil diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Extension.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Extension.swift index ceafb2a..1d8d8e3 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Extension.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Extension.swift @@ -18,7 +18,7 @@ class SwiftInterfaceExtension: SwiftInterfaceElement { var childGroupName: String { extendedType } // Grouping by extended type /// The members, declarations, ... inside of the body of the struct - let children: [any SwiftInterfaceElement] + var children: [any SwiftInterfaceElement] var parent: (any SwiftInterfaceElement)? = nil diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Function.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Function.swift index 7f515f6..1347613 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Function.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Function.swift @@ -59,8 +59,7 @@ class SwiftInterfaceFunction: SwiftInterfaceElement { var childGroupName: String { "" } // Not relevant as only used to group children - /// A function does not have children - let children: [any SwiftInterfaceElement] = [] + var children: [any SwiftInterfaceElement] = [] var parent: (any SwiftInterfaceElement)? = nil diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Initializer.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Initializer.swift index 6642fbb..bd1c12a 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Initializer.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Initializer.swift @@ -58,7 +58,7 @@ class SwiftInterfaceInitializer: SwiftInterfaceElement { var childGroupName: String { "" } // Not relevant as only used to group children /// A function does not have children - let children: [any SwiftInterfaceElement] = [] + var children: [any SwiftInterfaceElement] = [] var parent: (any SwiftInterfaceElement)? = nil diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Protocol.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Protocol.swift index 210a71c..ac1805d 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Protocol.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Protocol.swift @@ -20,8 +20,8 @@ class SwiftInterfaceProtocol: SwiftInterfaceElement { var childGroupName: String { name } // Not relevant as only used to group children /// The members, declarations, ... inside of the body of the struct - let children: [any SwiftInterfaceElement] - + var children: [any SwiftInterfaceElement] + var parent: (any SwiftInterfaceElement)? = nil var diffableSignature: String { diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Struct.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Struct.swift index 842fad7..99a1933 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Struct.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Struct.swift @@ -20,8 +20,7 @@ class SwiftInterfaceStruct: SwiftInterfaceElement { var childGroupName: String { name } - /// The members, declarations, ... inside of the body of the struct - let children: [any SwiftInterfaceElement] + var children: [any SwiftInterfaceElement] var parent: (any SwiftInterfaceElement)? = nil diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Subscript.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Subscript.swift index b05db51..bc5d2f2 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Subscript.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Subscript.swift @@ -58,8 +58,7 @@ class SwiftInterfaceSubscript: SwiftInterfaceElement { var childGroupName: String { "" } - /// A function does not have children - let children: [any SwiftInterfaceElement] = [] + var children: [any SwiftInterfaceElement] = [] var parent: (any SwiftInterfaceElement)? = nil diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+TypeAlias.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+TypeAlias.swift index 927e6c9..db9e3ad 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+TypeAlias.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+TypeAlias.swift @@ -21,8 +21,7 @@ class SwiftInterfaceTypeAlias: SwiftInterfaceElement { var childGroupName: String { "" } // Not relevant as only used to group children - /// A typealias does not have children - let children: [any SwiftInterfaceElement] = [] + var children: [any SwiftInterfaceElement] = [] var parent: (any SwiftInterfaceElement)? = nil diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Var.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Var.swift index 8221736..e1703c6 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Var.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Var.swift @@ -21,8 +21,7 @@ class SwiftInterfaceVar: SwiftInterfaceElement { var childGroupName: String { "" } // Not relevant as only used to group children - /// A var does not have children - let children: [any SwiftInterfaceElement] = [] + var children: [any SwiftInterfaceElement] = [] var parent: (any SwiftInterfaceElement)? = nil diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement.swift index 6e976e2..91bbc6f 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement.swift @@ -39,7 +39,9 @@ extension SwiftInterfaceElement { if let extensionElement = self as? SwiftInterfaceExtension { // We want to group all extensions under the type that they are extending // so we return the extended type as the parent - return extensionElement.extendedType + return sanitized( + parentPath: extensionElement.extendedType + ) } var parent = self.parent @@ -50,8 +52,23 @@ extension SwiftInterfaceElement { path += [parent?.childGroupName] } - let sanitizedPath = path.compactMap { $0 } - return sanitizedPath.reversed().joined(separator: ".") + return sanitized( + parentPath: path.compactMap { $0 }.filter { !$0.isEmpty }.reversed().joined(separator: ".") + ) + } + + /// Removing module name prefix for nicer readability + private func sanitized(parentPath: String) -> String { + var sanitizedPathComponents = parentPath.components(separatedBy: ".") + + // The first path component is always the module name so it's safe to remove all prefixes + if let moduleName = sanitizedPathComponents.first { + while sanitizedPathComponents.first == moduleName { + sanitizedPathComponents.removeFirst() + } + } + + return sanitizedPathComponents.joined(separator: ".") } } @@ -81,6 +98,11 @@ extension SwiftInterfaceElement { } recursiveDescription.append("\n\(String(repeating: spacer, count: indentation))}") } + + if indentation == 0 { + recursiveDescription.append("\n") + } + return recursiveDescription } } diff --git a/Sources/Helpers/XcodeTools.swift b/Sources/Helpers/XcodeTools.swift index 447fbd6..bd85693 100644 --- a/Sources/Helpers/XcodeTools.swift +++ b/Sources/Helpers/XcodeTools.swift @@ -23,13 +23,16 @@ struct XcodeTools { private let shell: ShellHandling private let fileHandler: FileHandling + private let logger: Logging? init( shell: ShellHandling = Shell(), - fileHandler: FileHandling = FileManager.default + fileHandler: FileHandling = FileManager.default, + logger: Logging? ) { self.shell = shell self.fileHandler = fileHandler + self.logger = logger } func loadPackageDescription( @@ -63,6 +66,7 @@ struct XcodeTools { } // print("πŸ‘Ύ \(command.joined(separator: " "))") + logger?.log("πŸ—οΈ Building \(scheme) from \(projectDirectoryPath)", from: String(describing: Self.self)) let result = shell.execute(command.joined(separator: " ")) if @@ -78,6 +82,36 @@ struct XcodeTools { } } + func archive( + projectDirectoryPath: String, + scheme: String + ) async throws -> String { + let command = "cd \(projectDirectoryPath); xcodebuild clean build -scheme \"\(scheme)\" -destination \"generic/platform=iOS\" -derivedDataPath \(Constants.derivedDataPath) -sdk `xcrun --sdk iphonesimulator --show-sdk-path` BUILD_LIBRARY_FOR_DISTRIBUTION=YES" + + + return try await Task { + logger?.log("πŸ“¦ Archiving \(scheme) from \(projectDirectoryPath)", from: String(describing: Self.self)) + + let result = shell.execute(command) + + let derivedDataPath = "\(projectDirectoryPath)/\(Constants.derivedDataPath)" + + // It might be that the archive failed but the .swiftinterface files are still created + // so we have to check outside if they exist. + // + // Also see: https://github.com/swiftlang/swift/issues/56573 + if !fileHandler.fileExists(atPath: derivedDataPath) { + print(result) + throw XcodeToolsError( + errorDescription: "πŸ’₯ Building project failed", + underlyingError: result + ) + } + + return derivedDataPath + }.value + } + func dumpSdk( projectDirectoryPath: String, module: String, diff --git a/Sources/Pipeline/Modules/ABIGenerator/ABIGenerator.swift b/Sources/Pipeline/Modules/ABIGenerator/ABIGenerator.swift index c1e1ea4..fbd4a75 100644 --- a/Sources/Pipeline/Modules/ABIGenerator/ABIGenerator.swift +++ b/Sources/Pipeline/Modules/ABIGenerator/ABIGenerator.swift @@ -20,7 +20,7 @@ struct ABIGenerator: ABIGenerating { logger: Logging? ) { self.shell = shell - self.xcodeTools = XcodeTools(shell: shell, fileHandler: fileHandler) + self.xcodeTools = XcodeTools(shell: shell, fileHandler: fileHandler, logger: logger) self.packageFileHelper = .init(fileHandler: fileHandler, xcodeTools: xcodeTools) self.fileHandler = fileHandler self.logger = logger diff --git a/Sources/Pipeline/Modules/ABIGenerator/ProjectABIProvider.swift b/Sources/Pipeline/Modules/ABIGenerator/ProjectABIProvider.swift index a964d38..08384f2 100644 --- a/Sources/Pipeline/Modules/ABIGenerator/ProjectABIProvider.swift +++ b/Sources/Pipeline/Modules/ABIGenerator/ProjectABIProvider.swift @@ -19,11 +19,6 @@ struct ProjectABIProvider: ABIGenerating { description: String ) throws -> [ABIGeneratorOutput] { - // TODO: For binary frameworks: - // Instead of using the abi.json - use the .swiftinterface file instead (Parsable with SwiftSyntax) - // The .swiftinterface file also does exist for SwiftPackages with binary targets - // (for non-binary Swift Packages we would still parse the abi.json) - guard let scheme else { assertionFailure("ProjectABIProvider needs a scheme to be passed to \(#function)") return [] diff --git a/Sources/Pipeline/Modules/ProjectBuilder.swift b/Sources/Pipeline/Modules/ProjectBuilder.swift index 54e8327..3179e34 100644 --- a/Sources/Pipeline/Modules/ProjectBuilder.swift +++ b/Sources/Pipeline/Modules/ProjectBuilder.swift @@ -78,7 +78,8 @@ private extension ProjectBuilder { let xcodeTools = XcodeTools( shell: shell, - fileHandler: fileHandler + fileHandler: fileHandler, + logger: logger ) try Self.buildProject( diff --git a/Sources/Pipeline/Modules/ProjectSetupHelper.swift b/Sources/Pipeline/Modules/ProjectSetupHelper.swift new file mode 100644 index 0000000..17ccf63 --- /dev/null +++ b/Sources/Pipeline/Modules/ProjectSetupHelper.swift @@ -0,0 +1,77 @@ +// +// File.swift +// +// +// Created by Alexander Guretzki on 04/10/2024. +// + +import Foundation + +struct ProjectSetupHelper: ProjectSetupHelping { + + let workingDirectoryPath: String + let shell: any ShellHandling + let randomStringGenerator: any RandomStringGenerating + let fileHandler: any FileHandling + let logger: (any Logging)? + + init( + workingDirectoryPath: String, + randomStringGenerator: any RandomStringGenerating = RandomStringGenerator(), + shell: any ShellHandling = Shell(), + fileHandler: any FileHandling = FileManager.default, + logger: (any Logging)? + ) { + self.workingDirectoryPath = workingDirectoryPath + self.randomStringGenerator = randomStringGenerator + self.shell = shell + self.fileHandler = fileHandler + self.logger = logger + } + + func setup( + _ projectSource: ProjectSource, + projectType: ProjectType + ) async throws -> String { + try await Task { + let checkoutPath = workingDirectoryPath + "\(randomStringGenerator.generateRandomString())" + switch projectSource { + case .local(let path): + shell.execute("cp -a '\(path)' '\(checkoutPath)'") + case .remote(let branch, let repository): + let git = Git(shell: shell, fileHandler: fileHandler, logger: logger) + try git.clone(repository, at: branch, targetDirectoryPath: checkoutPath) + } + + filterProjectFiles(at: checkoutPath, for: projectType) + return checkoutPath + }.value + } + + func filterProjectFiles(at checkoutPath: String, for projectType: ProjectType) { + try? fileHandler.contentsOfDirectory(atPath: checkoutPath) + .filter { !projectType.fileIsIncluded(filePath: $0) } + .forEach { filePath in + try? fileHandler.removeItem(atPath: "\(checkoutPath)/\(filePath)") + } + } +} + +private extension ProjectType { + + var excludedFileSuffixes: [String] { + switch self { + case .swiftPackage: + [".xcodeproj", ".xcworkspace"] + case .xcodeProject: + ["Package.swift"] + } + } + + func fileIsIncluded(filePath: String) -> Bool { + for excludedFileSuffix in excludedFileSuffixes { + if filePath.hasSuffix(excludedFileSuffix) { return false } + } + return true + } +} diff --git a/Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpAnalyzer.swift b/Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpAnalyzer.swift index ce560fc..1841969 100644 --- a/Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpAnalyzer.swift +++ b/Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpAnalyzer.swift @@ -137,13 +137,6 @@ private extension SDKDump.Element { /// If we used the `name` it could cause a false positive with other functions named `init` (e.g. convenience inits) when trying to find matching elements during this finding phase. /// In a later consolidation phase removals/additions are compared again based on their `name` to combine them to a `change` func isComparable(to otherElement: SDKDump.Element) -> Bool { - - if declKind == .func && otherElement.declKind == .func { - print(printedName) - print(otherElement.printedName) - print("-----------------------------") - } - return printedName == otherElement.printedName && declKind == otherElement.declKind && parentPath == otherElement.parentPath diff --git a/Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceAnalyzer.swift b/Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceAnalyzer.swift index c4f712b..e68b9df 100644 --- a/Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceAnalyzer.swift +++ b/Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceAnalyzer.swift @@ -6,9 +6,9 @@ import Foundation -// TODO: Add a protocol for this - -struct SwiftInterfaceAnalyzer { +struct SwiftInterfaceAnalyzer: SwiftInterfaceAnalyzing { + + // TODO: Surface changes that happened to a subclass/protocol/extension let changeConsolidator: SwiftInterfaceChangeConsolidating @@ -46,23 +46,31 @@ struct SwiftInterfaceAnalyzer { isRoot: Bool = false ) -> [IndependentSwiftInterfaceChange] { - if lhs.recursiveDescription() == rhs.recursiveDescription() { return [] } - var changes = [IndependentSwiftInterfaceChange]() + if lhs.recursiveDescription() == rhs.recursiveDescription() { return changes } + if !isRoot, oldFirst, lhs.description != rhs.description { changes += independentChanges(from: lhs, and: rhs, oldFirst: oldFirst) } changes += lhs.children.flatMap { lhsElement in - + // Trying to find a matching element - // First checking if we found an exact match based on the description + // First checking if we found an exact match based on the recursive description // as we don't want to match a non-change with a change - if let exactMatch = rhs.children.first(where: { $0.description == lhsElement.description }) { - // We found an exact match so we check if the children changed - return Self.recursiveCompare(element: lhsElement, to: exactMatch, oldFirst: oldFirst) + // + // This is especially important for extensions where the description might + // be the same for a lot of different extensions but the body might be completely different + if rhs.children.first(where: { $0.recursiveDescription() == lhsElement.recursiveDescription() }) != nil { + return [IndependentSwiftInterfaceChange]() + } + + // First checking if we found a match based on the description + if let descriptionMatch = rhs.children.first(where: { $0.description == lhsElement.description }) { + // so we check if the children changed + return Self.recursiveCompare(element: lhsElement, to: descriptionMatch, oldFirst: oldFirst) } // ... then losening the criteria to find a comparable element @@ -70,7 +78,7 @@ struct SwiftInterfaceAnalyzer { // We found a comparable element so we check if the children changed return Self.recursiveCompare(element: lhsElement, to: rhsChildForName, oldFirst: oldFirst) } - + // No matching element was found so either it was removed or added let changeType: IndependentSwiftInterfaceChange.ChangeType = oldFirst ? .removal(lhsElement.description) : diff --git a/Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceChangeConsolidator.swift b/Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceChangeConsolidator.swift index 3c0c317..743ff01 100644 --- a/Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceChangeConsolidator.swift +++ b/Sources/Pipeline/Modules/SwiftInterfaceAnalyzer/SwiftInterfaceChangeConsolidator.swift @@ -49,7 +49,11 @@ struct SwiftInterfaceChangeConsolidator: SwiftInterfaceChangeConsolidating { let oldDescription = change.oldFirst ? change.element.description : match.element.description let newDescription = change.oldFirst ? match.element.description : change.element.description let listOfChanges = listOfChanges(between: change, and: match) - + + // TODO: We should not even end up here if an element does not have any changes + // This is just a quick fix for now but we should explore why we sometimes get here + if listOfChanges.isEmpty { break } + consolidatedChanges.append( .init( changeType: .change( diff --git a/Sources/Pipeline/Modules/SwiftInterfaceFileLocator.swift b/Sources/Pipeline/Modules/SwiftInterfaceFileLocator.swift new file mode 100644 index 0000000..d992977 --- /dev/null +++ b/Sources/Pipeline/Modules/SwiftInterfaceFileLocator.swift @@ -0,0 +1,44 @@ +import Foundation + +struct SwiftInterfaceFileLocator { + + enum SwiftInterfaceType { + case `private` + case `public` + } + + let fileHandler: any FileHandling + let shell: any ShellHandling + + init( + fileHandler: any FileHandling = FileManager.default, + shell: any ShellHandling = Shell() + ) { + self.fileHandler = fileHandler + self.shell = shell + } + + func locate(for scheme: String, derivedDataPath: String, type: SwiftInterfaceType) throws -> [URL] { + let swiftModulePaths = shell.execute("cd '\(derivedDataPath)'; find . -type d -name '\(scheme).swiftmodule'") + .components(separatedBy: .newlines) + .map { URL(filePath: $0) } + + guard let swiftModulePath = swiftModulePaths.first?.path() else { + throw FileHandlerError.pathDoesNotExist(path: "find . -type d -name '\(scheme).swiftmodule'") + } + + let completeSwiftModulePath = derivedDataPath + "/" + swiftModulePath + + let swiftModuleContent = try fileHandler.contentsOfDirectory(atPath: completeSwiftModulePath) + + let swiftInterfacePaths: [String] + switch type { + case .private: + swiftInterfacePaths = swiftModuleContent.filter { $0.hasSuffix(".private.swiftinterface") } + case .public: + swiftInterfacePaths = swiftModuleContent.filter { $0.hasSuffix(".swiftinterface") && !$0.hasSuffix(".private.swiftinterface") } + } + + return swiftInterfacePaths.map { URL(filePath: "\(completeSwiftModulePath)/\($0)") } + } +} diff --git a/Sources/Pipeline/Modules/SwiftInterfaceParser/SwiftInterfaceParser.swift b/Sources/Pipeline/Modules/SwiftInterfaceParser/SwiftInterfaceParser.swift index 0fd02b1..7d92503 100644 --- a/Sources/Pipeline/Modules/SwiftInterfaceParser/SwiftInterfaceParser.swift +++ b/Sources/Pipeline/Modules/SwiftInterfaceParser/SwiftInterfaceParser.swift @@ -7,7 +7,7 @@ import SwiftParser Documentation about DeclSyntax: - https://swiftpackageindex.com/swiftlang/swift-syntax/600.0.1/documentation/swiftsyntax/declsyntax */ -class SwiftInterfaceParser: SyntaxVisitor { +class SwiftInterfaceParser: SyntaxVisitor, SwiftInterfaceParsing { class Root: SwiftInterfaceElement { @@ -52,7 +52,7 @@ class SwiftInterfaceParser: SyntaxVisitor { private var scope: Scope = .root(elements: []) - static public func parse(source: String, moduleName: String) -> Root { + public func parse(source: String, moduleName: String) -> any SwiftInterfaceElement { let visitor = Self() visitor.walk(Parser.parse(source: source)) return Root( diff --git a/Sources/Pipeline/Modules/SwiftPackageFileAnalyzer.swift b/Sources/Pipeline/Modules/SwiftPackageFileAnalyzer.swift index c503e0b..ec7a2bc 100644 --- a/Sources/Pipeline/Modules/SwiftPackageFileAnalyzer.swift +++ b/Sources/Pipeline/Modules/SwiftPackageFileAnalyzer.swift @@ -13,10 +13,11 @@ struct SwiftPackageFileAnalyzer: ProjectAnalyzing { init( fileHandler: FileHandling = FileManager.default, - xcodeTools: XcodeTools = XcodeTools() + shell: ShellHandling = Shell(), + logger: Logging? ) { self.fileHandler = fileHandler - self.xcodeTools = xcodeTools + self.xcodeTools = XcodeTools(shell: shell, fileHandler: fileHandler, logger: logger) } func analyze(oldProjectUrl: URL, newProjectUrl: URL) throws -> ProjectAnalyzerResult { diff --git a/Sources/Pipeline/Pipeline+Protocols.swift b/Sources/Pipeline/Pipeline+Protocols.swift index 9c483ed..454d36f 100644 --- a/Sources/Pipeline/Pipeline+Protocols.swift +++ b/Sources/Pipeline/Pipeline+Protocols.swift @@ -10,6 +10,15 @@ protocol ProjectBuilding { func build(source: ProjectSource, scheme: String?) async throws -> URL } +enum ProjectType { + case swiftPackage + case xcodeProject +} + +protocol ProjectSetupHelping { + func setup(_ projectSource: ProjectSource, projectType: ProjectType) async throws -> String +} + struct ABIGeneratorOutput: Equatable { let targetName: String let abiJsonFileUrl: URL @@ -27,6 +36,14 @@ protocol SDKDumpAnalyzing { func analyze(old: SDKDump, new: SDKDump) throws -> [Change] } +protocol SwiftInterfaceParsing { + func parse(source: String, moduleName: String) -> any SwiftInterfaceElement +} + +protocol SwiftInterfaceAnalyzing { + func analyze(old: some SwiftInterfaceElement, new: some SwiftInterfaceElement) throws -> [Change] +} + protocol OutputGenerating { func generate( from changesPerTarget: [String: [Change]], diff --git a/Sources/Pipeline/Pipeline.swift b/Sources/Pipeline/SDKDumpPipeline.swift similarity index 99% rename from Sources/Pipeline/Pipeline.swift rename to Sources/Pipeline/SDKDumpPipeline.swift index 8632164..0346b7f 100644 --- a/Sources/Pipeline/Pipeline.swift +++ b/Sources/Pipeline/SDKDumpPipeline.swift @@ -6,7 +6,7 @@ import Foundation -struct Pipeline { +struct SDKDumpPipeline { let newProjectSource: ProjectSource let oldProjectSource: ProjectSource @@ -80,7 +80,7 @@ struct Pipeline { // MARK: - Convenience Methods -private extension Pipeline { +private extension SDKDumpPipeline { func buildProjects(oldSource: ProjectSource, newSource: ProjectSource, scheme: String?) async throws -> (URL, URL) { async let oldBuildResult = try projectBuilder.build( diff --git a/Sources/Pipeline/SwiftInterfacePipeline.swift b/Sources/Pipeline/SwiftInterfacePipeline.swift new file mode 100644 index 0000000..68a4a2c --- /dev/null +++ b/Sources/Pipeline/SwiftInterfacePipeline.swift @@ -0,0 +1,61 @@ +// +// File.swift +// +// +// Created by Alexander Guretzki on 03/10/2024. +// + +import Foundation + +struct SwiftInterfacePipeline { + + let swiftInterfaceFiles: [SwiftInterfaceFile] + + let fileHandler: any FileHandling + let swiftInterfaceParser: any SwiftInterfaceParsing + let swiftInterfaceAnalyzer: any SwiftInterfaceAnalyzing + let logger: (any Logging)? + + struct SwiftInterfaceFile { + let name: String + let oldFilePath: String + let newFilePath: String + } + + init( + swiftInterfaceFiles: [SwiftInterfaceFile], + fileHandler: FileHandling, + swiftInterfaceParser: any SwiftInterfaceParsing, + swiftInterfaceAnalyzer: any SwiftInterfaceAnalyzing, + logger: (any Logging)? + ) { + self.swiftInterfaceFiles = swiftInterfaceFiles + self.fileHandler = fileHandler + self.swiftInterfaceParser = swiftInterfaceParser + self.swiftInterfaceAnalyzer = swiftInterfaceAnalyzer + self.logger = logger + } + + func run() async throws -> [String: [Change]] { + + var changes = [String: [Change]]() + + try swiftInterfaceFiles.forEach { file in + let newContent = try fileHandler.loadString(from: file.newFilePath) + let oldContent = try fileHandler.loadString(from: file.oldFilePath) + let newParsed = swiftInterfaceParser.parse(source: newContent, moduleName: file.name) + let oldParsed = swiftInterfaceParser.parse(source: oldContent, moduleName: file.name) + + let moduleChanges = try swiftInterfaceAnalyzer.analyze( + old: oldParsed, + new: newParsed + ) + + if !moduleChanges.isEmpty { + changes[file.name] = moduleChanges + } + } + + return changes + } +} diff --git a/Sources/public-api-diff.swift b/Sources/public-api-diff.swift index 54847d4..7d55b19 100644 --- a/Sources/public-api-diff.swift +++ b/Sources/public-api-diff.swift @@ -10,8 +10,6 @@ import Foundation @main struct PublicApiDiff: AsyncParsableCommand { - // TODO: Allow to pass already built projects - @Option(help: "Specify the updated version to compare to") public var new: String @@ -30,31 +28,166 @@ struct PublicApiDiff: AsyncParsableCommand { let oldSource = try ProjectSource.from(old, fileHandler: fileHandler) let newSource = try ProjectSource.from(new, fileHandler: fileHandler) let logger: any Logging = PipelineLogger(logLevel: .debug) // LogLevel should be provided by a parameter - + let xcodeTools = XcodeTools(logger: logger) logger.log("Comparing `\(newSource.description)` to `\(oldSource.description)`", from: "Main") let currentDirectory = fileHandler.currentDirectoryPath let workingDirectoryPath = currentDirectory.appending("/tmp-public-api-diff") - let pipelineOutput = try await Pipeline.run( - newSource: newSource, + // MARK: - Generate the .swiftinterface files on the fly (optional) + // TODO: Allow passing of .swiftinterface files + + let projectType: ProjectType = .swiftPackage + let swiftInterfaceType: SwiftInterfaceFileLocator.SwiftInterfaceType = .public + + let (oldProjectUrl, newProjectUrl) = try await setupProject( oldSource: oldSource, - scheme: scheme, + newSource: newSource, + workingDirectoryPath: workingDirectoryPath, + projectType: projectType, + logger: logger + ) + + let swiftInterfaceFiles = try await generateSwiftInterfaceFiles( + newProjectUrl: newProjectUrl, + oldProjectUrl: oldProjectUrl, + projectType: projectType, + swiftInterfaceType: swiftInterfaceType, workingDirectoryPath: workingDirectoryPath, fileHandler: fileHandler, + xcodeTools: xcodeTools, logger: logger ) + // MARK: - Analyze .swiftinterface files + + var changes = try await SwiftInterfacePipeline( + swiftInterfaceFiles: swiftInterfaceFiles, + fileHandler: fileHandler, + swiftInterfaceParser: SwiftInterfaceParser(), + swiftInterfaceAnalyzer: SwiftInterfaceAnalyzer(), + logger: logger + ).run() + + // MARK: - Analyze Package.swift (optional) + + let swiftPackageFileAnalyzer = SwiftPackageFileAnalyzer(logger: logger) + let swiftPackageAnalysis = try swiftPackageFileAnalyzer.analyze( + oldProjectUrl: oldProjectUrl, + newProjectUrl: newProjectUrl + ) + + if !swiftPackageAnalysis.changes.isEmpty { + changes["Package.swift"] = swiftPackageAnalysis.changes + } + + let allTargets = swiftInterfaceFiles.map(\.name) + + // MARK: - Generate Output (optional) + + let markdownOutput = MarkdownOutputGenerator().generate( + from: changes, + allTargets: allTargets.sorted(), + oldSource: oldSource, + newSource: newSource, + warnings: swiftPackageAnalysis.warnings + ) + if let output { - try fileHandler.write(pipelineOutput, to: output) + try fileHandler.write(markdownOutput, to: output) } else { // We're not using a logger here as we always want to have it printed if no output was specified - print(pipelineOutput) + print(markdownOutput) + } + } +} + +private extension PublicApiDiff { + + func setupProject( + oldSource: ProjectSource, + newSource: ProjectSource, + workingDirectoryPath: String, + projectType: ProjectType, + logger: (any Logging)? + ) async throws -> (old: URL, new: URL) { + let projectSetupHelper = ProjectSetupHelper( + workingDirectoryPath: workingDirectoryPath, + logger: logger + ) + + // async let to make them perform in parallel + async let asyncNewProjectDirectoryPath = try projectSetupHelper.setup(newSource, projectType: projectType) + async let asyncOldProjectDirectoryPath = try projectSetupHelper.setup(oldSource, projectType: projectType) + + return try await (URL(filePath: asyncOldProjectDirectoryPath), URL(filePath: asyncNewProjectDirectoryPath)) + } + + // TODO: Move this to it's own pipeline that can be used optionally + func generateSwiftInterfaceFiles( + newProjectUrl: URL, + oldProjectUrl: URL, + projectType: ProjectType, + swiftInterfaceType: SwiftInterfaceFileLocator.SwiftInterfaceType, + workingDirectoryPath: String, + fileHandler: any FileHandling, + xcodeTools: XcodeTools, + logger: (any Logging)? + ) async throws -> [SwiftInterfacePipeline.SwiftInterfaceFile] { + + let newProjectDirectoryPath = newProjectUrl.path() + let oldProjectDirectoryPath = oldProjectUrl.path() + + let archiveScheme: String + let schemesToCompare: [String] + + switch projectType { + case .swiftPackage: + archiveScheme = "_AllTargets" + let packageFileHelper = PackageFileHelper(fileHandler: fileHandler, xcodeTools: xcodeTools) + try packageFileHelper + .preparePackageWithConsolidatedLibrary(named: archiveScheme, at: newProjectDirectoryPath) + try packageFileHelper + .preparePackageWithConsolidatedLibrary(named: archiveScheme, at: oldProjectDirectoryPath) + + let newTargets = try Set(packageFileHelper.availableTargets(at: newProjectDirectoryPath)) + let oldTargets = try Set(packageFileHelper.availableTargets(at: oldProjectDirectoryPath)) + + schemesToCompare = newTargets.intersection(oldTargets).sorted() // TODO: Handle added/removed targets + + case .xcodeProject: + guard let scheme else { + throw PipelineError.noTargetFound // TODO: Better error! + } + archiveScheme = scheme + schemesToCompare = [scheme] + } + + async let asyncNewDerivedDataPath = try xcodeTools.archive(projectDirectoryPath: newProjectDirectoryPath, scheme: archiveScheme) + async let asyncOldDerivedDataPath = try xcodeTools.archive(projectDirectoryPath: oldProjectDirectoryPath, scheme: archiveScheme) + + let newDerivedDataPath = try await asyncNewDerivedDataPath + let oldDerivedDataPath = try await asyncOldDerivedDataPath + + return try schemesToCompare.compactMap { scheme in + // Locating swift interface files + let interfaceFileLocator = SwiftInterfaceFileLocator() + let newSwiftInterfacePaths = try interfaceFileLocator.locate(for: scheme, derivedDataPath: newDerivedDataPath, type: swiftInterfaceType) + let oldSwiftInterfacePaths = try interfaceFileLocator.locate(for: scheme, derivedDataPath: oldDerivedDataPath, type: swiftInterfaceType) + + guard + let oldFilePath = oldSwiftInterfacePaths.first?.path(), + let newFilePath = newSwiftInterfacePaths.first?.path() + else { + return nil + } + + return .init(name: scheme, oldFilePath: oldFilePath, newFilePath: newFilePath) } } } -internal extension Pipeline { +internal extension SDKDumpPipeline { static func run( newSource: ProjectSource, @@ -70,13 +203,13 @@ internal extension Pipeline { try? fileHandler.removeItem(atPath: workingDirectoryPath) } - return try await Pipeline( + return try await SDKDumpPipeline( newProjectSource: newSource, oldProjectSource: oldSource, scheme: scheme, projectBuilder: ProjectBuilder(baseWorkingDirectoryPath: workingDirectoryPath, logger: logger), abiGenerator: ABIGenerator(logger: logger), - projectAnalyzer: SwiftPackageFileAnalyzer(), + projectAnalyzer: SwiftPackageFileAnalyzer(logger: logger), sdkDumpGenerator: SDKDumpGenerator(), sdkDumpAnalyzer: SDKDumpAnalyzer(), outputGenerator: MarkdownOutputGenerator(), diff --git a/Tests/IntegrationTests/ReferencePackageTests.swift b/Tests/IntegrationTests/ReferencePackageTests.swift index 4a4fdec..080c384 100644 --- a/Tests/IntegrationTests/ReferencePackageTests.swift +++ b/Tests/IntegrationTests/ReferencePackageTests.swift @@ -9,17 +9,81 @@ import XCTest class ReferencePackageTests: XCTestCase { - func test_swiftInterface() throws { + func test_swiftInterface() async throws { - // TODO: Build + use the pipeline + // Unfortunately we can't use packages as Test Resources, so we put it in a `ReferencePackages` directory on root + guard let projectRoot = #file.replacingOccurrences(of: "relatve/path/to/file", with: "").split(separator: "/Tests/").first else { + XCTFail("Cannot find root directory") + return + } + + let referencePackagesRoot = URL(filePath: String(projectRoot)).appending(path: "ReferencePackages") + + /* + let oldSourceContent = try content(atPath: "/Users/alexandergu/Downloads/AdyenPOS.xcframework/ios-arm64_x86_64-simulator/AdyenPOS.framework/Modules/AdyenPOS.swiftmodule/arm64-apple-ios-simulator.swiftinterface") + let newSourceContent = try content(atPath: "/Users/alexandergu/Downloads/AdyenPOS/AdyenPOS_3.2.0.xcframework/ios-arm64_x86_64-simulator/AdyenPOS.framework/Modules/AdyenPOS.swiftmodule/arm64-apple-ios-simulator.swiftinterface") + */ + + let oldPrivateSwiftInterfaceFilePath = try swiftInterfaceFilePath( + for: referencePackagesRoot, + packageName: "ReferencePackage", + interfaceType: .private + ) - // Public interface + let newPrivateSwiftInterfaceFilePath = try swiftInterfaceFilePath( + for: referencePackagesRoot, + packageName: "UpdatedPackage", + interfaceType: .private + ) - try test(swiftInterface: .public) + let oldPublicSwiftInterfaceFilePath = try swiftInterfaceFilePath( + for: referencePackagesRoot, + packageName: "ReferencePackage", + interfaceType: .public + ) + + let newPublicSwiftInterfaceFilePath = try swiftInterfaceFilePath( + for: referencePackagesRoot, + packageName: "UpdatedPackage", + interfaceType: .public + ) - // @_spi interface + let pipelineOutput = try await SwiftInterfacePipeline( + swiftInterfaceFiles: [ + .newAndOld( + name: "ReferencePackage", + oldFilePath: oldPrivateSwiftInterfaceFilePath, + newFilePath: newPrivateSwiftInterfaceFilePath + ), + .old( + name: "ReferencePackage", + filePath: oldPublicSwiftInterfaceFilePath + ), + .new( + name: "ReferencePackage", + filePath: newPublicSwiftInterfaceFilePath + ) + ], + fileHandler: FileManager.default, + swiftInterfaceParser: SwiftInterfaceParser(), + swiftInterfaceAnalyzer: SwiftInterfaceAnalyzer(), + outputGenerator: MarkdownOutputGenerator(), + logger: PipelineLogger(logLevel: .debug) + ).run() + + print(pipelineOutput) - try test(swiftInterface: .private) + /* + let expectedLines = sanitizeOutput(expectedOutput).components(separatedBy: "\n") + let markdownOutputLines = sanitizeOutput(markdownOutput).components(separatedBy: "\n") + + for i in 0.. String { + func swiftInterfaceFilePath(for referencePackagesRoot: URL, packageName: String, interfaceType: InterfaceType) throws -> String { let oldReferencePackageDirectory = referencePackagesRoot.appending(path: packageName) let interfaceFilePath = try XCTUnwrap(oldReferencePackageDirectory.appending(path: interfaceType.interfaceFilePath)) - let interfaceFileContent = try XCTUnwrap(FileManager.default.contents(atPath: interfaceFilePath.path())) - return try XCTUnwrap(String(data: interfaceFileContent, encoding: .utf8)) + return interfaceFilePath.path() } func content(atPath path: String) throws -> String { @@ -66,62 +129,6 @@ private extension ReferencePackageTests { return try XCTUnwrap(String(data: interfaceFileContent, encoding: .utf8)) } - func test(swiftInterface interface: InterfaceType) throws { - // Unfortunately we can't use packages as Test Resources, so we put it in a `ReferencePackages` directory on root - guard let projectRoot = #file.replacingOccurrences(of: "relatve/path/to/file", with: "").split(separator: "/Tests/").first else { - XCTFail("Cannot find root directory") - return - } - - let referencePackagesRoot = URL(filePath: String(projectRoot)).appending(path: "ReferencePackages") - - let expectedOutput = try expectedOutput(for: interface) - - let oldSourceContent = try swiftInterfaceContent( - referencePackagesRoot: referencePackagesRoot, - packageName: "ReferencePackage", - interfaceType: interface - ) - - let newSourceContent = try swiftInterfaceContent( - referencePackagesRoot: referencePackagesRoot, - packageName: "UpdatedPackage", - interfaceType: interface - ) - - /* - let oldSourceContent = try content(atPath: "/Users/alexandergu/Downloads/AdyenPOS.xcframework/ios-arm64_x86_64-simulator/AdyenPOS.framework/Modules/AdyenPOS.swiftmodule/arm64-apple-ios-simulator.swiftinterface") - let newSourceContent = try content(atPath: "/Users/alexandergu/Downloads/AdyenPOS/AdyenPOS_3.2.0.xcframework/ios-arm64_x86_64-simulator/AdyenPOS.framework/Modules/AdyenPOS.swiftmodule/arm64-apple-ios-simulator.swiftinterface") - */ - - let oldInterface = SwiftInterfaceParser.parse(source: oldSourceContent, moduleName: "ReferencePackage") - let newInterface = SwiftInterfaceParser.parse(source: newSourceContent, moduleName: "ReferencePackage") - - let analyzer = SwiftInterfaceAnalyzer() - - let changes = analyzer.analyze(old: oldInterface, new: newInterface) - - let markdownOutput = MarkdownOutputGenerator().generate( - from: ["ReferencePackage": changes], - allTargets: ["ReferencePackage"], - oldSource: .local(path: "AdyenPOS 2.2.2"), - newSource: .local(path: "AdyenPOS 3.2.0"), - warnings: [] - ) - - print(markdownOutput) - - let expectedLines = sanitizeOutput(expectedOutput).components(separatedBy: "\n") - let markdownOutputLines = sanitizeOutput(markdownOutput).components(separatedBy: "\n") - - for i in 0.. String { var lines = output.components(separatedBy: "\n") diff --git a/Tests/UnitTests/PipelineTests.swift b/Tests/UnitTests/PipelineTests.swift index 0b90e30..b1361d2 100644 --- a/Tests/UnitTests/PipelineTests.swift +++ b/Tests/UnitTests/PipelineTests.swift @@ -54,7 +54,7 @@ class PipelineTests: XCTestCase { "Output" ] - let pipeline = Pipeline( + let pipeline = SDKDumpPipeline( newProjectSource: newProjectSource, oldProjectSource: oldProjectSource, scheme: nil, From b4ccf0a68ae703f4cc443c07d8539862e15bb585 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Mon, 7 Oct 2024 12:09:35 +0200 Subject: [PATCH 06/45] Merging extensions with extended types --- .../SwiftInterfaceElement+Actor.swift | 6 +- .../SwiftInterfaceElement+Class.swift | 6 +- .../SwiftInterfaceElement+Enum.swift | 6 +- .../SwiftInterfaceElement+Protocol.swift | 6 +- .../SwiftInterfaceElement+Struct.swift | 6 +- .../SwiftInterfaceElement.swift | 10 ++ .../SwiftInterfaceParser+Root.swift | 102 ++++++++++++++++++ .../SwiftInterfaceParser.swift | 34 ------ 8 files changed, 132 insertions(+), 44 deletions(-) create mode 100644 Sources/Pipeline/Modules/SwiftInterfaceParser/SwiftInterfaceParser+Root.swift diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Actor.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Actor.swift index e41e27d..a8282b1 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Actor.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Actor.swift @@ -1,6 +1,6 @@ import Foundation -class SwiftInterfaceActor: SwiftInterfaceElement { +class SwiftInterfaceActor: SwiftInterfaceElement, SwiftInterfaceExtendableElement { var childGroupName: String { name } @@ -12,7 +12,7 @@ class SwiftInterfaceActor: SwiftInterfaceElement { /// e.g. let genericParameterDescription: String? - let inheritance: [String]? + var inheritance: [String]? /// e.g. public, private, package, open, internal let modifiers: [String] @@ -36,6 +36,8 @@ class SwiftInterfaceActor: SwiftInterfaceElement { compileDescription() } + var typeName: String { name } + init( attributes: [String], modifiers: [String], diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Class.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Class.swift index 3b587b4..a1543f8 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Class.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Class.swift @@ -1,6 +1,6 @@ import Foundation -class SwiftInterfaceClass: SwiftInterfaceElement { +class SwiftInterfaceClass: SwiftInterfaceElement, SwiftInterfaceExtendableElement { /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... let attributes: [String] @@ -10,7 +10,7 @@ class SwiftInterfaceClass: SwiftInterfaceElement { /// e.g. let genericParameterDescription: String? - let inheritance: [String]? + var inheritance: [String]? /// e.g. public, private, package, open, internal let modifiers: [String] @@ -36,6 +36,8 @@ class SwiftInterfaceClass: SwiftInterfaceElement { compileDescription() } + var typeName: String { name } + init( attributes: [String], modifiers: [String], diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Enum.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Enum.swift index 01c42c1..806e766 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Enum.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Enum.swift @@ -1,6 +1,6 @@ import Foundation -class SwiftInterfaceEnum: SwiftInterfaceElement { +class SwiftInterfaceEnum: SwiftInterfaceElement, SwiftInterfaceExtendableElement { /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... let attributes: [String] @@ -13,7 +13,7 @@ class SwiftInterfaceEnum: SwiftInterfaceElement { /// e.g. let genericParameterDescription: String? - let inheritance: [String]? + var inheritance: [String]? /// e.g. where T : Equatable let genericWhereClauseDescription: String? @@ -36,6 +36,8 @@ class SwiftInterfaceEnum: SwiftInterfaceElement { compileDescription() } + var typeName: String { name } + init( attributes: [String], modifiers: [String], diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Protocol.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Protocol.swift index ac1805d..cd8b740 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Protocol.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Protocol.swift @@ -1,6 +1,6 @@ import Foundation -class SwiftInterfaceProtocol: SwiftInterfaceElement { +class SwiftInterfaceProtocol: SwiftInterfaceElement, SwiftInterfaceExtendableElement { /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... let attributes: [String] @@ -9,7 +9,7 @@ class SwiftInterfaceProtocol: SwiftInterfaceElement { let primaryAssociatedTypes: [String]? - let inheritance: [String]? + var inheritance: [String]? /// e.g. public, private, package, open, internal let modifiers: [String] @@ -36,6 +36,8 @@ class SwiftInterfaceProtocol: SwiftInterfaceElement { compileDescription() } + var typeName: String { name } + init( attributes: [String], modifiers: [String], diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Struct.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Struct.swift index 99a1933..e057e29 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Struct.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Struct.swift @@ -1,6 +1,6 @@ import Foundation -class SwiftInterfaceStruct: SwiftInterfaceElement { +class SwiftInterfaceStruct: SwiftInterfaceElement, SwiftInterfaceExtendableElement { /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... let attributes: [String] @@ -10,7 +10,7 @@ class SwiftInterfaceStruct: SwiftInterfaceElement { /// e.g. let genericParameterDescription: String? - let inheritance: [String]? + var inheritance: [String]? /// e.g. public, private, package, open, internal let modifiers: [String] @@ -36,6 +36,8 @@ class SwiftInterfaceStruct: SwiftInterfaceElement { compileDescription() } + var typeName: String { name } + init( attributes: [String], modifiers: [String], diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement.swift index 91bbc6f..460be55 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement.swift @@ -1,5 +1,14 @@ import Foundation +protocol SwiftInterfaceExtendableElement: AnyObject { + + var typeName: String { get } + + var inheritance: [String]? { get set } + + var children: [any SwiftInterfaceElement] { get set } +} + protocol SwiftInterfaceElement: CustomStringConvertible, AnyObject { /// Used to group children together @@ -88,6 +97,7 @@ extension SwiftInterfaceElement { } extension SwiftInterfaceElement { + func recursiveDescription(indentation: Int = 0) -> String { let spacer = " " var recursiveDescription = "\(String(repeating: spacer, count: indentation))\(description)" diff --git a/Sources/Pipeline/Modules/SwiftInterfaceParser/SwiftInterfaceParser+Root.swift b/Sources/Pipeline/Modules/SwiftInterfaceParser/SwiftInterfaceParser+Root.swift new file mode 100644 index 0000000..6733d71 --- /dev/null +++ b/Sources/Pipeline/Modules/SwiftInterfaceParser/SwiftInterfaceParser+Root.swift @@ -0,0 +1,102 @@ +// +// File.swift +// +// +// Created by Alexander Guretzki on 07/10/2024. +// + +import Foundation + +extension SwiftInterfaceParser { + + class Root: SwiftInterfaceElement { + + var parent: (any SwiftInterfaceElement)? = nil + + var diffableSignature: String { "" } + + var consolidatableName: String { "" } + + var description: String { + var description = "" + children.forEach { child in + description.append(child.recursiveDescription()) + description.append("\n") + } + return description + } + + var childGroupName: String { moduleName } + + private let moduleName: String + private(set) var children: [any SwiftInterfaceElement] + + init(moduleName: String, elements: [any SwiftInterfaceElement]) { + self.moduleName = moduleName + self.children = elements + + self.children = Self.mergeExtensions(for: self.children, moduleName: moduleName) + self.children.forEach { $0.setupParentRelationships(parent: self) } + } + + func differences(to otherElement: T) -> [String] { + return [] + } + + /// Attempting to merge extensions into their extended type to allow for better diffing + /// Independent extensions (without a where clause) are very hard to diff as the only information we have + /// is the extended type and there might be a lot of changes inside of the extensions between versions + static func mergeExtensions(for elements: [any SwiftInterfaceElement], moduleName: String) -> [any SwiftInterfaceElement] { + let extensions = elements.compactMap { $0 as? (SwiftInterfaceExtension & SwiftInterfaceElement) } + let extendableElements = elements.compactMap { $0 as? (SwiftInterfaceExtendableElement & SwiftInterfaceElement) } + let nonExtensions = elements.filter { !($0 is SwiftInterfaceExtension) } + + var adjustedElements: [any SwiftInterfaceElement] = nonExtensions + + extensions.forEach { extensionElement in + + // We want to merge all extensions that don't have a where clause into the extended type + guard extensionElement.genericWhereClauseDescription == nil else { + adjustedElements.append(extensionElement) + return + } + + if merge(extensionElement: extensionElement, with: extendableElements, prefix: moduleName) { + return // We found the matching extended element + } + + // We could not find the extended type so we add the extension to the list + adjustedElements.append(extensionElement) + } + + return adjustedElements + } + + /// Attempting to recursively merge an extension element with potential matches of extendable elements + /// The prefix provides the parent path as the types don't include it but the `extension.extendedType` does + static func merge( + extensionElement: any (SwiftInterfaceExtension & SwiftInterfaceElement), + with extendableElements: [any (SwiftInterfaceExtendableElement & SwiftInterfaceElement)], + prefix: String + ) -> Bool { + + if let extendedElement = extendableElements.first(where: { extensionElement.extendedType.hasPrefix("\(prefix).\($0.typeName)") }) { + + let extendedElementPrefix = "\(prefix).\(extendedElement.typeName)" + + // We found the extended type + if extendedElementPrefix == extensionElement.extendedType { + extendedElement.inheritance = (extendedElement.inheritance ?? []) + (extensionElement.inheritance ?? []) + extendedElement.children += extensionElement.children + return true + } + + // We're looking for the extended type inside of the children + let extendableChildren = extendedElement.children.compactMap { $0 as? (SwiftInterfaceExtendableElement & SwiftInterfaceElement) } + return merge(extensionElement: extensionElement, with: extendableChildren, prefix: extendedElementPrefix) + } + + return false + } + } +} diff --git a/Sources/Pipeline/Modules/SwiftInterfaceParser/SwiftInterfaceParser.swift b/Sources/Pipeline/Modules/SwiftInterfaceParser/SwiftInterfaceParser.swift index 7d92503..894d433 100644 --- a/Sources/Pipeline/Modules/SwiftInterfaceParser/SwiftInterfaceParser.swift +++ b/Sources/Pipeline/Modules/SwiftInterfaceParser/SwiftInterfaceParser.swift @@ -9,40 +9,6 @@ import SwiftParser */ class SwiftInterfaceParser: SyntaxVisitor, SwiftInterfaceParsing { - class Root: SwiftInterfaceElement { - - var parent: (any SwiftInterfaceElement)? = nil - - var diffableSignature: String { "" } - - var consolidatableName: String { "" } - - var description: String { - var description = "" - children.forEach { child in - description.append(child.recursiveDescription()) - description.append("\n") - } - return description - } - - var childGroupName: String { moduleName } - - private let moduleName: String - let children: [any SwiftInterfaceElement] - - init(moduleName: String, elements: [any SwiftInterfaceElement]) { - self.moduleName = moduleName - self.children = elements - - elements.forEach { $0.setupParentRelationships(parent: self) } - } - - func differences(to otherElement: T) -> [String] { - return [] - } - } - // TODO: Handle (Nice to have) // - DeinitializerDeclSyntax // - PrecedenceGroupDeclSyntax From 8f591dca923202b4b198248ee283c8185874ed02 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Mon, 7 Oct 2024 13:11:59 +0200 Subject: [PATCH 07/45] Fixing tests --- Sources/Helpers/XcodeTools.swift | 2 +- .../ReferencePackageTests.swift | 145 ++++++------ ...ference-changes-swift-interface-private.md | 206 +++++++++++++++--- ...eference-changes-swift-interface-public.md | 167 +++++++++++--- Tests/UnitTests/ProjectBuilderTests.swift | 12 +- .../SwiftPackageFileAnalyzerTests.swift | 18 +- Tests/UnitTests/XcodeToolsTests.swift | 6 +- Tests/public-api-diff.xctestplan | 15 -- 8 files changed, 405 insertions(+), 166 deletions(-) diff --git a/Sources/Helpers/XcodeTools.swift b/Sources/Helpers/XcodeTools.swift index bd85693..17d4347 100644 --- a/Sources/Helpers/XcodeTools.swift +++ b/Sources/Helpers/XcodeTools.swift @@ -66,7 +66,7 @@ struct XcodeTools { } // print("πŸ‘Ύ \(command.joined(separator: " "))") - logger?.log("πŸ—οΈ Building \(scheme) from \(projectDirectoryPath)", from: String(describing: Self.self)) + logger?.log("πŸ—οΈ Building \(scheme) from `\(projectDirectoryPath)`", from: String(describing: Self.self)) let result = shell.execute(command.joined(separator: " ")) if diff --git a/Tests/IntegrationTests/ReferencePackageTests.swift b/Tests/IntegrationTests/ReferencePackageTests.swift index 080c384..1df77a4 100644 --- a/Tests/IntegrationTests/ReferencePackageTests.swift +++ b/Tests/IntegrationTests/ReferencePackageTests.swift @@ -8,82 +8,57 @@ import XCTest class ReferencePackageTests: XCTestCase { - - func test_swiftInterface() async throws { - - // Unfortunately we can't use packages as Test Resources, so we put it in a `ReferencePackages` directory on root - guard let projectRoot = #file.replacingOccurrences(of: "relatve/path/to/file", with: "").split(separator: "/Tests/").first else { - XCTFail("Cannot find root directory") - return - } + + func test_swiftInterface_public() async throws { - let referencePackagesRoot = URL(filePath: String(projectRoot)).appending(path: "ReferencePackages") + let interfaceType: InterfaceType = .public - /* - let oldSourceContent = try content(atPath: "/Users/alexandergu/Downloads/AdyenPOS.xcframework/ios-arm64_x86_64-simulator/AdyenPOS.framework/Modules/AdyenPOS.swiftmodule/arm64-apple-ios-simulator.swiftinterface") - let newSourceContent = try content(atPath: "/Users/alexandergu/Downloads/AdyenPOS/AdyenPOS_3.2.0.xcframework/ios-arm64_x86_64-simulator/AdyenPOS.framework/Modules/AdyenPOS.swiftmodule/arm64-apple-ios-simulator.swiftinterface") - */ + let expectedOutput = try expectedOutput(for: interfaceType) + let pipelineOutput = try await runPipeline(for: interfaceType) - let oldPrivateSwiftInterfaceFilePath = try swiftInterfaceFilePath( - for: referencePackagesRoot, - packageName: "ReferencePackage", - interfaceType: .private + let markdownOutput = MarkdownOutputGenerator().generate( + from: pipelineOutput, + allTargets: ["ReferencePackage"], + oldSource: .local(path: "old_public"), + newSource: .local(path: "new_public"), + warnings: [] ) - let newPrivateSwiftInterfaceFilePath = try swiftInterfaceFilePath( - for: referencePackagesRoot, - packageName: "UpdatedPackage", - interfaceType: .private - ) + let expectedLines = sanitizeOutput(expectedOutput).components(separatedBy: "\n") + let markdownOutputLines = sanitizeOutput(markdownOutput).components(separatedBy: "\n") - let oldPublicSwiftInterfaceFilePath = try swiftInterfaceFilePath( - for: referencePackagesRoot, - packageName: "ReferencePackage", - interfaceType: .public - ) + for i in 0.. String { - let interfaceFileContent = try XCTUnwrap(FileManager.default.contents(atPath: path)) - return try XCTUnwrap(String(data: interfaceFileContent, encoding: .utf8)) + func runPipeline(for interfaceType: InterfaceType) async throws -> [String: [Change]] { + + // Unfortunately we can't use packages as Test Resources, so we put it in a `ReferencePackages` directory on root + guard let projectRoot = #file.replacingOccurrences(of: "relatve/path/to/file", with: "").split(separator: "/Tests/").first else { + struct CannotFindRootDirectoryError: Error {} + throw CannotFindRootDirectoryError() + } + + let referencePackagesRoot = URL(filePath: String(projectRoot)).appending(path: "ReferencePackages") + + let oldPrivateSwiftInterfaceFilePath = try swiftInterfaceFilePath( + for: referencePackagesRoot, + packageName: "ReferencePackage", + interfaceType: interfaceType + ) + + let newPrivateSwiftInterfaceFilePath = try swiftInterfaceFilePath( + for: referencePackagesRoot, + packageName: "UpdatedPackage", + interfaceType: interfaceType + ) + + return try await SwiftInterfacePipeline( + swiftInterfaceFiles: [ + .init( + name: "ReferencePackage", + oldFilePath: oldPrivateSwiftInterfaceFilePath, + newFilePath: newPrivateSwiftInterfaceFilePath + ) + ], + fileHandler: FileManager.default, + swiftInterfaceParser: SwiftInterfaceParser(), + swiftInterfaceAnalyzer: SwiftInterfaceAnalyzer(), + logger: PipelineLogger(logLevel: .debug) + ).run() } /// Removes the 2nd line that contains local file paths + empty newline at the end of the content if it exists diff --git a/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-private.md b/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-private.md index 0becb5f..30b1172 100644 --- a/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-private.md +++ b/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-private.md @@ -1,12 +1,11 @@ -# πŸ‘€ 57 public changes detected -_Comparing `/.../.../UpdatedPackage` to `/.../.../ReferencePackage`_ +# πŸ‘€ 54 public changes detected +_Comparing `new_private` to `old_private`_ --- ## `ReferencePackage` -### `ReferencePackage` #### ❇️ Added ```javascript -public enum RawValueEnum: Swift.String +public enum RawValueEnum: Swift.String, Swift.Equatable, Swift.Hashable, Swift.RawRepresentable { case one case two @@ -14,6 +13,7 @@ public enum RawValueEnum: Swift.String public typealias RawValue = Swift.String public var rawValue: Swift.String { get } } + ``` ```javascript public protocol ParentProtocol @@ -21,6 +21,7 @@ public protocol ParentProtocol associatedtype ParentType: Swift.Equatable where Self.ParentType == Self.Iterator.Element associatedtype Iterator: Swift.Collection } + ``` ```javascript public protocol ParentProtocol @@ -28,9 +29,11 @@ public protocol ParentProtocol associatedtype ParentType: Swift.Equatable where Self.ParentType == Self.Iterator.Element associatedtype Iterator: Swift.Collection } + ``` ```javascript public protocol SimpleProtocol + ``` #### πŸ”€ Changed ```javascript @@ -39,6 +42,11 @@ public protocol SimpleProtocol // To @_hasMissingDesignatedInitializers public actor CustomActor: ReferencePackage.SimpleProtocol + +/** +Changes: +- Added inheritance `ReferencePackage.SimpleProtocol` +*/ ``` ```javascript // From @@ -46,13 +54,25 @@ public protocol SimpleProtocol // To @_spi(SystemProgrammingInterface) open class OpenSpiConformingClass: ReferencePackage.CustomProtocol where T : Swift.Strideable + +/** +Changes: +- Added generic parameter description `` +- Added generic where clause `where T : Swift.Strideable` +*/ ``` ```javascript // From public enum CustomEnum // To -public enum CustomEnum +public enum CustomEnum: ReferencePackage.SimpleProtocol + +/** +Changes: +- Added generic parameter description `` +- Added inheritance `ReferencePackage.SimpleProtocol` +*/ ``` ```javascript // From @@ -60,6 +80,14 @@ public protocol CustomProtocol // To public protocol CustomProtocol: ReferencePackage.ParentProtocol where Self.ParentType == Swift.Double + +/** +Changes: +- Added generic where clause `where Self.ParentType == Swift.Double` +- Added inheritance `ReferencePackage.ParentProtocol` +- Added primary associated type `AnotherAssociatedType` +- Added primary associated type `CustomAssociatedType` +*/ ``` ```javascript // From @@ -67,26 +95,47 @@ public struct CustomStruct: ReferencePackage.CustomProtocol // To public struct CustomStruct: ReferencePackage.CustomProtocol where T : Swift.Strideable + +/** +Changes: +- Added generic parameter description `` +- Added generic where clause `where T : Swift.Strideable` +*/ ``` -### `ReferencePackage.CustomClass` +### `Array` +#### ❇️ Added +```javascript +extension Swift.Array +{ + public subscript(safe index: Swift.Int) -> Element? { get } +} + +``` +### `CustomClass` #### ❇️ Added ```javascript final public let a: Swift.Int + ``` ```javascript final public let b: Swift.Int + ``` ```javascript final public let c: Swift.Int + ``` ```javascript final public let d: Swift.Double + ``` ```javascript public subscript(index: Swift.Int) -> T? { get set } + ``` ```javascript public var lazyVar: Swift.String { get set } + ``` #### πŸ”€ Changed ```javascript @@ -95,6 +144,13 @@ public var lazyVar: Swift.String { get set } // To @_Concurrency.MainActor public func asyncThrowingFunc(_ element: Element) async throws -> Swift.Void where Element : Swift.Strideable + +/** +Changes: +- Added generic parameter description `` +- Added generic where clause `where Element : Swift.Strideable` +- Added parameter `_ element: Element` +*/ ``` ```javascript // From @@ -102,6 +158,11 @@ convenience public init(value: T) // To convenience public init!(value: T) + +/** +Changes: +- Added optional mark `!` +*/ ``` ```javascript // From @@ -109,42 +170,52 @@ public init() // To public init?() + +/** +Changes: +- Added optional mark `?` +*/ ``` -### `ReferencePackage.CustomEnum` +### `CustomEnum` #### ❇️ Added ```javascript case a + ``` ```javascript case b + ``` ```javascript case c + ``` ```javascript case caseWithNamedString(title: T) + ``` ```javascript case d + ``` ```javascript case e(ReferencePackage.CustomEnum.NestedStructInExtension) + ``` ```javascript extension ReferencePackage.CustomEnum where T == Swift.String { public var titleOfCaseWithNamedString: Swift.String? { get } } + ``` ```javascript -extension ReferencePackage.CustomEnum: ReferencePackage.SimpleProtocol +public struct NestedStructInExtension { - public struct NestedStructInExtension - { - public let string: Swift.String - public init(string: Swift.String = "Hello") - } + public let string: Swift.String + public init(string: Swift.String = "Hello") } + ``` #### πŸ”€ Changed ```javascript @@ -153,6 +224,14 @@ case caseWithTuple(Swift.String, Swift.Int) // To case caseWithTuple(_: Swift.String, bar: Swift.Int) + +/** +Changes: +- Added parameter `_: Swift.String` +- Added parameter `bar: Swift.Int` +- Removed parameter `Swift.Int` +- Removed parameter `Swift.String` +*/ ``` ```javascript // From @@ -160,24 +239,34 @@ indirect case recursive(ReferencePackage.CustomEnum) // To indirect case recursive(ReferencePackage.CustomEnum) + +/** +Changes: +- Added parameter `ReferencePackage.CustomEnum` +- Removed parameter `ReferencePackage.CustomEnum` +*/ ``` #### πŸ˜Άβ€πŸŒ«οΈ Removed ```javascript case caseWithString(Swift.String) ``` -### `ReferencePackage.CustomProtocol` +### `CustomProtocol` #### ❇️ Added ```javascript associatedtype AnotherAssociatedType: Swift.Strideable + ``` ```javascript associatedtype AnotherAssociatedType: Swift.Strideable + ``` ```javascript associatedtype CustomAssociatedType: Swift.Equatable + ``` ```javascript associatedtype CustomAssociatedType: Swift.Equatable + ``` #### πŸ”€ Changed ```javascript @@ -186,6 +275,11 @@ func function() -> any Swift.Equatable // To func function() -> Self.CustomAssociatedType + +/** +Changes: +- Changed return type from `any Swift.Equatable` to `Self.CustomAssociatedType` +*/ ``` ```javascript // From @@ -193,6 +287,11 @@ var getSetVar: any Swift.Equatable { get set } // To var getSetVar: Self.AnotherAssociatedType { get set } + +/** +Changes: +- Changed type from `any Swift.Equatable` to `Self.AnotherAssociatedType` +*/ ``` ```javascript // From @@ -200,12 +299,17 @@ var getVar: any Swift.Equatable { get } // To var getVar: Self.CustomAssociatedType { get } + +/** +Changes: +- Changed type from `any Swift.Equatable` to `Self.CustomAssociatedType` +*/ ``` #### πŸ˜Άβ€πŸŒ«οΈ Removed ```javascript typealias CustomAssociatedType = Swift.Equatable ``` -### `ReferencePackage.CustomStruct` +### `CustomStruct` #### ❇️ Added ```javascript @available(macOS, unavailable, message: "Unavailable on macOS") public struct NestedStruct @@ -213,18 +317,23 @@ typealias CustomAssociatedType = Swift.Equatable @available(*, deprecated, renamed: "nestedVar") public let nestedLet: Swift.String @available(swift 5.9) public let nestedVar: Swift.String } + ``` ```javascript public typealias AnotherAssociatedType = Swift.Double + ``` ```javascript public typealias CustomAssociatedType = Swift.Int + ``` ```javascript public typealias Iterator = Swift.Array.AnotherAssociatedType> + ``` ```javascript public typealias ParentType = Swift.Double + ``` #### πŸ”€ Changed ```javascript @@ -233,6 +342,11 @@ public typealias ParentType = Swift.Double // To @discardableResult public func function() -> Swift.Int + +/** +Changes: +- Changed return type from `any Swift.Equatable` to `Swift.Int` +*/ ``` ```javascript // From @@ -240,6 +354,11 @@ public var getSetVar: any Swift.Equatable // To public var getSetVar: Swift.Double + +/** +Changes: +- Changed type from `any Swift.Equatable` to `Swift.Double` +*/ ``` ```javascript // From @@ -247,17 +366,25 @@ public var getVar: any Swift.Equatable // To public var getVar: Swift.Int + +/** +Changes: +- Changed type from `any Swift.Equatable` to `Swift.Int` +*/ ``` -### `ReferencePackage.OpenSpiConformingClass` +### `OpenSpiConformingClass` #### ❇️ Added ```javascript @_spi(SystemProgrammingInterface) public typealias AnotherAssociatedType = T + ``` ```javascript @_spi(SystemProgrammingInterface) public typealias Iterator = Swift.Array + ``` ```javascript @_spi(SystemProgrammingInterface) public typealias ParentType = Swift.Double + ``` #### πŸ”€ Changed ```javascript @@ -266,6 +393,11 @@ public var getVar: Swift.Int // To @_spi(SystemProgrammingInterface) @inlinable public func function() -> T + +/** +Changes: +- Changed return type from `ReferencePackage.OpenSpiConformingClass.CustomAssociatedType` to `T` +*/ ``` ```javascript // From @@ -273,6 +405,14 @@ public var getVar: Swift.Int // To @_spi(SystemProgrammingInterface) public init(getSetVar: T, getVar: T) + +/** +Changes: +- Added parameter `getSetVar: T` +- Added parameter `getVar: T` +- Removed parameter `getSetVar: ReferencePackage.OpenSpiConformingClass.CustomAssociatedType` +- Removed parameter `getVar: ReferencePackage.OpenSpiConformingClass.CustomAssociatedType` +*/ ``` ```javascript // From @@ -280,6 +420,11 @@ public var getVar: Swift.Int // To @_spi(SystemProgrammingInterface) public typealias CustomAssociatedType = T + +/** +Changes: +- Changed assignment from `any Swift.Equatable` to `T` +*/ ``` ```javascript // From @@ -287,6 +432,11 @@ public var getVar: Swift.Int // To @_spi(SystemProgrammingInterface) public var getSetVar: T + +/** +Changes: +- Changed type from `ReferencePackage.OpenSpiConformingClass.CustomAssociatedType` to `T` +*/ ``` ```javascript // From @@ -294,25 +444,11 @@ public var getVar: Swift.Int // To @_spi(SystemProgrammingInterface) public var getVar: T -``` -### `ReferencePackage.RawValueEnum` -#### ❇️ Added -```javascript -extension ReferencePackage.RawValueEnum: Swift.Equatable -``` -```javascript -extension ReferencePackage.RawValueEnum: Swift.Hashable -``` -```javascript -extension ReferencePackage.RawValueEnum: Swift.RawRepresentable -``` -### `Swift.Array` -#### ❇️ Added -```javascript -extension Swift.Array -{ - public subscript(safe index: Swift.Int) -> Element? { get } -} + +/** +Changes: +- Changed type from `ReferencePackage.OpenSpiConformingClass.CustomAssociatedType` to `T` +*/ ``` --- diff --git a/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-public.md b/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-public.md index c2bcd47..6d8c8d7 100644 --- a/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-public.md +++ b/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-public.md @@ -1,12 +1,11 @@ -# πŸ‘€ 48 public changes detected -_Comparing `/.../.../UpdatedPackage` to `/.../.../ReferencePackage`_ +# πŸ‘€ 45 public changes detected +_Comparing `new_public` to `old_public`_ --- ## `ReferencePackage` -### `ReferencePackage` #### ❇️ Added ```javascript -public enum RawValueEnum: Swift.String +public enum RawValueEnum: Swift.String, Swift.Equatable, Swift.Hashable, Swift.RawRepresentable { case one case two @@ -14,6 +13,7 @@ public enum RawValueEnum: Swift.String public typealias RawValue = Swift.String public var rawValue: Swift.String { get } } + ``` ```javascript public protocol ParentProtocol @@ -21,6 +21,7 @@ public protocol ParentProtocol associatedtype ParentType: Swift.Equatable where Self.ParentType == Self.Iterator.Element associatedtype Iterator: Swift.Collection } + ``` ```javascript public protocol ParentProtocol @@ -28,9 +29,11 @@ public protocol ParentProtocol associatedtype ParentType: Swift.Equatable where Self.ParentType == Self.Iterator.Element associatedtype Iterator: Swift.Collection } + ``` ```javascript public protocol SimpleProtocol + ``` #### πŸ”€ Changed ```javascript @@ -39,13 +42,24 @@ public protocol SimpleProtocol // To @_hasMissingDesignatedInitializers public actor CustomActor: ReferencePackage.SimpleProtocol + +/** +Changes: +- Added inheritance `ReferencePackage.SimpleProtocol` +*/ ``` ```javascript // From public enum CustomEnum // To -public enum CustomEnum +public enum CustomEnum: ReferencePackage.SimpleProtocol + +/** +Changes: +- Added generic parameter description `` +- Added inheritance `ReferencePackage.SimpleProtocol` +*/ ``` ```javascript // From @@ -53,6 +67,14 @@ public protocol CustomProtocol // To public protocol CustomProtocol: ReferencePackage.ParentProtocol where Self.ParentType == Swift.Double + +/** +Changes: +- Added generic where clause `where Self.ParentType == Swift.Double` +- Added inheritance `ReferencePackage.ParentProtocol` +- Added primary associated type `AnotherAssociatedType` +- Added primary associated type `CustomAssociatedType` +*/ ``` ```javascript // From @@ -60,26 +82,47 @@ public struct CustomStruct: ReferencePackage.CustomProtocol // To public struct CustomStruct: ReferencePackage.CustomProtocol where T : Swift.Strideable + +/** +Changes: +- Added generic parameter description `` +- Added generic where clause `where T : Swift.Strideable` +*/ +``` +### `Array` +#### ❇️ Added +```javascript +extension Swift.Array +{ + public subscript(safe index: Swift.Int) -> Element? { get } +} + ``` -### `ReferencePackage.CustomClass` +### `CustomClass` #### ❇️ Added ```javascript final public let a: Swift.Int + ``` ```javascript final public let b: Swift.Int + ``` ```javascript final public let c: Swift.Int + ``` ```javascript final public let d: Swift.Double + ``` ```javascript public subscript(index: Swift.Int) -> T? { get set } + ``` ```javascript public var lazyVar: Swift.String { get set } + ``` #### πŸ”€ Changed ```javascript @@ -88,6 +131,13 @@ public var lazyVar: Swift.String { get set } // To @_Concurrency.MainActor public func asyncThrowingFunc(_ element: Element) async throws -> Swift.Void where Element : Swift.Strideable + +/** +Changes: +- Added generic parameter description `` +- Added generic where clause `where Element : Swift.Strideable` +- Added parameter `_ element: Element` +*/ ``` ```javascript // From @@ -95,6 +145,11 @@ convenience public init(value: T) // To convenience public init!(value: T) + +/** +Changes: +- Added optional mark `!` +*/ ``` ```javascript // From @@ -102,42 +157,52 @@ public init() // To public init?() + +/** +Changes: +- Added optional mark `?` +*/ ``` -### `ReferencePackage.CustomEnum` +### `CustomEnum` #### ❇️ Added ```javascript case a + ``` ```javascript case b + ``` ```javascript case c + ``` ```javascript case caseWithNamedString(title: T) + ``` ```javascript case d + ``` ```javascript case e(ReferencePackage.CustomEnum.NestedStructInExtension) + ``` ```javascript extension ReferencePackage.CustomEnum where T == Swift.String { public var titleOfCaseWithNamedString: Swift.String? { get } } + ``` ```javascript -extension ReferencePackage.CustomEnum: ReferencePackage.SimpleProtocol +public struct NestedStructInExtension { - public struct NestedStructInExtension - { - public let string: Swift.String - public init(string: Swift.String = "Hello") - } + public let string: Swift.String + public init(string: Swift.String = "Hello") } + ``` #### πŸ”€ Changed ```javascript @@ -146,6 +211,14 @@ case caseWithTuple(Swift.String, Swift.Int) // To case caseWithTuple(_: Swift.String, bar: Swift.Int) + +/** +Changes: +- Added parameter `_: Swift.String` +- Added parameter `bar: Swift.Int` +- Removed parameter `Swift.Int` +- Removed parameter `Swift.String` +*/ ``` ```javascript // From @@ -153,24 +226,34 @@ indirect case recursive(ReferencePackage.CustomEnum) // To indirect case recursive(ReferencePackage.CustomEnum) + +/** +Changes: +- Added parameter `ReferencePackage.CustomEnum` +- Removed parameter `ReferencePackage.CustomEnum` +*/ ``` #### πŸ˜Άβ€πŸŒ«οΈ Removed ```javascript case caseWithString(Swift.String) ``` -### `ReferencePackage.CustomProtocol` +### `CustomProtocol` #### ❇️ Added ```javascript associatedtype AnotherAssociatedType: Swift.Strideable + ``` ```javascript associatedtype AnotherAssociatedType: Swift.Strideable + ``` ```javascript associatedtype CustomAssociatedType: Swift.Equatable + ``` ```javascript associatedtype CustomAssociatedType: Swift.Equatable + ``` #### πŸ”€ Changed ```javascript @@ -179,6 +262,11 @@ func function() -> any Swift.Equatable // To func function() -> Self.CustomAssociatedType + +/** +Changes: +- Changed return type from `any Swift.Equatable` to `Self.CustomAssociatedType` +*/ ``` ```javascript // From @@ -186,6 +274,11 @@ var getSetVar: any Swift.Equatable { get set } // To var getSetVar: Self.AnotherAssociatedType { get set } + +/** +Changes: +- Changed type from `any Swift.Equatable` to `Self.AnotherAssociatedType` +*/ ``` ```javascript // From @@ -193,12 +286,17 @@ var getVar: any Swift.Equatable { get } // To var getVar: Self.CustomAssociatedType { get } + +/** +Changes: +- Changed type from `any Swift.Equatable` to `Self.CustomAssociatedType` +*/ ``` #### πŸ˜Άβ€πŸŒ«οΈ Removed ```javascript typealias CustomAssociatedType = Swift.Equatable ``` -### `ReferencePackage.CustomStruct` +### `CustomStruct` #### ❇️ Added ```javascript @available(macOS, unavailable, message: "Unavailable on macOS") public struct NestedStruct @@ -206,18 +304,23 @@ typealias CustomAssociatedType = Swift.Equatable @available(*, deprecated, renamed: "nestedVar") public let nestedLet: Swift.String @available(swift 5.9) public let nestedVar: Swift.String } + ``` ```javascript public typealias AnotherAssociatedType = Swift.Double + ``` ```javascript public typealias CustomAssociatedType = Swift.Int + ``` ```javascript public typealias Iterator = Swift.Array.AnotherAssociatedType> + ``` ```javascript public typealias ParentType = Swift.Double + ``` #### πŸ”€ Changed ```javascript @@ -226,6 +329,11 @@ public typealias ParentType = Swift.Double // To @discardableResult public func function() -> Swift.Int + +/** +Changes: +- Changed return type from `any Swift.Equatable` to `Swift.Int` +*/ ``` ```javascript // From @@ -233,6 +341,11 @@ public var getSetVar: any Swift.Equatable // To public var getSetVar: Swift.Double + +/** +Changes: +- Changed type from `any Swift.Equatable` to `Swift.Double` +*/ ``` ```javascript // From @@ -240,25 +353,11 @@ public var getVar: any Swift.Equatable // To public var getVar: Swift.Int -``` -### `ReferencePackage.RawValueEnum` -#### ❇️ Added -```javascript -extension ReferencePackage.RawValueEnum: Swift.Equatable -``` -```javascript -extension ReferencePackage.RawValueEnum: Swift.Hashable -``` -```javascript -extension ReferencePackage.RawValueEnum: Swift.RawRepresentable -``` -### `Swift.Array` -#### ❇️ Added -```javascript -extension Swift.Array -{ - public subscript(safe index: Swift.Int) -> Element? { get } -} + +/** +Changes: +- Changed type from `any Swift.Equatable` to `Swift.Int` +*/ ``` --- diff --git a/Tests/UnitTests/ProjectBuilderTests.swift b/Tests/UnitTests/ProjectBuilderTests.swift index 604a35d..7b08b7a 100644 --- a/Tests/UnitTests/ProjectBuilderTests.swift +++ b/Tests/UnitTests/ProjectBuilderTests.swift @@ -63,10 +63,18 @@ class ProjectBuilderTests: XCTestCase { return "" } } + + var expectedLogs: [(message: String, subsystem: String)] = [ + (message: "πŸ› οΈ Building project `\(localPath)` at\n`\(baseWorkingDirectoryPath)/\(randomString)`", subsystem: "ProjectBuilder"), + (message: "πŸ—οΈ Building _AllTargets from `\(baseWorkingDirectoryPath)/\(randomString)`", subsystem: "XcodeTools") + ] + var logger = MockLogger() logger.handleLog = { message, subsystem in - XCTAssertEqual(message, "πŸ› οΈ Building project `\(localPath)` at\n`\(baseWorkingDirectoryPath)/\(randomString)`") - XCTAssertEqual(subsystem, "ProjectBuilder") + let expectedLog = expectedLogs.first! + XCTAssertEqual(message, expectedLog.message) + XCTAssertEqual(subsystem, expectedLog.subsystem) + expectedLogs.removeFirst() } logger.handleDebug = { message, subsystem in XCTAssertEqual(message, "βœ… `\(localPath)` was built successfully") diff --git a/Tests/UnitTests/SwiftPackageFileAnalyzerTests.swift b/Tests/UnitTests/SwiftPackageFileAnalyzerTests.swift index e279c81..c43c7a8 100644 --- a/Tests/UnitTests/SwiftPackageFileAnalyzerTests.swift +++ b/Tests/UnitTests/SwiftPackageFileAnalyzerTests.swift @@ -31,11 +31,10 @@ class SwiftPackageFileAnalyzerTests: XCTestCase { return String(data: encodedPackageDescription, encoding: .utf8)! } - let xcodeTools = XcodeTools(shell: shell) - let projectAnalyzer = SwiftPackageFileAnalyzer( fileHandler: fileHandler, - xcodeTools: xcodeTools + shell: shell, + logger: nil ) let changes = try projectAnalyzer.analyze( @@ -84,9 +83,11 @@ class SwiftPackageFileAnalyzerTests: XCTestCase { return String(data: encodedPackageDescription, encoding: .utf8)! } - let xcodeTools = XcodeTools(shell: shell) - - let projectAnalyzer = SwiftPackageFileAnalyzer(fileHandler: fileHandler, xcodeTools: xcodeTools) + let projectAnalyzer = SwiftPackageFileAnalyzer( + fileHandler: fileHandler, + shell: shell, + logger: nil + ) let changes = try projectAnalyzer.analyze( oldProjectUrl: URL(filePath: "OldPackage"), @@ -111,7 +112,10 @@ class SwiftPackageFileAnalyzerTests: XCTestCase { handleFileExpectation.fulfill() return false // Package.swift file does not exist } - let projectAnalyzer = SwiftPackageFileAnalyzer(fileHandler: fileHandler) + let projectAnalyzer = SwiftPackageFileAnalyzer( + fileHandler: fileHandler, + logger: nil + ) let changes = try projectAnalyzer.analyze( oldProjectUrl: URL(filePath: "OldProject"), diff --git a/Tests/UnitTests/XcodeToolsTests.swift b/Tests/UnitTests/XcodeToolsTests.swift index 9e4e324..5c2cb57 100644 --- a/Tests/UnitTests/XcodeToolsTests.swift +++ b/Tests/UnitTests/XcodeToolsTests.swift @@ -22,7 +22,7 @@ class XcodeToolsTests: XCTestCase { return "" } - let xcodeTools = XcodeTools(shell: mockShell) + let xcodeTools = XcodeTools(shell: mockShell, logger: nil) xcodeTools.dumpSdk(projectDirectoryPath: projectDirectoryPath, module: module, outputFilePath: outputFilePath) } @@ -44,7 +44,7 @@ class XcodeToolsTests: XCTestCase { return true }) - let xcodeTools = XcodeTools(shell: mockShell, fileHandler: fileHandler) + let xcodeTools = XcodeTools(shell: mockShell, fileHandler: fileHandler, logger: nil) try xcodeTools.build(projectDirectoryPath: projectDirectoryPath, scheme: allTargetsLibraryName, isPackage: true) } @@ -59,7 +59,7 @@ class XcodeToolsTests: XCTestCase { return false }) - let xcodeTools = XcodeTools(shell: mockShell, fileHandler: fileHandler) + let xcodeTools = XcodeTools(shell: mockShell, fileHandler: fileHandler, logger: nil) do { try xcodeTools.build(projectDirectoryPath: projectDirectoryPath, scheme: allTargetsLibraryName, isPackage: true) XCTFail("Build should have failed") diff --git a/Tests/public-api-diff.xctestplan b/Tests/public-api-diff.xctestplan index 2d9ac7c..5e39246 100644 --- a/Tests/public-api-diff.xctestplan +++ b/Tests/public-api-diff.xctestplan @@ -52,21 +52,6 @@ } }, { - "enabled" : false, - "skippedTests" : [ - "ABIGeneratorTests", - "FileHandlingTests", - "GitTests", - "OutputGeneratorTests", - "PipelineTests", - "ProjectBuilderTests", - "ProjectSourceTests", - "SDKDumpAnalyzerTests", - "SDKDumpGeneratorTests", - "SDKDumpTests", - "SwiftPackageFileAnalyzerTests", - "XcodeToolsTests" - ], "target" : { "containerPath" : "container:", "identifier" : "UnitTests", From 637abd74627b59ebf0e3a73173d6ff8006c260b1 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Mon, 7 Oct 2024 13:47:20 +0200 Subject: [PATCH 08/45] Fixing integration tests --- Sources/Helpers/XcodeTools.swift | 2 +- .../ReferencePackageTests.swift | 52 +++++++++++++++---- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/Sources/Helpers/XcodeTools.swift b/Sources/Helpers/XcodeTools.swift index 17d4347..8f52a4d 100644 --- a/Sources/Helpers/XcodeTools.swift +++ b/Sources/Helpers/XcodeTools.swift @@ -15,7 +15,7 @@ struct XcodeToolsError: LocalizedError, CustomDebugStringConvertible { struct XcodeTools { - private enum Constants { + internal enum Constants { static let deviceTarget: String = "x86_64-apple-ios17.4-simulator" // TODO: Match the iOS version to the sdk static let derivedDataPath: String = ".build" static let simulatorSdkCommand = "xcrun --sdk iphonesimulator --show-sdk-path" diff --git a/Tests/IntegrationTests/ReferencePackageTests.swift b/Tests/IntegrationTests/ReferencePackageTests.swift index 1df77a4..fa56974 100644 --- a/Tests/IntegrationTests/ReferencePackageTests.swift +++ b/Tests/IntegrationTests/ReferencePackageTests.swift @@ -9,6 +9,34 @@ import XCTest class ReferencePackageTests: XCTestCase { + override func setUp() async throws { + + let referencePackagesRoot = try Self.referencePackagesPath() + let oldReferencePackageDirectory = referencePackagesRoot.appending(path: "ReferencePackage") + let newReferencePackageDirectory = referencePackagesRoot.appending(path: "UpdatedPackage") + + if + FileManager.default.fileExists(atPath: oldReferencePackageDirectory.appending(path: XcodeTools.Constants.derivedDataPath).path()), + FileManager.default.fileExists(atPath: newReferencePackageDirectory.appending(path: XcodeTools.Constants.derivedDataPath).path()) { + return // Nothing to build + } + + let xcodeTools = XcodeTools(logger: nil) + + _ = try await xcodeTools.archive(projectDirectoryPath: oldReferencePackageDirectory.path(), scheme: "ReferencePackage") + _ = try await xcodeTools.archive(projectDirectoryPath: newReferencePackageDirectory.path(), scheme: "ReferencePackage") + } + + override static func tearDown() { + + guard let referencePackagesRoot = try? Self.referencePackagesPath() else { return } + let oldReferencePackageDirectory = referencePackagesRoot.appending(path: "ReferencePackage").appending(path: XcodeTools.Constants.derivedDataPath) + let newReferencePackageDirectory = referencePackagesRoot.appending(path: "UpdatedPackage").appending(path: XcodeTools.Constants.derivedDataPath) + + try? FileManager.default.removeItem(at: oldReferencePackageDirectory) + try? FileManager.default.removeItem(at: newReferencePackageDirectory) + } + func test_swiftInterface_public() async throws { let interfaceType: InterfaceType = .public @@ -64,6 +92,16 @@ class ReferencePackageTests: XCTestCase { private extension ReferencePackageTests { + static func referencePackagesPath() throws -> URL { + // Unfortunately we can't use packages as Test Resources, so we put it in a `ReferencePackages` directory on root + guard let projectRoot = #file.replacingOccurrences(of: "relatve/path/to/file", with: "").split(separator: "/Tests/").first else { + struct CannotFindRootDirectoryError: Error {} + throw CannotFindRootDirectoryError() + } + + return URL(filePath: String(projectRoot)).appending(path: "ReferencePackages") + } + enum InterfaceType { case `public` case `private` @@ -80,9 +118,9 @@ private extension ReferencePackageTests { var interfaceFilePath: String { switch self { case .public: - "_build/Build/Products/Debug-iphoneos/ReferencePackage.swiftmodule/arm64-apple-ios.swiftinterface" + "\(XcodeTools.Constants.derivedDataPath)/Build/Products/Debug-iphoneos/ReferencePackage.swiftmodule/arm64-apple-ios.swiftinterface" case .private: - "_build/Build/Products/Debug-iphoneos/ReferencePackage.swiftmodule/arm64-apple-ios.private.swiftinterface" + "\(XcodeTools.Constants.derivedDataPath)/Build/Products/Debug-iphoneos/ReferencePackage.swiftmodule/arm64-apple-ios.private.swiftinterface" } } } @@ -100,14 +138,8 @@ private extension ReferencePackageTests { } func runPipeline(for interfaceType: InterfaceType) async throws -> [String: [Change]] { - - // Unfortunately we can't use packages as Test Resources, so we put it in a `ReferencePackages` directory on root - guard let projectRoot = #file.replacingOccurrences(of: "relatve/path/to/file", with: "").split(separator: "/Tests/").first else { - struct CannotFindRootDirectoryError: Error {} - throw CannotFindRootDirectoryError() - } - - let referencePackagesRoot = URL(filePath: String(projectRoot)).appending(path: "ReferencePackages") + + let referencePackagesRoot = try Self.referencePackagesPath() let oldPrivateSwiftInterfaceFilePath = try swiftInterfaceFilePath( for: referencePackagesRoot, From 6fc4ffba8ee9d6e9d4667b2cc4488c037f9cf132 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Mon, 7 Oct 2024 14:25:30 +0200 Subject: [PATCH 09/45] Fixing file name --- Sources/public-api-diff.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/public-api-diff.swift b/Sources/public-api-diff.swift index 7d55b19..0fb4715 100644 --- a/Sources/public-api-diff.swift +++ b/Sources/public-api-diff.swift @@ -144,7 +144,7 @@ private extension PublicApiDiff { switch projectType { case .swiftPackage: archiveScheme = "_AllTargets" - let packageFileHelper = PackageFileHelper(fileHandler: fileHandler, xcodeTools: xcodeTools) + let packageFileHelper = SwiftPackageFileHelper(fileHandler: fileHandler, xcodeTools: xcodeTools) try packageFileHelper .preparePackageWithConsolidatedLibrary(named: archiveScheme, at: newProjectDirectoryPath) try packageFileHelper From 7a0bcd5513ef729a3122b0859e96490a7c52c28c Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Tue, 8 Oct 2024 17:24:56 +0200 Subject: [PATCH 10/45] Simplifying and fixing logic --- Sources/Helpers/LogFileLogger.swift | 38 +++ Sources/Helpers/LoggingGroup.swift | 27 ++ .../VarDeclSyntax+SwiftInterface.swift | 12 +- .../SwiftInterfaceElement+Var.swift | 4 +- Sources/Helpers/SwiftInterfaceType.swift | 31 +++ ...ipelineLogger.swift => SystemLogger.swift} | 4 +- Sources/Helpers/XcodeTools.swift | 46 +++- Sources/Pipeline/Modules/ProjectBuilder.swift | 2 +- .../Modules/SwiftInterfaceFileLocator.swift | 31 ++- Sources/Pipeline/Pipeline+Protocols.swift | 1 - Sources/Pipeline/SwiftInterfacePipeline.swift | 1 + Sources/public-api-diff.swift | 255 ++++++++++++------ 12 files changed, 332 insertions(+), 120 deletions(-) create mode 100644 Sources/Helpers/LogFileLogger.swift create mode 100644 Sources/Helpers/LoggingGroup.swift create mode 100644 Sources/Helpers/SwiftInterfaceType.swift rename Sources/Helpers/{PipelineLogger.swift => SystemLogger.swift} (93%) diff --git a/Sources/Helpers/LogFileLogger.swift b/Sources/Helpers/LogFileLogger.swift new file mode 100644 index 0000000..52ac51f --- /dev/null +++ b/Sources/Helpers/LogFileLogger.swift @@ -0,0 +1,38 @@ +// +// File.swift +// +// +// Created by Alexander Guretzki on 08/10/2024. +// + +import Foundation + +class LogFileLogger: Logging { + + private let fileHandler: any FileHandling + private let outputFilePath: String + + @MainActor + private var output: [String] = [] { + didSet { + try? fileHandler.write(output.joined(separator: "\n"), to: outputFilePath) + } + } + + init(fileHandler: any FileHandling, outputFilePath: String) { + self.fileHandler = fileHandler + self.outputFilePath = outputFilePath + } + + func log(_ message: String, from subsystem: String) { + Task { @MainActor in + output += ["[\(subsystem)] \(message)\n"] + } + } + + func debug(_ message: String, from subsystem: String) { + Task { @MainActor in + output += ["[\(subsystem)] \(message)\n"] + } + } +} diff --git a/Sources/Helpers/LoggingGroup.swift b/Sources/Helpers/LoggingGroup.swift new file mode 100644 index 0000000..3a7c4b5 --- /dev/null +++ b/Sources/Helpers/LoggingGroup.swift @@ -0,0 +1,27 @@ +// +// File.swift +// +// +// Created by Alexander Guretzki on 08/10/2024. +// + +import Foundation + +struct LoggingGroup: Logging { + + let logger: [any Logging] + + init(with logger: [any Logging]) { + self.logger = logger + } + + @MainActor + func log(_ message: String, from subsystem: String) { + logger.forEach { $0.log(message, from: subsystem) } + } + + @MainActor + func debug(_ message: String, from subsystem: String) { + logger.forEach { $0.debug(message, from: subsystem) } + } +} diff --git a/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/VarDeclSyntax+SwiftInterface.swift b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/VarDeclSyntax+SwiftInterface.swift index e81a9b0..4f720b6 100644 --- a/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/VarDeclSyntax+SwiftInterface.swift +++ b/Sources/Helpers/Models/SwiftInterface/DeclSyntax+SwiftInterface/VarDeclSyntax+SwiftInterface.swift @@ -9,7 +9,7 @@ extension VariableDeclSyntax { let declarationAttributes = self.attributes.sanitizedList let modifiers = self.modifiers.sanitizedList let bindingSpecifier = self.bindingSpecifier.trimmedDescription - + // Transforming: // - final public let a = 0, b = 1, c: Double = 5.0 // Into: @@ -17,14 +17,20 @@ extension VariableDeclSyntax { // - final public let b: Int = 1 // - final public let c: Double = 5.0 return bindings.map { + var accessors = $0.accessorBlock?.sanitizedDescription + if accessors == nil, bindingSpecifier == "let" { + // If the accessors are missing and we have a let we can assume it's get only + accessors = "get" + } + return SwiftInterfaceVar( attributes: declarationAttributes, modifiers: modifiers, bindingSpecifier: bindingSpecifier, name: $0.pattern.trimmedDescription, - typeAnnotation: $0.typeAnnotation?.type.trimmedDescription, + typeAnnotation: $0.typeAnnotation?.type.trimmedDescription ?? "UNKNOWN_TYPE", initializerValue: $0.initializer?.value.trimmedDescription, - accessors: $0.accessorBlock?.sanitizedDescription + accessors: accessors ) } } diff --git a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Var.swift b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Var.swift index e1703c6..3a289ac 100644 --- a/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Var.swift +++ b/Sources/Helpers/Models/SwiftInterface/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Var.swift @@ -42,7 +42,7 @@ class SwiftInterfaceVar: SwiftInterfaceElement { modifiers: [String], bindingSpecifier: String, name: String, - typeAnnotation: String?, + typeAnnotation: String, initializerValue: String?, accessors: String? ) { @@ -50,7 +50,7 @@ class SwiftInterfaceVar: SwiftInterfaceElement { self.modifiers = modifiers self.bindingSpecifier = bindingSpecifier self.name = name - self.typeAnnotation = typeAnnotation ?? "UNKNOWN_TYPE" + self.typeAnnotation = typeAnnotation self.initializerValue = initializerValue self.accessors = accessors } diff --git a/Sources/Helpers/SwiftInterfaceType.swift b/Sources/Helpers/SwiftInterfaceType.swift new file mode 100644 index 0000000..72a526c --- /dev/null +++ b/Sources/Helpers/SwiftInterfaceType.swift @@ -0,0 +1,31 @@ +// +// File.swift +// +// +// Created by Alexander Guretzki on 08/10/2024. +// + +import Foundation +import ArgumentParser + +enum SwiftInterfaceType { + case `private` + case `public` + + var name: String { + switch self { + case .private: "private" + case .public: "public" + } + } +} + +extension SwiftInterfaceType: ExpressibleByArgument { + init?(argument: String) { + switch argument { + case "private": self = .private + case "public": self = .public + default: return nil + } + } +} diff --git a/Sources/Helpers/PipelineLogger.swift b/Sources/Helpers/SystemLogger.swift similarity index 93% rename from Sources/Helpers/PipelineLogger.swift rename to Sources/Helpers/SystemLogger.swift index 55d3e0a..32c9da0 100644 --- a/Sources/Helpers/PipelineLogger.swift +++ b/Sources/Helpers/SystemLogger.swift @@ -7,7 +7,7 @@ import Foundation import OSLog -struct PipelineLogger: Logging { +struct SystemLogger: Logging { private let logLevel: LogLevel @@ -40,7 +40,7 @@ struct PipelineLogger: Logging { } } -private extension PipelineLogger { +private extension SystemLogger { func logger(for subsystem: String) -> Logger { Logger( diff --git a/Sources/Helpers/XcodeTools.swift b/Sources/Helpers/XcodeTools.swift index 8f52a4d..0b13898 100644 --- a/Sources/Helpers/XcodeTools.swift +++ b/Sources/Helpers/XcodeTools.swift @@ -49,9 +49,9 @@ struct XcodeTools { func build( projectDirectoryPath: String, scheme: String, - isPackage: Bool + projectType: ProjectType ) throws { - var command = [ + var commandComponents = [ "cd \(projectDirectoryPath);", "xcodebuild -scheme \"\(scheme)\"", "-derivedDataPath \(Constants.derivedDataPath)", @@ -59,15 +59,18 @@ struct XcodeTools { "-destination \"platform=iOS,name=Any iOS Device\"" ] - if isPackage { - command += [ - "-skipPackagePluginValidation" - ] + switch projectType { + case .swiftPackage: + commandComponents += ["-skipPackagePluginValidation"] + case .xcodeProject: + break // Nothing to add } + let command = commandComponents.joined(separator: " ") + // print("πŸ‘Ύ \(command.joined(separator: " "))") logger?.log("πŸ—οΈ Building \(scheme) from `\(projectDirectoryPath)`", from: String(describing: Self.self)) - let result = shell.execute(command.joined(separator: " ")) + let result = shell.execute(command) if !fileHandler.fileExists(atPath: "\(projectDirectoryPath)/\(Constants.derivedDataPath)") || @@ -84,24 +87,43 @@ struct XcodeTools { func archive( projectDirectoryPath: String, - scheme: String + scheme: String, + projectType: ProjectType ) async throws -> String { - let command = "cd \(projectDirectoryPath); xcodebuild clean build -scheme \"\(scheme)\" -destination \"generic/platform=iOS\" -derivedDataPath \(Constants.derivedDataPath) -sdk `xcrun --sdk iphonesimulator --show-sdk-path` BUILD_LIBRARY_FOR_DISTRIBUTION=YES" + let derivedDataPath = "\(projectDirectoryPath)/\(Constants.derivedDataPath)" + + var commandComponents = [ + "cd \(projectDirectoryPath);", + "xcodebuild clean build -scheme \"\(scheme)\"", + "-sdk `\(Constants.simulatorSdkCommand)`", + "-derivedDataPath \(derivedDataPath)", + "-destination \"generic/platform=iOS\"", + "SKIP_INSTALL=NO", + "BUILD_LIBRARY_FOR_DISTRIBUTION=YES", + ] + + switch projectType { + case .swiftPackage: + commandComponents += ["-skipPackagePluginValidation"] + case .xcodeProject: + break // Nothing to add + } + + let command = commandComponents.joined(separator: " ") return try await Task { logger?.log("πŸ“¦ Archiving \(scheme) from \(projectDirectoryPath)", from: String(describing: Self.self)) let result = shell.execute(command) - let derivedDataPath = "\(projectDirectoryPath)/\(Constants.derivedDataPath)" - // It might be that the archive failed but the .swiftinterface files are still created // so we have to check outside if they exist. // // Also see: https://github.com/swiftlang/swift/issues/56573 - if !fileHandler.fileExists(atPath: derivedDataPath) { + guard fileHandler.fileExists(atPath: derivedDataPath) else { print(result) + throw XcodeToolsError( errorDescription: "πŸ’₯ Building project failed", underlyingError: result diff --git a/Sources/Pipeline/Modules/ProjectBuilder.swift b/Sources/Pipeline/Modules/ProjectBuilder.swift index 6489f64..0c3b621 100644 --- a/Sources/Pipeline/Modules/ProjectBuilder.swift +++ b/Sources/Pipeline/Modules/ProjectBuilder.swift @@ -193,7 +193,7 @@ private extension ProjectBuilder { try xcodeTools.build( projectDirectoryPath: projectDirectoryPath, scheme: schemeToBuild, - isPackage: scheme == nil + projectType: scheme == nil ? .swiftPackage : .xcodeProject ) logger?.debug("βœ… `\(description)` was built successfully", from: String(describing: Self.self)) } catch { diff --git a/Sources/Pipeline/Modules/SwiftInterfaceFileLocator.swift b/Sources/Pipeline/Modules/SwiftInterfaceFileLocator.swift index d992977..d61b926 100644 --- a/Sources/Pipeline/Modules/SwiftInterfaceFileLocator.swift +++ b/Sources/Pipeline/Modules/SwiftInterfaceFileLocator.swift @@ -2,29 +2,29 @@ import Foundation struct SwiftInterfaceFileLocator { - enum SwiftInterfaceType { - case `private` - case `public` - } - let fileHandler: any FileHandling let shell: any ShellHandling + let logger: (any Logging)? init( fileHandler: any FileHandling = FileManager.default, - shell: any ShellHandling = Shell() + shell: any ShellHandling = Shell(), + logger: (any Logging)? ) { self.fileHandler = fileHandler self.shell = shell + self.logger = logger } - func locate(for scheme: String, derivedDataPath: String, type: SwiftInterfaceType) throws -> [URL] { - let swiftModulePaths = shell.execute("cd '\(derivedDataPath)'; find . -type d -name '\(scheme).swiftmodule'") + func locate(for scheme: String, derivedDataPath: String, type: SwiftInterfaceType) throws -> URL { + let schemeSwiftModuleName = "\(scheme).swiftmodule" + + let swiftModulePathsForScheme = shell.execute("cd '\(derivedDataPath)'; find . -type d -name '\(schemeSwiftModuleName)'") .components(separatedBy: .newlines) .map { URL(filePath: $0) } - guard let swiftModulePath = swiftModulePaths.first?.path() else { - throw FileHandlerError.pathDoesNotExist(path: "find . -type d -name '\(scheme).swiftmodule'") + guard let swiftModulePath = swiftModulePathsForScheme.first?.path() else { + throw FileHandlerError.pathDoesNotExist(path: "find . -type d -name '\(schemeSwiftModuleName)'") // TODO: Better error } let completeSwiftModulePath = derivedDataPath + "/" + swiftModulePath @@ -39,6 +39,15 @@ struct SwiftInterfaceFileLocator { swiftInterfacePaths = swiftModuleContent.filter { $0.hasSuffix(".swiftinterface") && !$0.hasSuffix(".private.swiftinterface") } } - return swiftInterfacePaths.map { URL(filePath: "\(completeSwiftModulePath)/\($0)") } + guard let swiftInterfacePath = swiftInterfacePaths.first else { + switch type { + case .private: + throw FileHandlerError.pathDoesNotExist(path: "'\(scheme).private.swiftinterface'") // TODO: Better error + case .public: + throw FileHandlerError.pathDoesNotExist(path: "'\(scheme).swiftinterface'") // TODO: Better error + } + } + + return URL(filePath: "\(completeSwiftModulePath)/\(swiftInterfacePath)") } } diff --git a/Sources/Pipeline/Pipeline+Protocols.swift b/Sources/Pipeline/Pipeline+Protocols.swift index 454d36f..018e019 100644 --- a/Sources/Pipeline/Pipeline+Protocols.swift +++ b/Sources/Pipeline/Pipeline+Protocols.swift @@ -75,7 +75,6 @@ enum LogLevel { protocol Logging { - init(logLevel: LogLevel) func log(_ message: String, from subsystem: String) func debug(_ message: String, from subsystem: String) } diff --git a/Sources/Pipeline/SwiftInterfacePipeline.swift b/Sources/Pipeline/SwiftInterfacePipeline.swift index 68a4a2c..c763cef 100644 --- a/Sources/Pipeline/SwiftInterfacePipeline.swift +++ b/Sources/Pipeline/SwiftInterfacePipeline.swift @@ -41,6 +41,7 @@ struct SwiftInterfacePipeline { var changes = [String: [Change]]() try swiftInterfaceFiles.forEach { file in + logger?.log("πŸ§‘β€πŸ”¬ Analyzing \(file.name)", from: String(describing: Self.self)) let newContent = try fileHandler.loadString(from: file.newFilePath) let oldContent = try fileHandler.loadString(from: file.oldFilePath) let newParsed = swiftInterfaceParser.parse(source: newContent, moduleName: file.name) diff --git a/Sources/public-api-diff.swift b/Sources/public-api-diff.swift index 0fb4715..03b90d4 100644 --- a/Sources/public-api-diff.swift +++ b/Sources/public-api-diff.swift @@ -19,85 +19,102 @@ struct PublicApiDiff: AsyncParsableCommand { @Option(help: "Where to output the result (File path)") public var output: String? + @Option(help: "Where to output the logs (File path)") + public var logOutput: String? + @Option(help: "Which scheme to build (Needed when comparing 2 swift frameworks)") public var scheme: String? public func run() async throws { let fileHandler: FileHandling = FileManager.default - let oldSource = try ProjectSource.from(old, fileHandler: fileHandler) - let newSource = try ProjectSource.from(new, fileHandler: fileHandler) - let logger: any Logging = PipelineLogger(logLevel: .debug) // LogLevel should be provided by a parameter - let xcodeTools = XcodeTools(logger: logger) - logger.log("Comparing `\(newSource.description)` to `\(oldSource.description)`", from: "Main") - - let currentDirectory = fileHandler.currentDirectoryPath - let workingDirectoryPath = currentDirectory.appending("/tmp-public-api-diff") - - // MARK: - Generate the .swiftinterface files on the fly (optional) - // TODO: Allow passing of .swiftinterface files - - let projectType: ProjectType = .swiftPackage - let swiftInterfaceType: SwiftInterfaceFileLocator.SwiftInterfaceType = .public - - let (oldProjectUrl, newProjectUrl) = try await setupProject( - oldSource: oldSource, - newSource: newSource, - workingDirectoryPath: workingDirectoryPath, - projectType: projectType, - logger: logger - ) - - let swiftInterfaceFiles = try await generateSwiftInterfaceFiles( - newProjectUrl: newProjectUrl, - oldProjectUrl: oldProjectUrl, - projectType: projectType, - swiftInterfaceType: swiftInterfaceType, - workingDirectoryPath: workingDirectoryPath, - fileHandler: fileHandler, - xcodeTools: xcodeTools, - logger: logger - ) - - // MARK: - Analyze .swiftinterface files - - var changes = try await SwiftInterfacePipeline( - swiftInterfaceFiles: swiftInterfaceFiles, - fileHandler: fileHandler, - swiftInterfaceParser: SwiftInterfaceParser(), - swiftInterfaceAnalyzer: SwiftInterfaceAnalyzer(), - logger: logger - ).run() - - // MARK: - Analyze Package.swift (optional) - - let swiftPackageFileAnalyzer = SwiftPackageFileAnalyzer(logger: logger) - let swiftPackageAnalysis = try swiftPackageFileAnalyzer.analyze( - oldProjectUrl: oldProjectUrl, - newProjectUrl: newProjectUrl - ) - - if !swiftPackageAnalysis.changes.isEmpty { - changes["Package.swift"] = swiftPackageAnalysis.changes + var loggers = [any Logging]() + if let logOutput { + loggers += [LogFileLogger(fileHandler: fileHandler, outputFilePath: logOutput)] } + loggers += [SystemLogger(logLevel: .debug)] // LogLevel should be provided by a parameter - let allTargets = swiftInterfaceFiles.map(\.name) - - // MARK: - Generate Output (optional) + let logger: any Logging = LoggingGroup(with: loggers) - let markdownOutput = MarkdownOutputGenerator().generate( - from: changes, - allTargets: allTargets.sorted(), - oldSource: oldSource, - newSource: newSource, - warnings: swiftPackageAnalysis.warnings - ) - - if let output { - try fileHandler.write(markdownOutput, to: output) - } else { - // We're not using a logger here as we always want to have it printed if no output was specified - print(markdownOutput) + do { + let oldSource = try ProjectSource.from(old, fileHandler: fileHandler) + let newSource = try ProjectSource.from(new, fileHandler: fileHandler) + + let xcodeTools = XcodeTools(logger: logger) + logger.log("Comparing `\(newSource.description)` to `\(oldSource.description)`", from: "Main") + + let currentDirectory = fileHandler.currentDirectoryPath + let workingDirectoryPath = currentDirectory.appending("/tmp-public-api-diff") + + // MARK: - Generate the .swiftinterface files on the fly (optional) + // TODO: Allow passing of .swiftinterface files + + let projectType: ProjectType = .swiftPackage + let swiftInterfaceType: SwiftInterfaceType = .public + + let (oldProjectUrl, newProjectUrl) = try await setupProject( + oldSource: oldSource, + newSource: newSource, + workingDirectoryPath: workingDirectoryPath, + projectType: projectType, + logger: logger + ) + + let swiftInterfaceFiles = try await generateSwiftInterfaceFiles( + newProjectUrl: newProjectUrl, + oldProjectUrl: oldProjectUrl, + projectType: projectType, + swiftInterfaceType: swiftInterfaceType, + workingDirectoryPath: workingDirectoryPath, + fileHandler: fileHandler, + xcodeTools: xcodeTools, + logger: logger + ) + + // MARK: - Analyze .swiftinterface files + + var changes = try await SwiftInterfacePipeline( + swiftInterfaceFiles: swiftInterfaceFiles, + fileHandler: fileHandler, + swiftInterfaceParser: SwiftInterfaceParser(), + swiftInterfaceAnalyzer: SwiftInterfaceAnalyzer(), + logger: logger + ).run() + + // MARK: - Analyze Package.swift (optional) + + let swiftPackageFileAnalyzer = SwiftPackageFileAnalyzer(logger: logger) + let swiftPackageAnalysis = try swiftPackageFileAnalyzer.analyze( + oldProjectUrl: oldProjectUrl, + newProjectUrl: newProjectUrl + ) + + if !swiftPackageAnalysis.changes.isEmpty { + changes["Package.swift"] = swiftPackageAnalysis.changes + } + + let allTargets = swiftInterfaceFiles.map(\.name) + + // MARK: - Generate Output (optional) + + let markdownOutput = MarkdownOutputGenerator().generate( + from: changes, + allTargets: allTargets.sorted(), + oldSource: oldSource, + newSource: newSource, + warnings: swiftPackageAnalysis.warnings + ) + + if let output { + try fileHandler.write(markdownOutput, to: output) + } else { + // We're not using a logger here as we always want to have it printed if no output was specified + print(markdownOutput) + } + + logger.log("βœ… Success", from: "Main") + } catch { + logger.log("πŸ’₯ \(error.localizedDescription)", from: "Main") } } } @@ -128,7 +145,7 @@ private extension PublicApiDiff { newProjectUrl: URL, oldProjectUrl: URL, projectType: ProjectType, - swiftInterfaceType: SwiftInterfaceFileLocator.SwiftInterfaceType, + swiftInterfaceType: SwiftInterfaceType, workingDirectoryPath: String, fileHandler: any FileHandling, xcodeTools: XcodeTools, @@ -138,6 +155,38 @@ private extension PublicApiDiff { let newProjectDirectoryPath = newProjectUrl.path() let oldProjectDirectoryPath = oldProjectUrl.path() + let (archiveScheme, schemesToCompare) = try prepareProjectsForArchiving( + newProjectDirectoryPath: newProjectDirectoryPath, + oldProjectDirectoryPath: oldProjectDirectoryPath, + projectType: projectType, + fileHandler: fileHandler, + xcodeTools: xcodeTools + ) + + let (newDerivedDataPath, oldDerivedDataPath) = try await archiveProjects( + newProjectDirectoryPath: newProjectDirectoryPath, + oldProjectDirectoryPath: oldProjectDirectoryPath, + scheme: archiveScheme, + projectType: projectType, + xcodeTools: xcodeTools + ) + + return try locateInterfaceFiles( + newDerivedDataPath: newDerivedDataPath, + oldDerivedDataPath: oldDerivedDataPath, + schemes: schemesToCompare, + swiftInterfaceType: swiftInterfaceType, + logger: logger + ) + } + + func prepareProjectsForArchiving( + newProjectDirectoryPath: String, + oldProjectDirectoryPath: String, + projectType: ProjectType, + fileHandler: any FileHandling, + xcodeTools: XcodeTools + ) throws -> (archiveScheme: String, schemesToCompare: [String]) { // TODO: Typed return type let archiveScheme: String let schemesToCompare: [String] @@ -153,7 +202,11 @@ private extension PublicApiDiff { let newTargets = try Set(packageFileHelper.availableTargets(at: newProjectDirectoryPath)) let oldTargets = try Set(packageFileHelper.availableTargets(at: oldProjectDirectoryPath)) - schemesToCompare = newTargets.intersection(oldTargets).sorted() // TODO: Handle added/removed targets + schemesToCompare = newTargets.intersection(oldTargets).sorted() + + if schemesToCompare.isEmpty { + throw PipelineError.noTargetFound + } case .xcodeProject: guard let scheme else { @@ -163,26 +216,52 @@ private extension PublicApiDiff { schemesToCompare = [scheme] } - async let asyncNewDerivedDataPath = try xcodeTools.archive(projectDirectoryPath: newProjectDirectoryPath, scheme: archiveScheme) - async let asyncOldDerivedDataPath = try xcodeTools.archive(projectDirectoryPath: oldProjectDirectoryPath, scheme: archiveScheme) + return (archiveScheme, schemesToCompare) + } + + func archiveProjects( + newProjectDirectoryPath: String, + oldProjectDirectoryPath: String, + scheme: String, + projectType: ProjectType, + xcodeTools: XcodeTools + ) async throws -> (newDerivedDataPath: String, oldDerivedDataPath: String) { // TODO: Typed return type + async let asyncNewDerivedDataPath = try xcodeTools.archive( + projectDirectoryPath: newProjectDirectoryPath, + scheme: scheme, + projectType: projectType + ) + async let asyncOldDerivedDataPath = try xcodeTools.archive( + projectDirectoryPath: oldProjectDirectoryPath, + scheme: scheme, + projectType: projectType + ) + + return try await (asyncNewDerivedDataPath, asyncOldDerivedDataPath) + } + + func locateInterfaceFiles( + newDerivedDataPath: String, + oldDerivedDataPath: String, + schemes schemesToCompare: [String], + swiftInterfaceType: SwiftInterfaceType, + logger: (any Logging)? + ) throws -> [SwiftInterfacePipeline.SwiftInterfaceFile] { + logger?.log("πŸ”Ž Locating interface files for \(schemesToCompare.joined(separator: ", "))", from: "Main") - let newDerivedDataPath = try await asyncNewDerivedDataPath - let oldDerivedDataPath = try await asyncOldDerivedDataPath + // TODO: Ideally concatenate all .swiftinterface files so all the information is in one file + // and cross-module extensions can be applied correctly - return try schemesToCompare.compactMap { scheme in - // Locating swift interface files - let interfaceFileLocator = SwiftInterfaceFileLocator() - let newSwiftInterfacePaths = try interfaceFileLocator.locate(for: scheme, derivedDataPath: newDerivedDataPath, type: swiftInterfaceType) - let oldSwiftInterfacePaths = try interfaceFileLocator.locate(for: scheme, derivedDataPath: oldDerivedDataPath, type: swiftInterfaceType) - - guard - let oldFilePath = oldSwiftInterfacePaths.first?.path(), - let newFilePath = newSwiftInterfacePaths.first?.path() - else { + let interfaceFileLocator = SwiftInterfaceFileLocator(logger: logger) + return schemesToCompare.compactMap { scheme in + do { + let newSwiftInterfaceUrl = try interfaceFileLocator.locate(for: scheme, derivedDataPath: newDerivedDataPath, type: swiftInterfaceType) + let oldSwiftInterfaceUrl = try interfaceFileLocator.locate(for: scheme, derivedDataPath: oldDerivedDataPath, type: swiftInterfaceType) + return .init(name: scheme, oldFilePath: oldSwiftInterfaceUrl.path(), newFilePath: newSwiftInterfaceUrl.path()) + } catch { + logger?.log("πŸ‘» \(error.localizedDescription)", from: "Main") return nil } - - return .init(name: scheme, oldFilePath: oldFilePath, newFilePath: newFilePath) } } } From 26ff0728adb892d383234ab49ea5399d91b3256e Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Wed, 9 Oct 2024 10:30:43 +0200 Subject: [PATCH 11/45] fixing dependency resolving --- Sources/Helpers/LogFileLogger.swift | 4 ++-- Sources/Helpers/LoggingGroup.swift | 6 +++++- Sources/Helpers/SystemLogger.swift | 26 ++++++----------------- Sources/Helpers/XcodeTools.swift | 13 ++++++------ Sources/Pipeline/Pipeline+Protocols.swift | 22 +++++++++++++++++++ Sources/public-api-diff.swift | 9 +++++--- 6 files changed, 47 insertions(+), 33 deletions(-) diff --git a/Sources/Helpers/LogFileLogger.swift b/Sources/Helpers/LogFileLogger.swift index 52ac51f..564a5e8 100644 --- a/Sources/Helpers/LogFileLogger.swift +++ b/Sources/Helpers/LogFileLogger.swift @@ -26,13 +26,13 @@ class LogFileLogger: Logging { func log(_ message: String, from subsystem: String) { Task { @MainActor in - output += ["[\(subsystem)] \(message)\n"] + output += ["πŸͺ΅ [\(subsystem)] \(message)\n"] } } func debug(_ message: String, from subsystem: String) { Task { @MainActor in - output += ["[\(subsystem)] \(message)\n"] + output += ["🐞 [\(subsystem)] \(message)\n"] } } } diff --git a/Sources/Helpers/LoggingGroup.swift b/Sources/Helpers/LoggingGroup.swift index 3a7c4b5..ed383c6 100644 --- a/Sources/Helpers/LoggingGroup.swift +++ b/Sources/Helpers/LoggingGroup.swift @@ -10,18 +10,22 @@ import Foundation struct LoggingGroup: Logging { let logger: [any Logging] + let logLevel: LogLevel - init(with logger: [any Logging]) { + init(with logger: [any Logging], logLevel: LogLevel) { self.logger = logger + self.logLevel = logLevel } @MainActor func log(_ message: String, from subsystem: String) { + guard logLevel.shouldLog else { return } logger.forEach { $0.log(message, from: subsystem) } } @MainActor func debug(_ message: String, from subsystem: String) { + guard logLevel.shouldDebug else { return } logger.forEach { $0.debug(message, from: subsystem) } } } diff --git a/Sources/Helpers/SystemLogger.swift b/Sources/Helpers/SystemLogger.swift index 32c9da0..87d425f 100644 --- a/Sources/Helpers/SystemLogger.swift +++ b/Sources/Helpers/SystemLogger.swift @@ -15,28 +15,14 @@ struct SystemLogger: Logging { self.logLevel = logLevel } - func log( - _ message: String, - from subsystem: String - ) { - switch logLevel { - case .quiet: - break - case .debug, .default: - logger(for: subsystem).log("\(message)") - } + func log(_ message: String, from subsystem: String) { + guard logLevel.shouldLog else { return } + logger(for: subsystem).log("\(message)") } - func debug( - _ message: String, - from subsystem: String - ) { - switch logLevel { - case .quiet, .default: - break - case .debug: - logger(for: subsystem).debug("\(message)") - } + func debug(_ message: String, from subsystem: String) { + guard logLevel.shouldDebugLog else { return } + logger(for: subsystem).debug("\(message)") } } diff --git a/Sources/Helpers/XcodeTools.swift b/Sources/Helpers/XcodeTools.swift index 0b13898..b13b5bb 100644 --- a/Sources/Helpers/XcodeTools.swift +++ b/Sources/Helpers/XcodeTools.swift @@ -90,17 +90,13 @@ struct XcodeTools { scheme: String, projectType: ProjectType ) async throws -> String { - - let derivedDataPath = "\(projectDirectoryPath)/\(Constants.derivedDataPath)" - var commandComponents = [ "cd \(projectDirectoryPath);", "xcodebuild clean build -scheme \"\(scheme)\"", - "-sdk `\(Constants.simulatorSdkCommand)`", - "-derivedDataPath \(derivedDataPath)", "-destination \"generic/platform=iOS\"", - "SKIP_INSTALL=NO", - "BUILD_LIBRARY_FOR_DISTRIBUTION=YES", + "-derivedDataPath \(Constants.derivedDataPath)", + "-sdk `\(Constants.simulatorSdkCommand)`", + "BUILD_LIBRARY_FOR_DISTRIBUTION=YES" ] switch projectType { @@ -116,6 +112,9 @@ struct XcodeTools { logger?.log("πŸ“¦ Archiving \(scheme) from \(projectDirectoryPath)", from: String(describing: Self.self)) let result = shell.execute(command) + let derivedDataPath = "\(projectDirectoryPath)/\(Constants.derivedDataPath)" + + logger?.debug(result, from: String(describing: Self.self)) // It might be that the archive failed but the .swiftinterface files are still created // so we have to check outside if they exist. diff --git a/Sources/Pipeline/Pipeline+Protocols.swift b/Sources/Pipeline/Pipeline+Protocols.swift index 018e019..6864320 100644 --- a/Sources/Pipeline/Pipeline+Protocols.swift +++ b/Sources/Pipeline/Pipeline+Protocols.swift @@ -71,6 +71,28 @@ enum LogLevel { case quiet case `default` case debug + + var shouldLog: Bool { + switch self { + case .quiet: + return false + case .default: + return true + case .debug: + return true + } + } + + var shouldDebugLog: Bool { + switch self { + case .quiet: + return false + case .default: + return false + case .debug: + return true + } + } } protocol Logging { diff --git a/Sources/public-api-diff.swift b/Sources/public-api-diff.swift index 03b90d4..b299d07 100644 --- a/Sources/public-api-diff.swift +++ b/Sources/public-api-diff.swift @@ -226,18 +226,21 @@ private extension PublicApiDiff { projectType: ProjectType, xcodeTools: XcodeTools ) async throws -> (newDerivedDataPath: String, oldDerivedDataPath: String) { // TODO: Typed return type - async let asyncNewDerivedDataPath = try xcodeTools.archive( + + // We don't run them in parallel to not conflict with resolving dependencies concurrently + + let newDerivedDataPath = try await xcodeTools.archive( projectDirectoryPath: newProjectDirectoryPath, scheme: scheme, projectType: projectType ) - async let asyncOldDerivedDataPath = try xcodeTools.archive( + let oldDerivedDataPath = try await xcodeTools.archive( projectDirectoryPath: oldProjectDirectoryPath, scheme: scheme, projectType: projectType ) - return try await (asyncNewDerivedDataPath, asyncOldDerivedDataPath) + return (newDerivedDataPath, oldDerivedDataPath) } func locateInterfaceFiles( From 665c45e58941e026dc76f68a0d0cfd72c715abef Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Wed, 9 Oct 2024 10:38:38 +0200 Subject: [PATCH 12/45] fixing build --- Sources/Helpers/LoggingGroup.swift | 2 +- Sources/public-api-diff.swift | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Sources/Helpers/LoggingGroup.swift b/Sources/Helpers/LoggingGroup.swift index ed383c6..40f798d 100644 --- a/Sources/Helpers/LoggingGroup.swift +++ b/Sources/Helpers/LoggingGroup.swift @@ -25,7 +25,7 @@ struct LoggingGroup: Logging { @MainActor func debug(_ message: String, from subsystem: String) { - guard logLevel.shouldDebug else { return } + guard logLevel.shouldDebugLog else { return } logger.forEach { $0.debug(message, from: subsystem) } } } diff --git a/Sources/public-api-diff.swift b/Sources/public-api-diff.swift index b299d07..ab6f076 100644 --- a/Sources/public-api-diff.swift +++ b/Sources/public-api-diff.swift @@ -27,14 +27,15 @@ struct PublicApiDiff: AsyncParsableCommand { public func run() async throws { + let logLevel: LogLevel = .debug let fileHandler: FileHandling = FileManager.default var loggers = [any Logging]() if let logOutput { loggers += [LogFileLogger(fileHandler: fileHandler, outputFilePath: logOutput)] } - loggers += [SystemLogger(logLevel: .debug)] // LogLevel should be provided by a parameter + loggers += [SystemLogger(logLevel: logLevel)] // LogLevel should be provided by a parameter - let logger: any Logging = LoggingGroup(with: loggers) + let logger: any Logging = LoggingGroup(with: loggers, logLevel: logLevel) do { let oldSource = try ProjectSource.from(old, fileHandler: fileHandler) From ff8ab8985407bd85835835d350a0457a83c87191 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Wed, 9 Oct 2024 11:32:02 +0200 Subject: [PATCH 13/45] updating package.resolved --- Package.resolved | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.resolved b/Package.resolved index 6d73072..5b1fc27 100644 --- a/Package.resolved +++ b/Package.resolved @@ -23,8 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/nicklockwood/SwiftFormat", "state" : { - "revision" : "ab6844edb79a7b88dc6320e6cee0a0db7674dac3", - "version" : "0.54.5" + "revision" : "86ed20990585f478c0daf309af645c2a528b59d8", + "version" : "0.54.6" } } ], From b48d1f6825abac5a5bafd8a31a68dc05ea702b99 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Wed, 9 Oct 2024 11:42:08 +0200 Subject: [PATCH 14/45] Removing SDKDump related code --- .../ElementDescriptions/EnumCaseElement.swift | 56 - .../ElementDescriptions/FunctionElement.swift | 158 - .../ElementDescriptions/OperatorElement.swift | 34 - .../TypeAliasElement.swift | 36 - .../ElementDescriptions/VarElement.swift | 55 - .../SDKDump/IndependentSDKDumpChange.swift | 25 - .../Models/SDKDump/SDKDump+Conformance.swift | 27 - .../SDKDump/SDKDump+DeclarationKind.swift | 36 - .../SDKDump/SDKDump+Element+Description.swift | 92 - .../SDKDump/SDKDump+Element+Difference.swift | 190 - .../Models/SDKDump/SDKDump+Element.swift | 294 - .../Helpers/Models/SDKDump/SDKDump+Kind.swift | 46 - Sources/Helpers/Models/SDKDump/SDKDump.swift | 77 - Sources/Pipeline/Modules/ProjectBuilder.swift | 204 - .../SDKDumpAnalyzer/SDKDumpAnalyzer.swift | 144 - .../SDKDumpChangeConsolidator.swift | 134 - .../Pipeline/Modules/SDKDumpGenerator.swift | 35 - Sources/Pipeline/Pipeline+Protocols.swift | 12 - Sources/Pipeline/SDKDumpPipeline.swift | 205 - Sources/public-api-diff.swift | 31 - .../ReferencePackageTests.swift | 6 +- .../expected-reference-changes-sdk-dump.md | 264 - ...ference-changes-swift-interface-private.md | 14 +- ...eference-changes-swift-interface-public.md | 14 +- Tests/UnitTests/ABIGeneratorTests.swift | 95 - Tests/UnitTests/PipelineTests.swift | 125 +- Tests/UnitTests/ProjectBuilderTests.swift | 99 - .../Resources/dummi-abi-flat-definition.md | 10900 -- Tests/UnitTests/Resources/dummy.abi.json | 143379 --------------- Tests/UnitTests/SDKDumpAnalyzerTests.swift | 197 - Tests/UnitTests/SDKDumpGeneratorTests.swift | 53 - Tests/UnitTests/SDKDumpTests.swift | 123 - .../MockABIGenerator.swift | 17 - .../MockProjectBuilder.swift | 17 - .../MockSDKDumpAnalyzer.swift | 17 - .../MockSDKDumpGenerator.swift | 17 - Tests/UnitTests/XcodeToolsTests.swift | 4 +- 37 files changed, 20 insertions(+), 157212 deletions(-) delete mode 100644 Sources/Helpers/Models/SDKDump/ElementDescriptions/EnumCaseElement.swift delete mode 100644 Sources/Helpers/Models/SDKDump/ElementDescriptions/FunctionElement.swift delete mode 100644 Sources/Helpers/Models/SDKDump/ElementDescriptions/OperatorElement.swift delete mode 100644 Sources/Helpers/Models/SDKDump/ElementDescriptions/TypeAliasElement.swift delete mode 100644 Sources/Helpers/Models/SDKDump/ElementDescriptions/VarElement.swift delete mode 100644 Sources/Helpers/Models/SDKDump/IndependentSDKDumpChange.swift delete mode 100644 Sources/Helpers/Models/SDKDump/SDKDump+Conformance.swift delete mode 100644 Sources/Helpers/Models/SDKDump/SDKDump+DeclarationKind.swift delete mode 100644 Sources/Helpers/Models/SDKDump/SDKDump+Element+Description.swift delete mode 100644 Sources/Helpers/Models/SDKDump/SDKDump+Element+Difference.swift delete mode 100644 Sources/Helpers/Models/SDKDump/SDKDump+Element.swift delete mode 100644 Sources/Helpers/Models/SDKDump/SDKDump+Kind.swift delete mode 100644 Sources/Helpers/Models/SDKDump/SDKDump.swift delete mode 100644 Sources/Pipeline/Modules/ProjectBuilder.swift delete mode 100644 Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpAnalyzer.swift delete mode 100644 Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpChangeConsolidator.swift delete mode 100644 Sources/Pipeline/Modules/SDKDumpGenerator.swift delete mode 100644 Sources/Pipeline/SDKDumpPipeline.swift delete mode 100644 Tests/IntegrationTests/Resources/expected-reference-changes-sdk-dump.md delete mode 100644 Tests/UnitTests/ABIGeneratorTests.swift delete mode 100644 Tests/UnitTests/ProjectBuilderTests.swift delete mode 100644 Tests/UnitTests/Resources/dummi-abi-flat-definition.md delete mode 100644 Tests/UnitTests/Resources/dummy.abi.json delete mode 100644 Tests/UnitTests/SDKDumpAnalyzerTests.swift delete mode 100644 Tests/UnitTests/SDKDumpGeneratorTests.swift delete mode 100644 Tests/UnitTests/SDKDumpTests.swift delete mode 100644 Tests/UnitTests/Utilities/MockPipelineModules/MockABIGenerator.swift delete mode 100644 Tests/UnitTests/Utilities/MockPipelineModules/MockProjectBuilder.swift delete mode 100644 Tests/UnitTests/Utilities/MockPipelineModules/MockSDKDumpAnalyzer.swift delete mode 100644 Tests/UnitTests/Utilities/MockPipelineModules/MockSDKDumpGenerator.swift diff --git a/Sources/Helpers/Models/SDKDump/ElementDescriptions/EnumCaseElement.swift b/Sources/Helpers/Models/SDKDump/ElementDescriptions/EnumCaseElement.swift deleted file mode 100644 index 60de61a..0000000 --- a/Sources/Helpers/Models/SDKDump/ElementDescriptions/EnumCaseElement.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// Copyright (c) 2024 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -import Foundation - -extension SDKDump.Element { - - public var asEnumCase: SDKDump.EnumCaseElement? { - .init(for: self) - } -} - -extension SDKDump { - - struct EnumCaseElement: CustomStringConvertible { - - public var declaration: String { "case" } - - public var description: String { compileDescription() } - - private let underlyingElement: SDKDump.Element - - fileprivate init?(for underlyingElement: SDKDump.Element) { - guard underlyingElement.declKind == .case else { return nil } - - self.underlyingElement = underlyingElement - } - } -} - -// MARK: - Privates - -private extension SDKDump.EnumCaseElement { - - func compileDescription() -> String { - - let defaultDescription = "\(declaration) \(underlyingElement.printedName)" - - guard let firstChild = underlyingElement.children.first else { - return defaultDescription - } - - guard let nestedFirstChild = firstChild.children.first else { - return defaultDescription // Return type (enum type) - } - - guard nestedFirstChild.children.count == 2, let associatedValue = nestedFirstChild.children.last else { - return defaultDescription // No associated value - } - - return "\(defaultDescription)\(associatedValue.printedName)" - } -} diff --git a/Sources/Helpers/Models/SDKDump/ElementDescriptions/FunctionElement.swift b/Sources/Helpers/Models/SDKDump/ElementDescriptions/FunctionElement.swift deleted file mode 100644 index 27e216b..0000000 --- a/Sources/Helpers/Models/SDKDump/ElementDescriptions/FunctionElement.swift +++ /dev/null @@ -1,158 +0,0 @@ -// -// Copyright (c) 2024 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -import Foundation - -extension SDKDump.Element { - - public var asFunction: SDKDump.FunctionElement? { - .init(for: self) - } -} - -extension SDKDump { - - struct FunctionElement: CustomStringConvertible { - - public var declaration: String? { underlyingElement.declKind == .func ? "func" : nil } - - public var name: String { extractName() } - - public var arguments: [Argument] { extractArguments() } - - public var returnType: String? { extractReturnType() } - - public var description: String { compileDescription() } - - private let underlyingElement: SDKDump.Element - - fileprivate init?(for underlyingElement: SDKDump.Element) { - guard underlyingElement.declKind == .func || underlyingElement.declKind == .constructor || underlyingElement.declKind == .subscriptDeclaration else { - return nil - } - - self.underlyingElement = underlyingElement - } - } -} - -// MARK: Argument - -extension SDKDump.FunctionElement { - - public struct Argument: Equatable, CustomStringConvertible { - let name: String - let type: String - let ownership: String? - let defaultArgument: String? - - public var description: String { - let nameAndType = [ - "\(name):", - ownership, type - ].compactMap { $0 }.joined(separator: " ") - - if let defaultArgument { - return "\(nameAndType) = \(defaultArgument)" - } - return nameAndType - } - } -} - -// MARK: - Privates - -private extension SDKDump.FunctionElement { - - func compileDescription() -> String { - guard let returnType else { return underlyingElement.printedName } - - let argumentList = arguments - .map(\.description) - .joined(separator: ", ") - - let verboseFunctionName = [ - name, - underlyingElement.genericSig, - "(\(argumentList))" - ].compactMap { $0 }.joined() - - let components: [String?] = [ - underlyingElement.isMutating ? "mutating" : nil, - declaration, - verboseFunctionName, - underlyingElement.isThrowing ? "throws" : nil, - "->", - returnType - ] - - return components - .compactMap { $0 } - .joined(separator: " ") - } - - func extractName() -> String { - underlyingElement.printedName.components(separatedBy: "(").first ?? "" - } - - func extractArguments() -> [Argument] { - - let parameterNames = Self.parameterNames( - from: underlyingElement.printedName, - functionName: name - ) - - let parameterTypes = Self.parameterTypes( - for: underlyingElement - ) - - return parameterNames.enumerated().map { index, component in - - guard index < parameterTypes.count else { - return .init( - name: component, - type: Constants.unknownType, - ownership: nil, - defaultArgument: nil - ) - } - - let type = parameterTypes[index] - return .init( - name: component, - type: type.verboseName, - ownership: type.paramValueOwnership?.lowercased(), - defaultArgument: type.hasDefaultArg ? Constants.defaultArg : nil - ) - } - } - - func extractReturnType() -> String? { - guard let returnType = underlyingElement.children.first?.printedName else { return nil } - return returnType == "()" ? "Swift.Void" : returnType - } - - /// Extracts the parameter names from the `printedName` - static func parameterNames(from printedName: String, functionName: String) -> [String] { - var sanitizedArguments = printedName - sanitizedArguments.removeFirst(functionName.count) - sanitizedArguments.removeFirst() // `(` - if sanitizedArguments.hasSuffix(":)") { - sanitizedArguments.removeLast(2) // `:)` - } else { - sanitizedArguments.removeLast() // `)` - } - - if sanitizedArguments.isEmpty { return [] } - - return sanitizedArguments.components(separatedBy: ":") - } - - /// Extracts the parameter types from the underlying element - private static func parameterTypes(for underlyingElement: SDKDump.Element) -> [SDKDump.Element] { - Array(underlyingElement.children.suffix(from: 1)) // First element is the return type - } -} diff --git a/Sources/Helpers/Models/SDKDump/ElementDescriptions/OperatorElement.swift b/Sources/Helpers/Models/SDKDump/ElementDescriptions/OperatorElement.swift deleted file mode 100644 index 437dbf0..0000000 --- a/Sources/Helpers/Models/SDKDump/ElementDescriptions/OperatorElement.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// Copyright (c) 2024 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -import Foundation - -extension SDKDump.Element { - - public var asOperator: SDKDump.OperatorElement? { - .init(for: self) - } -} - -extension SDKDump { - - struct OperatorElement: CustomStringConvertible { - - public var declaration: String { "operator" } - - public var name: String { underlyingElement.printedName } - - public var description: String { "\(declaration) \(name)" } - - private let underlyingElement: SDKDump.Element - - fileprivate init?(for underlyingElement: SDKDump.Element) { - guard underlyingElement.declKind == .infixOperator || underlyingElement.declKind == .postfixOperator || underlyingElement.declKind == .prefixOperator else { return nil } - - self.underlyingElement = underlyingElement - } - } -} diff --git a/Sources/Helpers/Models/SDKDump/ElementDescriptions/TypeAliasElement.swift b/Sources/Helpers/Models/SDKDump/ElementDescriptions/TypeAliasElement.swift deleted file mode 100644 index ac9c10a..0000000 --- a/Sources/Helpers/Models/SDKDump/ElementDescriptions/TypeAliasElement.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// Copyright (c) 2024 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -import Foundation - -extension SDKDump.Element { - - public var asTypeAlias: SDKDump.TypeAliasElement? { - .init(for: self) - } -} - -extension SDKDump { - - struct TypeAliasElement: CustomStringConvertible { - - public var declaration: String { "typealias" } - - public var name: String { underlyingElement.printedName } - - public var type: String { underlyingElement.children.first?.verboseName ?? Constants.unknownType } - - public var description: String { "\(declaration) \(name) = \(type)" } - - private let underlyingElement: SDKDump.Element - - fileprivate init?(for underlyingElement: SDKDump.Element) { - guard underlyingElement.declKind == .typeAlias else { return nil } - - self.underlyingElement = underlyingElement - } - } -} diff --git a/Sources/Helpers/Models/SDKDump/ElementDescriptions/VarElement.swift b/Sources/Helpers/Models/SDKDump/ElementDescriptions/VarElement.swift deleted file mode 100644 index d23a8f3..0000000 --- a/Sources/Helpers/Models/SDKDump/ElementDescriptions/VarElement.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// Copyright (c) 2024 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -import Foundation - -extension SDKDump.Element { - - public var asVar: SDKDump.VarElement? { - .init(for: self) - } -} - -extension SDKDump { - - struct VarElement: CustomStringConvertible { - - public var declaration: String { underlyingElement.isLet ? "let" : "var" } - - public var name: String { underlyingElement.printedName } - - public var type: String { underlyingElement.children.first?.printedName ?? Constants.unknownType } - - public var description: String { compileDescription() } - - private let underlyingElement: SDKDump.Element - - fileprivate init?(for underlyingElement: SDKDump.Element) { - guard underlyingElement.declKind == .var else { return nil } - - self.underlyingElement = underlyingElement - } - } -} - -// MARK: - Privates - -private extension SDKDump.VarElement { - - func compileDescription() -> String { - let isWeak = underlyingElement.children.first?.isWeak == true - - let defaultDescription = [ - isWeak ? "weak" : nil, - underlyingElement.isLazy ? "lazy" : nil, - declaration, - "\(name):", - type - ].compactMap { $0 }.joined(separator: " ") - - return defaultDescription - } -} diff --git a/Sources/Helpers/Models/SDKDump/IndependentSDKDumpChange.swift b/Sources/Helpers/Models/SDKDump/IndependentSDKDumpChange.swift deleted file mode 100644 index eda3371..0000000 --- a/Sources/Helpers/Models/SDKDump/IndependentSDKDumpChange.swift +++ /dev/null @@ -1,25 +0,0 @@ -import Foundation - -/// A change indicating an `addition` or `removal` of an element -/// -/// This intermediate structure helps gathering a list of additions and removals -/// that are later consolidated to a ``Change`` -struct IndependentSDKDumpChange: Equatable { - enum ChangeType: Equatable { - case addition(_ description: String) - case removal(_ description: String) - - var description: String { - switch self { - case let .addition(description): description - case let .removal(description): description - } - } - } - - let changeType: ChangeType - let element: SDKDump.Element - - let oldFirst: Bool - var parentPath: String { element.parentPath } -} diff --git a/Sources/Helpers/Models/SDKDump/SDKDump+Conformance.swift b/Sources/Helpers/Models/SDKDump/SDKDump+Conformance.swift deleted file mode 100644 index cfd62fe..0000000 --- a/Sources/Helpers/Models/SDKDump/SDKDump+Conformance.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// Copyright (c) 2024 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -import Foundation - -extension SDKDump.Element { - - /// Protocol conformance node - struct Conformance: Codable, Equatable, Hashable { - - var printedName: String - - enum CodingKeys: String, CodingKey { - case printedName - } - } -} - -extension SDKDump.Element.Conformance: Comparable { - - static func < (lhs: SDKDump.Element.Conformance, rhs: SDKDump.Element.Conformance) -> Bool { - lhs.printedName < rhs.printedName - } -} diff --git a/Sources/Helpers/Models/SDKDump/SDKDump+DeclarationKind.swift b/Sources/Helpers/Models/SDKDump/SDKDump+DeclarationKind.swift deleted file mode 100644 index 9459dfa..0000000 --- a/Sources/Helpers/Models/SDKDump/SDKDump+DeclarationKind.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// Copyright (c) 2024 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -import Foundation - -extension SDKDump { - - enum DeclarationKind: String, RawRepresentable, Codable { - - case `import` = "Import" - case `class` = "Class" // An `actor` is also just a `class` with some protocol conformances - case `struct` = "Struct" - case `enum` = "Enum" - case `case` = "EnumElement" - case `var` = "Var" - case `func` = "Func" - case `protocol` = "Protocol" - - case constructor = "Constructor" - case accessor = "Accessor" - - case typeAlias = "TypeAlias" - - case subscriptDeclaration = "Subscript" - case associatedType = "AssociatedType" - - case macro = "Macro" - - case infixOperator = "InfixOperator" - case postfixOperator = "PostfixOperator" - case prefixOperator = "PrefixOperator" - } -} diff --git a/Sources/Helpers/Models/SDKDump/SDKDump+Element+Description.swift b/Sources/Helpers/Models/SDKDump/SDKDump+Element+Description.swift deleted file mode 100644 index ef7410a..0000000 --- a/Sources/Helpers/Models/SDKDump/SDKDump+Element+Description.swift +++ /dev/null @@ -1,92 +0,0 @@ -// -// Copyright (c) 2024 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -import Foundation - -extension SDKDump.Element: CustomStringConvertible { - - var description: String { - - var components = genericPrefixes - components += [verboseName] - components += genericSuffixes - - return components.joined(separator: " ") - } - - var verboseName: String { - - guard let declKind else { return printedName } - - let defaultVerboseName = [ - "\(declKind.rawValue.lowercased()) \(printedName)", - genericSig - ].compactMap { $0 }.joined() - - switch declKind { - case .import, .enum, .protocol, .accessor, .macro, .associatedType, .class, .struct: - return defaultVerboseName - case .case: - return self.asEnumCase?.description ?? defaultVerboseName - case .var: - return self.asVar?.description ?? defaultVerboseName - case .constructor, .func, .subscriptDeclaration: - return self.asFunction?.description ?? defaultVerboseName - case .typeAlias: - return self.asTypeAlias?.description ?? defaultVerboseName - case .infixOperator, .prefixOperator, .postfixOperator: - return self.asOperator?.description ?? defaultVerboseName - } - } -} - -private extension SDKDump.Element { - - private var genericPrefixes: [String] { - var components = [String]() - - spiGroupNames?.forEach { components += ["@_spi(\($0))"] } - if hasDiscardableResult { components += ["@discardableResult"] } - if isObjcAccessible { components += ["@objc"] } - if isInlinable { components += ["@inlinable"] } - if isOverride { components += ["override"] } - if declKind != .import && declKind != .case { - if isOpen { - components += ["open"] - } else if isInternal { - components += ["internal"] - } else { - components += ["public"] - } - } - if isFinal { components += ["final"] } - if isIndirect { components += ["indirect"] } - if isRequired { components += ["required"] } - if isStatic { components += ["static"] } - if isConvenienceInit { components += ["convenience"] } - if isDynamic { components += ["dynamic"] } - if isPrefix { components += ["prefix"] } - if isPostfix { components += ["postfix"] } - if isInfix { components += ["infix"] } - - return components - } - - var genericSuffixes: [String] { - - var components = [String]() - - if let conformanceNames = conformances?.sorted().map(\.printedName), !conformanceNames.isEmpty { - components += [": \(conformanceNames.joined(separator: ", "))"] - } - - if let accessors = accessors?.map({ $0.name.lowercased() }), !accessors.isEmpty { - components += ["{ \(accessors.joined(separator: " ")) }"] - } - - return components - } -} diff --git a/Sources/Helpers/Models/SDKDump/SDKDump+Element+Difference.swift b/Sources/Helpers/Models/SDKDump/SDKDump+Element+Difference.swift deleted file mode 100644 index b58fa4f..0000000 --- a/Sources/Helpers/Models/SDKDump/SDKDump+Element+Difference.swift +++ /dev/null @@ -1,190 +0,0 @@ -// -// Copyright (c) 2024 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -import Foundation - -extension SDKDump.Element { - - func differences(to otherElement: SDKDump.Element) -> [String] { - var diff = [String]() - diff += differences(toIsFinal: otherElement.isFinal) - diff += differences(toIsThrowing: otherElement.isThrowing) - diff += differences(toHasDiscardableResult: otherElement.hasDiscardableResult) - diff += differences(toSpiGroupNames: otherElement.spiGroupNames) - diff += differences(toConformances: otherElement.conformances) - diff += differences(toGenericSig: otherElement.genericSig) - diff += differences(toIsObjcAccessible: otherElement.isObjcAccessible) - diff += differences(toIsOverride: otherElement.isOverride) - diff += differences(toIsDynamic: otherElement.isDynamic) - diff += differences(toIsMutating: otherElement.isMutating) - diff += differences(toIsRequired: otherElement.isRequired) - diff += differences(toIsOpen: otherElement.isOpen) - diff += differences(toIsInternal: otherElement.isInternal) - diff += differences(toIsPrefix: otherElement.isPrefix) - diff += differences(toIsInfix: otherElement.isInfix) - diff += differences(toIsPostfix: otherElement.isPostfix) - diff += differences(toIsInlinable: otherElement.isInlinable) - diff += differences(toIsIndirect: otherElement.isIndirect) - - if let functionDescription = asFunction, let otherFunctionDescription = otherElement.asFunction { - diff += functionDescription.differences(toFunction: otherFunctionDescription) - } - - return diff.sorted() - } -} - -private extension SDKDump.Element { - - func differences(toIsFinal otherIsFinal: Bool) -> [String] { - guard isFinal != otherIsFinal else { return [] } - return ["\(otherIsFinal ? "Added" : "Removed") `final` keyword"] - } - - func differences(toIsThrowing otherIsThrowing: Bool) -> [String] { - guard isThrowing != otherIsThrowing else { return [] } - return ["\(otherIsThrowing ? "Added" : "Removed") `throws` keyword"] - } - - func differences(toSpiGroupNames otherSpiGroupNames: [String]?) -> [String] { - guard spiGroupNames != otherSpiGroupNames else { return [] } - - let ownSpiGroupNames = Set(spiGroupNames ?? []) - let otherSpiGroupNames = Set(otherSpiGroupNames ?? []) - - return ownSpiGroupNames.symmetricDifference(otherSpiGroupNames).map { - "\(otherSpiGroupNames.contains($0) ? "Added" : "Removed") `@_spi(\($0))`" - } - } - - func differences(toConformances otherConformances: [Conformance]?) -> [String] { - guard conformances != otherConformances else { return [] } - - let ownConformances = Set(conformances ?? []) - let otherConformances = Set(otherConformances ?? []) - - return ownConformances.symmetricDifference(otherConformances).map { - "\(otherConformances.contains($0) ? "Added" : "Removed") `\($0.printedName)` conformance" - } - } - - func differences(toAccessors otherAccessors: [SDKDump.Element]?) -> [String] { - guard accessors != otherAccessors else { return [] } - - let ownAccessors = Set(accessors?.map(\.printedName) ?? []) - let otherAccessors = Set(otherAccessors?.map(\.printedName) ?? []) - - return ownAccessors.symmetricDifference(otherAccessors).map { - "\(otherAccessors.contains($0) ? "Added" : "Removed") `\($0)` accessor" - } - } - - func differences(toHasDiscardableResult otherHasDiscardableResult: Bool) -> [String] { - guard hasDiscardableResult != otherHasDiscardableResult else { return [] } - return ["\(otherHasDiscardableResult ? "Added" : "Removed") `@discardableResult` keyword"] - } - - func differences(toInitKind otherInitKind: String?) -> [String] { - guard let initKind, let otherInitKind, initKind != otherInitKind else { return [] } - - return ["Changed from `\(otherInitKind.lowercased())` to `\(initKind.lowercased()) init"] - } - - func differences(toGenericSig otherGenericSig: String?) -> [String] { - guard genericSig != otherGenericSig else { return [] } - - if let genericSig, let otherGenericSig { - return ["Changed generic signature from `\(genericSig)` to `\(otherGenericSig)"] - } - - if let otherGenericSig { - return ["Added generic signature `\(otherGenericSig)`"] - } - - if let genericSig { - return ["Removed generic signature `\(genericSig)`"] - } - - return [] - } - - func differences(toIsObjcAccessible otherIsObjcAccessible: Bool) -> [String] { - guard isObjcAccessible != otherIsObjcAccessible else { return [] } - return ["\(otherIsObjcAccessible ? "Added" : "Removed") `@objc` keyword"] - } - - func differences(toIsOverride otherIsOverride: Bool) -> [String] { - guard isOverride != otherIsOverride else { return [] } - return ["\(otherIsOverride ? "Added" : "Removed") `override` keyword"] - } - - func differences(toIsDynamic otherIsDynamic: Bool) -> [String] { - guard isDynamic != otherIsDynamic else { return [] } - return ["\(otherIsDynamic ? "Added" : "Removed") `dynamic` keyword"] - } - - func differences(toIsMutating otherIsMutating: Bool) -> [String] { - guard isMutating != otherIsMutating else { return [] } - return ["\(otherIsMutating ? "Added" : "Removed") `mutating` keyword"] - } - - func differences(toIsRequired otherIsRequired: Bool) -> [String] { - guard isRequired != otherIsRequired else { return [] } - return ["\(otherIsRequired ? "Added" : "Removed") `required` keyword"] - } - - func differences(toIsOpen otherIsOpen: Bool) -> [String] { - guard isOpen != otherIsOpen else { return [] } - return ["\(otherIsOpen ? "Added" : "Removed") `open` keyword"] - } - - func differences(toIsInternal otherIsInternal: Bool) -> [String] { - guard isInternal != otherIsInternal else { return [] } - return ["\(otherIsInternal ? "Added" : "Removed") `internal` keyword"] - } - - func differences(toIsPrefix otherIsPrefix: Bool) -> [String] { - guard isPrefix != otherIsPrefix else { return [] } - return ["\(otherIsPrefix ? "Added" : "Removed") `prefix` keyword"] - } - - func differences(toIsPostfix otherIsPostfix: Bool) -> [String] { - guard isPostfix != otherIsPostfix else { return [] } - return ["\(otherIsPostfix ? "Added" : "Removed") `postfix` keyword"] - } - - func differences(toIsInfix otherIsInfix: Bool) -> [String] { - guard isInfix != otherIsInfix else { return [] } - return ["\(otherIsInfix ? "Added" : "Removed") `infix` keyword"] - } - - func differences(toIsInlinable otherIsInlinable: Bool) -> [String] { - guard isInlinable != otherIsInlinable else { return [] } - return ["\(otherIsInlinable ? "Added" : "Removed") `@inlinable` keyword"] - } - - func differences(toIsIndirect otherIsIndirect: Bool) -> [String] { - guard isIndirect != otherIsIndirect else { return [] } - return ["\(otherIsIndirect ? "Added" : "Removed") `indirect` keyword"] - } -} - -extension SDKDump.FunctionElement { - - func differences(toFunction otherFunction: Self) -> [String] { - let ownArguments = arguments - let otherArguments = otherFunction.arguments - - guard ownArguments != otherArguments else { return [] } - - let ownArgumentNames = Set(arguments.map(\.description)) - let otherArgumentNames = Set(otherArguments.map(\.description)) - - return ownArgumentNames.symmetricDifference(otherArgumentNames).map { - "\(otherArgumentNames.contains($0) ? "Added" : "Removed") `\($0)`" - } - } -} diff --git a/Sources/Helpers/Models/SDKDump/SDKDump+Element.swift b/Sources/Helpers/Models/SDKDump/SDKDump+Element.swift deleted file mode 100644 index 7c7505c..0000000 --- a/Sources/Helpers/Models/SDKDump/SDKDump+Element.swift +++ /dev/null @@ -1,294 +0,0 @@ -// -// Copyright (c) 2024 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -import Foundation - -extension SDKDump { - - /// Generic element node - /// - /// The generic ``Element`` node contains all information from the abi.json - /// which - due to it's recursive (children) nature leads to optional fields that are only available in a specific context. - class Element: Codable, Equatable { - - let kind: Kind - let name: String - let printedName: String - let declKind: DeclarationKind? - /// Indicates whether or not a property / function is static - let isStatic: Bool - /// Indicates whether or not a variable is a `let` (or a `var`) - let isLet: Bool - /// Indicates whether or not a function argument has a default value - let hasDefaultArg: Bool - /// Whether or not an element is marked as `package` or `internal` (only observed when using an abi.json from a binary framework) - let isInternal: Bool - /// Whether or not a class is marked as `open` - let isOpen: Bool - /// Indicates whether or not a function is throwing - let isThrowing: Bool - /// Indicates whether or not an init is a `convenience` or a `designated` initializer - let initKind: String? - /// Contains the generic signature of the element - let genericSig: String? - /// Defines the ownership of the parameter value (e.g. inout) - let paramValueOwnership: String? - /// Defines whether or not the function is mutating/nonmutating - let funcSelfKind: String? - /// The `children` of an ``Element`` which can contain a return value, - /// function arguments and other context related information - let children: [Element] - /// The `@_spi` group names - let spiGroupNames: [String]? - /// Additional context related information about the element - /// (e.g. `DiscardableResult`, `Objc`, `Dynamic`, ...) - let declAttributes: [String]? - /// The accessors of the element (in the context of a protocol definition) - let accessors: [Element]? - /// The conformances the ``Element`` conforms to - let conformances: [Conformance]? - - /// The parent element to the ``Element`` to traverse back to the hierarchy - /// Is set manually within the ``setupParentRelationships(parent:)`` - var parent: Element? - - internal init( - kind: Kind, - name: String, - printedName: String, - declKind: DeclarationKind? = nil, - isStatic: Bool = false, - isLet: Bool = false, - hasDefaultArg: Bool = false, - isInternal: Bool = false, - isThrowing: Bool = false, - isOpen: Bool = false, - initKind: String? = nil, - genericSig: String? = nil, - paramValueOwnership: String? = nil, - funcSelfKind: String? = nil, - children: [Element] = [], - spiGroupNames: [String]? = nil, - declAttributes: [String]? = nil, - accessors: [Element]? = nil, - conformances: [Conformance]? = nil, - parent: Element? = nil - ) { - self.kind = kind - self.name = name - self.printedName = printedName - self.declKind = declKind - self.isStatic = isStatic - self.isLet = isLet - self.hasDefaultArg = hasDefaultArg - self.isInternal = isInternal - self.isThrowing = isThrowing - self.isOpen = isOpen - self.children = children - self.spiGroupNames = spiGroupNames - self.declAttributes = declAttributes - self.accessors = accessors - self.conformances = conformances - self.parent = parent - self.initKind = initKind - self.genericSig = genericSig - self.paramValueOwnership = paramValueOwnership - self.funcSelfKind = funcSelfKind - } - - required init(from decoder: any Decoder) throws { - let container: KeyedDecodingContainer = try decoder.container(keyedBy: CodingKeys.self) - self.kind = try container.decode(SDKDump.Kind.self, forKey: CodingKeys.kind) - self.name = try container.decode(String.self, forKey: CodingKeys.name) - self.printedName = try container.decode(String.self, forKey: CodingKeys.printedName) - self.children = try container.decodeIfPresent([SDKDump.Element].self, forKey: CodingKeys.children) ?? [] - self.spiGroupNames = try container.decodeIfPresent([String].self, forKey: CodingKeys.spiGroupNames) - self.declKind = try container.decodeIfPresent(DeclarationKind.self, forKey: CodingKeys.declKind) - self.isStatic = (try? container.decode(Bool.self, forKey: CodingKeys.isStatic)) ?? false - self.isLet = (try? container.decode(Bool.self, forKey: CodingKeys.isLet)) ?? false - self.hasDefaultArg = (try? container.decode(Bool.self, forKey: CodingKeys.hasDefaultArg)) ?? false - self.isInternal = (try? container.decode(Bool.self, forKey: CodingKeys.isInternal)) ?? false - self.isThrowing = (try? container.decode(Bool.self, forKey: CodingKeys.isThrowing)) ?? false - self.isOpen = try container.decodeIfPresent(Bool.self, forKey: CodingKeys.isOpen) ?? false - self.declAttributes = try container.decodeIfPresent([String].self, forKey: CodingKeys.declAttributes) - self.conformances = try container.decodeIfPresent([Conformance].self, forKey: CodingKeys.conformances) - self.accessors = try container.decodeIfPresent([SDKDump.Element].self, forKey: CodingKeys.accessors) - self.initKind = try container.decodeIfPresent(String.self, forKey: CodingKeys.initKind) - self.genericSig = try container.decodeIfPresent(String.self, forKey: CodingKeys.genericSig) - self.paramValueOwnership = try container.decodeIfPresent(String.self, forKey: CodingKeys.paramValueOwnership) - self.funcSelfKind = try container.decodeIfPresent(String.self, forKey: CodingKeys.funcSelfKind) - } - - func encode(to encoder: any Encoder) throws { - var container: KeyedEncodingContainer = encoder.container(keyedBy: SDKDump.Element.CodingKeys.self) - try container.encode(self.kind, forKey: SDKDump.Element.CodingKeys.kind) - try container.encode(self.name, forKey: SDKDump.Element.CodingKeys.name) - try container.encode(self.printedName, forKey: SDKDump.Element.CodingKeys.printedName) - try container.encode(self.children, forKey: SDKDump.Element.CodingKeys.children) - try container.encodeIfPresent(self.spiGroupNames, forKey: SDKDump.Element.CodingKeys.spiGroupNames) - try container.encodeIfPresent(self.declKind, forKey: SDKDump.Element.CodingKeys.declKind) - try container.encode(self.isStatic, forKey: SDKDump.Element.CodingKeys.isStatic) - try container.encode(self.isLet, forKey: SDKDump.Element.CodingKeys.isLet) - try container.encode(self.hasDefaultArg, forKey: SDKDump.Element.CodingKeys.hasDefaultArg) - try container.encode(self.isInternal, forKey: SDKDump.Element.CodingKeys.isInternal) - try container.encode(self.isThrowing, forKey: SDKDump.Element.CodingKeys.isThrowing) - try container.encode(self.isOpen, forKey: SDKDump.Element.CodingKeys.isOpen) - try container.encodeIfPresent(self.declAttributes, forKey: SDKDump.Element.CodingKeys.declAttributes) - try container.encodeIfPresent(self.conformances, forKey: SDKDump.Element.CodingKeys.conformances) - try container.encodeIfPresent(self.accessors, forKey: SDKDump.Element.CodingKeys.accessors) - try container.encodeIfPresent(self.initKind, forKey: SDKDump.Element.CodingKeys.initKind) - try container.encodeIfPresent(self.genericSig, forKey: SDKDump.Element.CodingKeys.genericSig) - try container.encodeIfPresent(self.paramValueOwnership, forKey: SDKDump.Element.CodingKeys.paramValueOwnership) - try container.encodeIfPresent(self.funcSelfKind, forKey: SDKDump.Element.CodingKeys.funcSelfKind) - } - - enum CodingKeys: String, CodingKey { - case kind - case name - case printedName - case children - case spiGroupNames = "spi_group_names" - case declKind - case isStatic = "static" - case isLet - case hasDefaultArg - case isInternal - case isThrowing = "throwing" - case declAttributes - case conformances - case accessors - case initKind = "init_kind" - case genericSig - case paramValueOwnership - case funcSelfKind - case isOpen - } - - static func == (lhs: SDKDump.Element, rhs: SDKDump.Element) -> Bool { - lhs.kind == rhs.kind && - lhs.name == rhs.name && - lhs.printedName == rhs.printedName && - lhs.declKind == rhs.declKind && - lhs.isStatic == rhs.isStatic && - lhs.isLet == rhs.isLet && - lhs.hasDefaultArg == rhs.hasDefaultArg && - lhs.isInternal == rhs.isInternal && - lhs.isThrowing == rhs.isThrowing && - lhs.children == rhs.children && - lhs.spiGroupNames == rhs.spiGroupNames && - lhs.declAttributes == rhs.declAttributes && - lhs.accessors == rhs.accessors && - lhs.conformances == rhs.conformances && - lhs.initKind == rhs.initKind && - lhs.genericSig == rhs.genericSig && - lhs.paramValueOwnership == rhs.paramValueOwnership && - lhs.funcSelfKind == rhs.funcSelfKind && - // Only comparing the printedName of the parent as using the whole element would lead to an infinite loop - lhs.parent?.printedName == rhs.parent?.printedName - } - } -} - -// MARK: - CustomDebugStringConvertible - -extension SDKDump.Element: CustomDebugStringConvertible { - - var debugDescription: String { - description - } -} - -// MARK: - Convenience - -extension SDKDump.Element { - - var isSpiInternal: Bool { - !(spiGroupNames ?? []).isEmpty - } - - var isFinal: Bool { - guard declKind == .class else { return false } - return (declAttributes ?? []).contains { $0.caseInsensitiveCompare("Final") == .orderedSame } - } - - var hasDiscardableResult: Bool { - (declAttributes ?? []).contains { $0.caseInsensitiveCompare("DiscardableResult") == .orderedSame } - } - - var isObjcAccessible: Bool { - (declAttributes ?? []).contains { $0.caseInsensitiveCompare("ObjC") == .orderedSame } - } - - var isOverride: Bool { - (declAttributes ?? []).contains { $0.caseInsensitiveCompare("Override") == .orderedSame } - } - - var isDynamic: Bool { - (declAttributes ?? []).contains { $0.caseInsensitiveCompare("Dynamic") == .orderedSame } - } - - var isLazy: Bool { - (declAttributes ?? []).contains { $0.caseInsensitiveCompare("Lazy") == .orderedSame } - } - - var isRequired: Bool { - (declAttributes ?? []).contains { $0.caseInsensitiveCompare("Required") == .orderedSame } - } - - var isPrefix: Bool { - (declAttributes ?? []).contains { $0.caseInsensitiveCompare("Prefix") == .orderedSame } - } - - var isPostfix: Bool { - (declAttributes ?? []).contains { $0.caseInsensitiveCompare("Postfix") == .orderedSame } - } - - var isInfix: Bool { - (declAttributes ?? []).contains { $0.caseInsensitiveCompare("Infix") == .orderedSame } - } - - var isInlinable: Bool { - (declAttributes ?? []).contains { $0.caseInsensitiveCompare("Inlinable") == .orderedSame } - } - - var isIndirect: Bool { - (declAttributes ?? []).contains { $0.caseInsensitiveCompare("Indirect") == .orderedSame } - } - - var isTypeInformation: Bool { - kind.isTypeInformation - } - - var isConvenienceInit: Bool { - initKind == "Convenience" - } - - var isWeak: Bool { - name == "WeakStorage" - } - - var isMutating: Bool { - funcSelfKind == "Mutating" - } - - var parentPath: String { - var parent = self.parent - var path = [parent?.name] - - while parent != nil { - parent = parent?.parent - path += [parent?.name] - } - - var sanitizedPath = path.compactMap { $0 } - - if sanitizedPath.last == "TopLevel" { - sanitizedPath.removeLast() - } - - return sanitizedPath.reversed().joined(separator: ".") - } -} diff --git a/Sources/Helpers/Models/SDKDump/SDKDump+Kind.swift b/Sources/Helpers/Models/SDKDump/SDKDump+Kind.swift deleted file mode 100644 index 077f7a0..0000000 --- a/Sources/Helpers/Models/SDKDump/SDKDump+Kind.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright (c) 2024 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -import Foundation - -extension SDKDump { - - enum Kind: String, RawRepresentable, Codable { - - case root = "Root" - - case `import` = "Import" - case `var` = "Var" - case `func` = "Function" - case `class` = "Class" - case `struct` = "Struct" - case `enum` = "Enum" - case `case` = "EnumElement" - case `subscript` = "Subscript" - case `associatedtype` = "AssociatedType" - - case accessor = "Accessor" - case constructor = "Constructor" - - case typeDeclaration = "TypeDecl" - case typeNominal = "TypeNominal" - case typeNameAlias = "TypeNameAlias" - case typeAlias = "TypeAlias" - - case typeFunc = "TypeFunc" - case operatorDeclaration = "OperatorDecl" - } -} - -extension SDKDump.Kind { - - var isTypeInformation: Bool { - switch self { - case .typeNominal, .typeNameAlias: return true - default: return false - } - } -} diff --git a/Sources/Helpers/Models/SDKDump/SDKDump.swift b/Sources/Helpers/Models/SDKDump/SDKDump.swift deleted file mode 100644 index f1c992c..0000000 --- a/Sources/Helpers/Models/SDKDump/SDKDump.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// Copyright (c) 2024 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -import Foundation - -/// Root node -class SDKDump: Codable, Equatable { - let root: Element - - enum CodingKeys: String, CodingKey { - case root = "ABIRoot" - } - - internal init(root: Element) { - self.root = root - setupParentRelationships() - } - - required init(from decoder: any Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.root = try container.decode(Element.self, forKey: .root) - setupParentRelationships() - } - - func encode(to encoder: any Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(self.root, forKey: .root) - } - - public static func == (lhs: SDKDump, rhs: SDKDump) -> Bool { - lhs.root == rhs.root - } -} - -// MARK: - Convenience - -private extension SDKDump { - func setupParentRelationships() { - root.setupParentRelationships() - } -} - -private extension SDKDump.Element { - func setupParentRelationships(parent: SDKDump.Element? = nil) { - self.parent = parent - children.forEach { - $0.setupParentRelationships(parent: self) - } - } -} - -internal extension SDKDump { - - var flatDescription: String { - var components = [String]() - components += root.flatChildDescriptions() - - return components.joined(separator: "\n") - } -} - -private extension SDKDump.Element { - - func flatChildDescriptions() -> [String] { - var definitions = [String]() - children.forEach { child in - if child.declKind == nil { return } // Filtering out metadata - let parentPath = child.parentPath.isEmpty ? "Root" : child.parentPath - let formattedDescription = "```javascript\n// Parent: \(parentPath)\n\(child.description)\n```" - definitions += [formattedDescription] + child.flatChildDescriptions() - } - return definitions - } -} diff --git a/Sources/Pipeline/Modules/ProjectBuilder.swift b/Sources/Pipeline/Modules/ProjectBuilder.swift deleted file mode 100644 index 0c3b621..0000000 --- a/Sources/Pipeline/Modules/ProjectBuilder.swift +++ /dev/null @@ -1,204 +0,0 @@ -// -// Copyright (c) 2024 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -import Foundation - -struct ProjectBuilder: ProjectBuilding { - - private let baseWorkingDirectoryPath: String - private let fileHandler: FileHandling - private let shell: ShellHandling - private let randomStringGenerator: RandomStringGenerating - private let logger: Logging? - - init( - baseWorkingDirectoryPath: String, - fileHandler: FileHandling = FileManager.default, - shell: ShellHandling = Shell(), - randomStringGenerator: RandomStringGenerating = RandomStringGenerator(), - logger: Logging? - ) { - self.baseWorkingDirectoryPath = baseWorkingDirectoryPath - self.fileHandler = fileHandler - self.shell = shell - self.randomStringGenerator = randomStringGenerator - self.logger = logger - } - - func build(source: ProjectSource, scheme: String?) throws -> URL { - let sourceDirectoryPath: String = try { - switch source { - case let .local(path): - path - - case let .remote(branchOrTag, repository): - try retrieveRemoteProject(branchOrTag: branchOrTag, repository: repository) - } - }() - - let sourceWorkingDirectoryPath = try buildSource( - from: sourceDirectoryPath, - scheme: scheme, - description: source.description - ) - - switch source { - case .local: - break - case .remote: - // Clean up the cloned repo - try fileHandler.removeItem(atPath: sourceDirectoryPath) - } - - return sourceWorkingDirectoryPath - } -} - -private extension ProjectBuilder { - - func buildSource( - from sourceDirectoryPath: String, - scheme: String?, - description: String - ) throws -> URL { - - let sourceWorkingDirectoryPath = baseWorkingDirectoryPath.appending("/\(randomStringGenerator.generateRandomString())") - - try Self.setupIndividualWorkingDirectory( - at: sourceWorkingDirectoryPath, - sourceDirectoryPath: sourceDirectoryPath, - fileHandler: fileHandler, - shell: shell, - isPackage: scheme == nil, - logger: logger - ) - - let xcodeTools = XcodeTools( - shell: shell, - fileHandler: fileHandler, - logger: logger - ) - - try Self.buildProject( - projectDirectoryPath: sourceWorkingDirectoryPath, - xcodeTools: xcodeTools, - fileHandler: fileHandler, - scheme: scheme, - description: description, - logger: logger - ) - - return URL(filePath: sourceWorkingDirectoryPath) - } - - func retrieveRemoteProject(branchOrTag: String, repository: String) throws -> String { - - let currentDirectory = fileHandler.currentDirectoryPath - let targetDirectoryPath = currentDirectory.appending("/\(randomStringGenerator.generateRandomString())") - - let git = Git(shell: shell, fileHandler: fileHandler, logger: logger) - try git.clone(repository, at: branchOrTag, targetDirectoryPath: targetDirectoryPath) - return targetDirectoryPath - } - - static func setupIndividualWorkingDirectory( - at destinationDirectoryPath: String, - sourceDirectoryPath: String, - fileHandler: FileHandling, - shell: ShellHandling, - isPackage: Bool, - logger: Logging? - ) throws { - - try fileHandler.createDirectory(atPath: destinationDirectoryPath) - - var fileNameIgnoreList: Set = [".build"] - var fileExtensionIgnoreList: Set = [] - - if isPackage { - fileNameIgnoreList = [ - ".build", - ".git", - ".github", - ".gitmodules", - ".codebeatignore", - ".swiftformat", - ".swiftpm", - ".DS_Store", - "Cartfile" - ] - - fileExtensionIgnoreList = [ - ".png", - ".docc", - ".md", - ".resolved", - ".podspec", - // Not copying over xcodeproj/xcworkspace files because otherwise - // xcodebuild prefers them over the Package.swift file when building - ".xcodeproj", - ".xcworkspace" - ] - } else { - fileNameIgnoreList = [ - "Package.swift" - ] - } - - try fileHandler.contentsOfDirectory(atPath: sourceDirectoryPath).forEach { fileName in - if fileExtensionIgnoreList.contains(where: { fileName.hasSuffix($0) }) { - logger?.debug("Skipping `\(fileName)`", from: String(describing: Self.self)) - return - } - if fileNameIgnoreList.contains(where: { fileName == $0 }) { - logger?.debug("Skipping `\(fileName)`", from: String(describing: Self.self)) - return - } - - let sourceFilePath = sourceDirectoryPath.appending("/\(fileName)") - let destinationFilePath = destinationDirectoryPath.appending("/\(fileName)") - - // Using shell here as it's faster than the FileManager - shell.execute("cp -a '\(sourceFilePath)' '\(destinationFilePath)'") - } - } - - static func buildProject( - projectDirectoryPath: String, - xcodeTools: XcodeTools, - fileHandler: FileHandling, - scheme: String?, - description: String, - logger: Logging? - ) throws { - var schemeToBuild: String - - if let scheme { - // If a project scheme was provided we just try to build it - schemeToBuild = scheme - } else { - // Creating an `.library(name: "_AllTargets", targets: [ALL_TARGETS])` - // so we only have to build once and then can generate ABI files for every module from a single build - schemeToBuild = "_AllTargets" - let packageFileHelper = SwiftPackageFileHelper(fileHandler: fileHandler, xcodeTools: xcodeTools) - try packageFileHelper.preparePackageWithConsolidatedLibrary(named: schemeToBuild, at: projectDirectoryPath) - } - - logger?.log("πŸ› οΈ Building project `\(description)` at\n`\(projectDirectoryPath)`", from: String(describing: Self.self)) - - do { - try xcodeTools.build( - projectDirectoryPath: projectDirectoryPath, - scheme: schemeToBuild, - projectType: scheme == nil ? .swiftPackage : .xcodeProject - ) - logger?.debug("βœ… `\(description)` was built successfully", from: String(describing: Self.self)) - } catch { - logger?.debug("πŸ’” `\(description)` failed building", from: String(describing: Self.self)) - throw error - } - } -} diff --git a/Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpAnalyzer.swift b/Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpAnalyzer.swift deleted file mode 100644 index 1841969..0000000 --- a/Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpAnalyzer.swift +++ /dev/null @@ -1,144 +0,0 @@ -// -// Copyright (c) 2024 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -import Foundation - -struct SDKDumpAnalyzer: SDKDumpAnalyzing { - - let changeConsolidator: SDKDumpChangeConsolidating - - init( - changeConsolidator: SDKDumpChangeConsolidating = SDKDumpChangeConsolidator() - ) { - self.changeConsolidator = changeConsolidator - } - - func analyze( - old: SDKDump, - new: SDKDump - ) -> [Change] { - - let individualChanges = Self.recursiveCompare( - element: old.root, - to: new.root, - oldFirst: true - ) + Self.recursiveCompare( - element: new.root, - to: old.root, - oldFirst: false - ) - - // Matching removals/additions to changes when applicable - return changeConsolidator.consolidate(individualChanges) - } - - private static func recursiveCompare( - element lhs: SDKDump.Element, - to rhs: SDKDump.Element, - oldFirst: Bool - ) -> [IndependentSDKDumpChange] { - - if lhs == rhs { return [] } - - // If both elements are spi internal we can ignore them as they are not in the public interface - if lhs.isSpiInternal, rhs.isSpiInternal { return [] } - - // If both elements are internal we can ignore them as they are not in the public interface - if lhs.isInternal, rhs.isInternal { return [] } - - var changes = [IndependentSDKDumpChange]() - - if oldFirst, lhs.description != rhs.description { - changes += independentChanges(from: lhs, and: rhs, oldFirst: oldFirst) - } - - changes += lhs.children.flatMap { lhsElement in - - // Trying to find a matching element - - // First checking if we found an exact match based on the description - // as we don't want to match a non-change with a change - if let exactMatch = rhs.children.first(where: { $0.description == lhsElement.description }) { - // We found an exact match so we check if the children changed - return recursiveCompare(element: lhsElement, to: exactMatch, oldFirst: oldFirst) - } - - // ... then losening the criteria to find a comparable element - if let rhsChildForName = rhs.children.first(where: { $0.isComparable(to: lhsElement) }) { - // We found a comparable element so we check if the children changed - return recursiveCompare(element: lhsElement, to: rhsChildForName, oldFirst: oldFirst) - } - - // No matching element was found so either it was removed or added - - // Type changes get caught during comparing the description and would only add noise to the output - if lhsElement.isTypeInformation { return [] } - - // An (spi-)internal element was added/removed which we do not count as a public change - if lhsElement.isSpiInternal || lhsElement.isInternal { return [] } - - let changeType: IndependentSDKDumpChange.ChangeType = oldFirst ? - .removal(lhsElement.description) : - .addition(lhsElement.description) - - return [ - .from( - changeType: changeType, - element: lhsElement, - oldFirst: oldFirst - ) - ] - } - - return changes - } - - private static func independentChanges( - from lhs: SDKDump.Element, - and rhs: SDKDump.Element, - oldFirst: Bool - ) -> [IndependentSDKDumpChange] { - - var changes: [IndependentSDKDumpChange] = [ - .from( - changeType: .removal(lhs.description), - element: lhs, - oldFirst: oldFirst - ) - ] - - if !rhs.isSpiInternal { - // We only report additions if they are not @_spi - changes += [ - .from( - changeType: .addition(rhs.description), - element: rhs, - oldFirst: oldFirst - ) - ] - } - - return changes - } -} - -private extension SDKDump.Element { - - /// Checks whether or not 2 elements can be compared based on their `printedName`, `declKind` and `parentPath` - /// - /// If the `printedName`, `declKind` + `parentPath` is the same we can assume that it's the same element but altered - /// We're using the `printedName` and not the `name` as for example there could be multiple functions with the same name but different parameters. - /// In this specific case we want to find an exact match of the signature. - /// - /// e.g. if we have a function `init(foo: Int, bar: Int) -> Void` the `name` would be `init` and `printedName` would be `init(foo:bar:)`. - /// If we used the `name` it could cause a false positive with other functions named `init` (e.g. convenience inits) when trying to find matching elements during this finding phase. - /// In a later consolidation phase removals/additions are compared again based on their `name` to combine them to a `change` - func isComparable(to otherElement: SDKDump.Element) -> Bool { - return printedName == otherElement.printedName && - declKind == otherElement.declKind && - parentPath == otherElement.parentPath - } -} diff --git a/Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpChangeConsolidator.swift b/Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpChangeConsolidator.swift deleted file mode 100644 index f7c8f51..0000000 --- a/Sources/Pipeline/Modules/SDKDumpAnalyzer/SDKDumpChangeConsolidator.swift +++ /dev/null @@ -1,134 +0,0 @@ -// -// Copyright (c) 2024 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -import Foundation - -/// A helper to consolidate a `removal` and `addition` to `change` -protocol SDKDumpChangeConsolidating { - - /// Tries to match a `removal` and `addition` to a `change` - /// - /// - Parameters: - /// - changes: The independent changes (`addition`/`removal`) to try to match - func consolidate(_ changes: [IndependentSDKDumpChange]) -> [Change] -} - -struct SDKDumpChangeConsolidator: SDKDumpChangeConsolidating { - - /// Tries to match a `removal` and `addition` to a `change` - /// - /// - Parameters: - /// - changes: The independent changes (`addition`/`removal`) to try to match - /// - /// e.g. if we have a `removal` `init(foo: Int, bar: Int)` and an `addition` `init(foo: Int, bar: Int, baz: String)` - /// It will get consolidated to a `change` based on the `name`, `parent` & `declKind` - /// The changeType will be also respected so `removals` only get matched with `additions` and vice versa. - /// - /// This can lead to false positive matches in cases where one `removal` could potentially be matched to multiple `additions` or vice versa. - /// e.g. a second `addition` `init(unrelated: String)` might be matched as a change of `init(foo: Int, bar: Int)` - /// as they share the same comparison features but might not be an actual change but a genuine addition. - /// This is acceptable for now but might be improved in the future (e.g. calculating a matching-percentage) - func consolidate(_ changes: [IndependentSDKDumpChange]) -> [Change] { - - var independentChanges = changes - var consolidatedChanges = [Change]() - - while !independentChanges.isEmpty { - let change = independentChanges.removeFirst() - - // Trying to find 2 independent changes that could actually have been a change instead of an addition/removal - guard let nameAndTypeMatchIndex = independentChanges.firstIndex(where: { $0.isConsolidatable(with: change) }) else { - consolidatedChanges.append(change.toConsolidatedChange) - continue - } - - let match = independentChanges.remove(at: nameAndTypeMatchIndex) - let oldDescription = change.oldFirst ? change.element.description : match.element.description - let newDescription = change.oldFirst ? match.element.description : change.element.description - let listOfChanges = listOfChanges(between: change, and: match) - - consolidatedChanges.append( - .init( - changeType: .change( - oldDescription: oldDescription, - newDescription: newDescription - ), - parentPath: match.parentPath, - listOfChanges: listOfChanges - ) - ) - } - - return consolidatedChanges - } - - /// Compiles a list of changes between 2 independent changes - func listOfChanges(between lhs: IndependentSDKDumpChange, and rhs: IndependentSDKDumpChange) -> [String] { - if lhs.oldFirst { - lhs.element.differences(to: rhs.element) - } else { - rhs.element.differences(to: lhs.element) - } - } -} - -extension IndependentSDKDumpChange { - - var toConsolidatedChange: Change { - let changeType: Change.ChangeType = { - switch self.changeType { - case let .addition(description): - .addition(description: description) - case let .removal(description): - .removal(description: description) - } - }() - - return .init( - changeType: changeType, - parentPath: parentPath, - listOfChanges: [] - ) - } - - /// Helper method to construct an IndependentChange from the changeType & element - static func from(changeType: ChangeType, element: SDKDump.Element, oldFirst: Bool) -> Self { - return .init( - changeType: changeType, - element: element, - oldFirst: oldFirst - ) - } - - /// Checks whether or not 2 changes can be diffed based on their elements `name`, `declKind` and `parentPath`. - /// It also checks if the `changeType` is different to not compare 2 additions/removals with eachother. - /// - /// If the `name`, `declKind`, `parentPath` of the element is the same we can assume that it's the same element but altered. - /// We're using the `name` and not the `printedName` is intended to be used to figure out if an addition & removal is actually a change. - /// `name` is more generic than `printedName` as it (for functions) does not take the arguments into account. - /// - /// e.g. if we have a function `init(foo: Int, bar: Int) -> Void` the `name` would be `init` and `printedName` would be `init(foo:bar:)`. - /// It could cause a false positive with other functions named `init` (e.g. convenience inits) when trying to find matching elements during the finding phase. - /// Here we already found the matching elements and thus are looking for combining a removal/addition to a change and thus we can loosen the filter to use the `name`. - /// It could potentially still lead to false positives when having multiple functions with changes and the same name and parent but this is acceptable in this phase. - func isConsolidatable(with otherChange: IndependentSDKDumpChange) -> Bool { - element.name == otherChange.element.name && - element.declKind == otherChange.element.declKind && - element.parentPath == otherChange.element.parentPath && - changeType.name != otherChange.changeType.name // We only want to match independent changes that are hava a different changeType - } -} - -private extension IndependentSDKDumpChange.ChangeType { - - /// The name of the type (without associated value) as String - var name: String { - switch self { - case .addition: "addition" - case .removal: "removal" - } - } -} diff --git a/Sources/Pipeline/Modules/SDKDumpGenerator.swift b/Sources/Pipeline/Modules/SDKDumpGenerator.swift deleted file mode 100644 index 7b0afd9..0000000 --- a/Sources/Pipeline/Modules/SDKDumpGenerator.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (c) 2024 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -import Foundation - -struct SDKDumpGenerator: SDKDumpGenerating { - - /// The path to the project directory that contains the Package.swift - let fileHandler: FileHandling - - init( - fileHandler: FileHandling = FileManager.default - ) { - self.fileHandler = fileHandler - } - - /// Generates an sdk dump object from a file - /// - /// - Parameters: - /// - abiJsonFileUrl: The file path pointing to the sdk dump json - /// - /// - Returns: An optional `SDKDump` (Can be nil if no dump can be found at the specific file path) - func generate(for abiJsonFileUrl: URL) throws -> SDKDump { - - let data = try fileHandler.loadData(from: abiJsonFileUrl.path()) - - return try JSONDecoder().decode( - SDKDump.self, - from: data - ) - } -} diff --git a/Sources/Pipeline/Pipeline+Protocols.swift b/Sources/Pipeline/Pipeline+Protocols.swift index 6864320..068f4e5 100644 --- a/Sources/Pipeline/Pipeline+Protocols.swift +++ b/Sources/Pipeline/Pipeline+Protocols.swift @@ -6,10 +6,6 @@ import Foundation -protocol ProjectBuilding { - func build(source: ProjectSource, scheme: String?) async throws -> URL -} - enum ProjectType { case swiftPackage case xcodeProject @@ -28,14 +24,6 @@ protocol ABIGenerating { func generate(for projectDirectory: URL, scheme: String?, description: String) throws -> [ABIGeneratorOutput] } -protocol SDKDumpGenerating { - func generate(for abiJsonFileUrl: URL) throws -> SDKDump -} - -protocol SDKDumpAnalyzing { - func analyze(old: SDKDump, new: SDKDump) throws -> [Change] -} - protocol SwiftInterfaceParsing { func parse(source: String, moduleName: String) -> any SwiftInterfaceElement } diff --git a/Sources/Pipeline/SDKDumpPipeline.swift b/Sources/Pipeline/SDKDumpPipeline.swift deleted file mode 100644 index ed0d4b6..0000000 --- a/Sources/Pipeline/SDKDumpPipeline.swift +++ /dev/null @@ -1,205 +0,0 @@ -// -// Copyright (c) 2024 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -import Foundation - -struct SDKDumpPipeline { - - let newProjectSource: ProjectSource - let oldProjectSource: ProjectSource - let scheme: String? - - let projectBuilder: any ProjectBuilding - let abiGenerator: any ABIGenerating - let projectAnalyzer: any ProjectAnalyzing - let sdkDumpGenerator: any SDKDumpGenerating - let sdkDumpAnalyzer: any SDKDumpAnalyzing - let outputGenerator: any OutputGenerating - let logger: (any Logging)? - - init( - newProjectSource: ProjectSource, - oldProjectSource: ProjectSource, - scheme: String?, - projectBuilder: any ProjectBuilding, - abiGenerator: any ABIGenerating, - projectAnalyzer: any ProjectAnalyzing, - sdkDumpGenerator: any SDKDumpGenerating, - sdkDumpAnalyzer: any SDKDumpAnalyzing, - outputGenerator: any OutputGenerating, - logger: (any Logging)? - ) { - self.newProjectSource = newProjectSource - self.oldProjectSource = oldProjectSource - self.scheme = scheme - self.projectBuilder = projectBuilder - self.abiGenerator = abiGenerator - self.projectAnalyzer = projectAnalyzer - self.sdkDumpGenerator = sdkDumpGenerator - self.sdkDumpAnalyzer = sdkDumpAnalyzer - self.outputGenerator = outputGenerator - self.logger = logger - } - - func run() async throws -> String { - - let (oldProjectUrl, newProjectUrl) = try await buildProjects( - oldSource: oldProjectSource, - newSource: newProjectSource, - scheme: scheme - ) - - var changes = [String: [Change]]() - var warnings = [String]() - - try analyzeProjectChanges( - oldProjectUrl: oldProjectUrl, - newProjectUrl: newProjectUrl, - changes: &changes, - warnings: &warnings - ) - - let allTargets = try analyzeApiChanges( - oldProjectUrl: oldProjectUrl, - newProjectUrl: newProjectUrl, - changes: &changes - ) - - return try outputGenerator.generate( - from: changes, - allTargets: allTargets.sorted(), - oldSource: oldProjectSource, - newSource: newProjectSource, - warnings: warnings - ) - } -} - -// MARK: - Convenience Methods - -private extension SDKDumpPipeline { - - func buildProjects(oldSource: ProjectSource, newSource: ProjectSource, scheme: String?) async throws -> (URL, URL) { - - // We don't run them in parallel to not conflict with resolving dependencies concurrently - - let oldProjectUrl = try await projectBuilder.build( - source: oldProjectSource, - scheme: scheme - ) - - let newProjectUrl = try await projectBuilder.build( - source: newProjectSource, - scheme: scheme - ) - - return (oldProjectUrl, newProjectUrl) - } - - func generateAbiFiles( - oldProjectUrl: URL, - newProjectUrl: URL, - scheme: String? - ) throws -> ([ABIGeneratorOutput], [ABIGeneratorOutput]) { - - let oldAbiFiles = try abiGenerator.generate( - for: oldProjectUrl, - scheme: scheme, - description: oldProjectSource.description - ) - - let newAbiFiles = try abiGenerator.generate( - for: newProjectUrl, - scheme: scheme, - description: newProjectSource.description - ) - - return (oldAbiFiles, newAbiFiles) - } - - func allTargetNames(from lhs: [ABIGeneratorOutput], and rhs: [ABIGeneratorOutput]) throws -> [String] { - let allTargets = Set(lhs.map(\.targetName)).union(Set(rhs.map(\.targetName))) - if allTargets.isEmpty { throw PipelineError.noTargetFound } - return allTargets.sorted() - } - - func analyzeProjectChanges(oldProjectUrl: URL, newProjectUrl: URL, changes: inout [String: [Change]], warnings: inout [String]) throws { - - let projectChanges = try projectAnalyzer.analyze( - oldProjectUrl: oldProjectUrl, - newProjectUrl: newProjectUrl - ) - - if !projectChanges.changes.isEmpty { - changes[""] = projectChanges.changes - } - - warnings = projectChanges.warnings - } - - func analyzeApiChanges(oldProjectUrl: URL, newProjectUrl: URL, changes: inout [String: [Change]]) throws -> [String] { - - let (oldAbiFiles, newAbiFiles) = try generateAbiFiles( - oldProjectUrl: oldProjectUrl, - newProjectUrl: newProjectUrl, - scheme: scheme - ) - - let allTargets = try allTargetNames( - from: oldAbiFiles, - and: newAbiFiles - ) - - // Goes through all the available abi files and compares them - try allTargets.forEach { target in - guard let oldAbiJson = oldAbiFiles.abiJsonFileUrl(for: target) else { return } - guard let newAbiJson = newAbiFiles.abiJsonFileUrl(for: target) else { return } - - /* - // Using `xcrun --sdk iphoneos swift-api-digester -diagnose-sdk` instead of the custom parser - let diagnose = XcodeTools().diagnoseSdk( - oldAbiJsonFilePath: oldAbiJson.path(), - newAbiJsonFilePath: newAbiJson.path(), - module: target - ) - - print(diagnose) - */ - - // Generate SDKDump objects - let oldSDKDump = try sdkDumpGenerator.generate(for: oldAbiJson) - let newSDKDump = try sdkDumpGenerator.generate(for: newAbiJson) - - // Compare SDKDump objects - let targetChanges = try sdkDumpAnalyzer.analyze( - old: oldSDKDump, - new: newSDKDump - ) - - if !targetChanges.isEmpty { - changes[target] = targetChanges - } - } - - return allTargets - } -} - -// MARK: - Convenience - -private extension [String: [Change]] { - - mutating func append(change: Change, to moduleName: String) { - self[moduleName] = (self[moduleName] ?? []) + [change] - } -} - -private extension [ABIGeneratorOutput] { - - func abiJsonFileUrl(for targetName: String) -> URL? { - first { $0.targetName == targetName }?.abiJsonFileUrl - } -} diff --git a/Sources/public-api-diff.swift b/Sources/public-api-diff.swift index ab6f076..2acc199 100644 --- a/Sources/public-api-diff.swift +++ b/Sources/public-api-diff.swift @@ -269,34 +269,3 @@ private extension PublicApiDiff { } } } - -internal extension SDKDumpPipeline { - - static func run( - newSource: ProjectSource, - oldSource: ProjectSource, - scheme: String?, - workingDirectoryPath: String, - fileHandler: FileHandling, - logger: Logging? - ) async throws -> String { - - defer { - logger?.debug("Cleaning up", from: "Main") - try? fileHandler.removeItem(atPath: workingDirectoryPath) - } - - return try await SDKDumpPipeline( - newProjectSource: newSource, - oldProjectSource: oldSource, - scheme: scheme, - projectBuilder: ProjectBuilder(baseWorkingDirectoryPath: workingDirectoryPath, logger: logger), - abiGenerator: ABIGenerator(logger: logger), - projectAnalyzer: SwiftPackageFileAnalyzer(logger: logger), - sdkDumpGenerator: SDKDumpGenerator(), - sdkDumpAnalyzer: SDKDumpAnalyzer(), - outputGenerator: MarkdownOutputGenerator(), - logger: logger - ).run() - } -} diff --git a/Tests/IntegrationTests/ReferencePackageTests.swift b/Tests/IntegrationTests/ReferencePackageTests.swift index fa56974..a7ce5ed 100644 --- a/Tests/IntegrationTests/ReferencePackageTests.swift +++ b/Tests/IntegrationTests/ReferencePackageTests.swift @@ -23,8 +23,8 @@ class ReferencePackageTests: XCTestCase { let xcodeTools = XcodeTools(logger: nil) - _ = try await xcodeTools.archive(projectDirectoryPath: oldReferencePackageDirectory.path(), scheme: "ReferencePackage") - _ = try await xcodeTools.archive(projectDirectoryPath: newReferencePackageDirectory.path(), scheme: "ReferencePackage") + _ = try await xcodeTools.archive(projectDirectoryPath: oldReferencePackageDirectory.path(), scheme: "ReferencePackage", projectType: .swiftPackage) + _ = try await xcodeTools.archive(projectDirectoryPath: newReferencePackageDirectory.path(), scheme: "ReferencePackage", projectType: .swiftPackage) } override static func tearDown() { @@ -164,7 +164,7 @@ private extension ReferencePackageTests { fileHandler: FileManager.default, swiftInterfaceParser: SwiftInterfaceParser(), swiftInterfaceAnalyzer: SwiftInterfaceAnalyzer(), - logger: PipelineLogger(logLevel: .debug) + logger: nil ).run() } diff --git a/Tests/IntegrationTests/Resources/expected-reference-changes-sdk-dump.md b/Tests/IntegrationTests/Resources/expected-reference-changes-sdk-dump.md deleted file mode 100644 index 63c311c..0000000 --- a/Tests/IntegrationTests/Resources/expected-reference-changes-sdk-dump.md +++ /dev/null @@ -1,264 +0,0 @@ -# πŸ‘€ 48 public changes detected -_Comparing `/.../.../UpdatedPackage` to `/.../.../ReferencePackage`_ - ---- -## `ReferencePackage` -#### ❇️ Added -```javascript -public enum RawValueEnum: Swift.String -{ - case one - case two - public init?(rawValue: Swift.String) - public typealias RawValue = Swift.String - public var rawValue: Swift.String { get } -} -``` -```javascript -public protocol ParentProtocol -{ - associatedtype ParentType: Swift.Equatable where Self.ParentType == Self.Iterator.Element - associatedtype Iterator: Swift.Collection -} -``` -```javascript -public protocol ParentProtocol -{ - associatedtype ParentType: Swift.Equatable where Self.ParentType == Self.Iterator.Element - associatedtype Iterator: Swift.Collection -} -``` -```javascript -public protocol SimpleProtocol -``` -#### πŸ”€ Changed -```javascript -// From -@_hasMissingDesignatedInitializers public actor CustomActor - -// To -@_hasMissingDesignatedInitializers public actor CustomActor: ReferencePackage.SimpleProtocol -``` -```javascript -// From -public enum CustomEnum - -// To -public enum CustomEnum -``` -```javascript -// From -public protocol CustomProtocol - -// To -public protocol CustomProtocol: ReferencePackage.ParentProtocol where Self.ParentType == Swift.Double -``` -```javascript -// From -public struct CustomStruct: ReferencePackage.CustomProtocol - -// To -public struct CustomStruct: ReferencePackage.CustomProtocol where T : Swift.Strideable -``` -### `CustomClass` -#### ❇️ Added -```javascript -final public let a: Swift.Int -``` -```javascript -final public let b: Swift.Int -``` -```javascript -final public let c: Swift.Int -``` -```javascript -final public let d: Swift.Double -``` -```javascript -public subscript(index: Swift.Int) -> T? { get set } -``` -```javascript -public var lazyVar: Swift.String { get set } -``` -#### πŸ”€ Changed -```javascript -// From -@_Concurrency.MainActor public func asyncThrowingFunc() async throws -> Swift.Void - -// To -@_Concurrency.MainActor public func asyncThrowingFunc(_ element: Element) async throws -> Swift.Void where Element : Swift.Strideable -``` -```javascript -// From -convenience public init(value: T) - -// To -convenience public init!(value: T) -``` -```javascript -// From -public init() - -// To -public init?() -``` -### `CustomEnum` -#### ❇️ Added -```javascript -case a -``` -```javascript -case b -``` -```javascript -case c -``` -```javascript -case caseWithNamedString(title: T) -``` -```javascript -case d -``` -```javascript -case e(ReferencePackage.CustomEnum.NestedStructInExtension) -``` -```javascript -extension ReferencePackage.CustomEnum where T == Swift.String -{ - public var titleOfCaseWithNamedString: Swift.String? { get } -} -``` -```javascript -extension ReferencePackage.CustomEnum: ReferencePackage.SimpleProtocol -{ - public struct NestedStructInExtension - { - public let string: Swift.String - public init(string: Swift.String = "Hello") - } -} -``` -#### πŸ”€ Changed -```javascript -// From -case caseWithTuple(Swift.String, Swift.Int) - -// To -case caseWithTuple(_: Swift.String, bar: Swift.Int) -``` -```javascript -// From -indirect case recursive(ReferencePackage.CustomEnum) - -// To -indirect case recursive(ReferencePackage.CustomEnum) -``` -#### πŸ˜Άβ€πŸŒ«οΈ Removed -```javascript -case caseWithString(Swift.String) -``` -### `CustomProtocol` -#### ❇️ Added -```javascript -associatedtype AnotherAssociatedType: Swift.Strideable -``` -```javascript -associatedtype AnotherAssociatedType: Swift.Strideable -``` -```javascript -associatedtype CustomAssociatedType: Swift.Equatable -``` -```javascript -associatedtype CustomAssociatedType: Swift.Equatable -``` -#### πŸ”€ Changed -```javascript -// From -func function() -> any Swift.Equatable - -// To -func function() -> Self.CustomAssociatedType -``` -```javascript -// From -var getSetVar: any Swift.Equatable { get set } - -// To -var getSetVar: Self.AnotherAssociatedType { get set } -``` -```javascript -// From -var getVar: any Swift.Equatable { get } - -// To -var getVar: Self.CustomAssociatedType { get } -``` -#### πŸ˜Άβ€πŸŒ«οΈ Removed -```javascript -typealias CustomAssociatedType = Swift.Equatable -``` -### `CustomStruct` -#### ❇️ Added -```javascript -@available(macOS, unavailable, message: "Unavailable on macOS") public struct NestedStruct -{ - @available(*, deprecated, renamed: "nestedVar") public let nestedLet: Swift.String - @available(swift 5.9) public let nestedVar: Swift.String -} -``` -```javascript -public typealias AnotherAssociatedType = Swift.Double -``` -```javascript -public typealias CustomAssociatedType = Swift.Int -``` -```javascript -public typealias Iterator = Swift.Array.AnotherAssociatedType> -``` -```javascript -public typealias ParentType = Swift.Double -``` -#### πŸ”€ Changed -```javascript -// From -@discardableResult public func function() -> any Swift.Equatable - -// To -@discardableResult public func function() -> Swift.Int -``` -```javascript -// From -public var getSetVar: any Swift.Equatable - -// To -public var getSetVar: Swift.Double -``` -```javascript -// From -public var getVar: any Swift.Equatable - -// To -public var getVar: Swift.Int -``` -### `RawValueEnum` -#### ❇️ Added -```javascript -extension ReferencePackage.RawValueEnum: Swift.Equatable -``` -```javascript -extension ReferencePackage.RawValueEnum: Swift.Hashable -``` -```javascript -extension ReferencePackage.RawValueEnum: Swift.RawRepresentable -``` -### `Swift.Array` -#### ❇️ Added -```javascript -extension Swift.Array -{ - public subscript(safe index: Swift.Int) -> Element? { get } -} -``` - ---- -**Analyzed targets:** ReferencePackage diff --git a/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-private.md b/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-private.md index 30b1172..e4eb7a8 100644 --- a/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-private.md +++ b/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-private.md @@ -114,19 +114,19 @@ extension Swift.Array ### `CustomClass` #### ❇️ Added ```javascript -final public let a: Swift.Int +final public let a: Swift.Int { get } ``` ```javascript -final public let b: Swift.Int +final public let b: Swift.Int { get } ``` ```javascript -final public let c: Swift.Int +final public let c: Swift.Int { get } ``` ```javascript -final public let d: Swift.Double +final public let d: Swift.Double { get } ``` ```javascript @@ -212,7 +212,7 @@ extension ReferencePackage.CustomEnum where T == Swift.String ```javascript public struct NestedStructInExtension { - public let string: Swift.String + public let string: Swift.String { get } public init(string: Swift.String = "Hello") } @@ -314,8 +314,8 @@ typealias CustomAssociatedType = Swift.Equatable ```javascript @available(macOS, unavailable, message: "Unavailable on macOS") public struct NestedStruct { - @available(*, deprecated, renamed: "nestedVar") public let nestedLet: Swift.String - @available(swift 5.9) public let nestedVar: Swift.String + @available(*, deprecated, renamed: "nestedVar") public let nestedLet: Swift.String { get } + @available(swift 5.9) public let nestedVar: Swift.String { get } } ``` diff --git a/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-public.md b/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-public.md index 6d8c8d7..7d00b8f 100644 --- a/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-public.md +++ b/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-public.md @@ -101,19 +101,19 @@ extension Swift.Array ### `CustomClass` #### ❇️ Added ```javascript -final public let a: Swift.Int +final public let a: Swift.Int { get } ``` ```javascript -final public let b: Swift.Int +final public let b: Swift.Int { get } ``` ```javascript -final public let c: Swift.Int +final public let c: Swift.Int { get } ``` ```javascript -final public let d: Swift.Double +final public let d: Swift.Double { get } ``` ```javascript @@ -199,7 +199,7 @@ extension ReferencePackage.CustomEnum where T == Swift.String ```javascript public struct NestedStructInExtension { - public let string: Swift.String + public let string: Swift.String { get } public init(string: Swift.String = "Hello") } @@ -301,8 +301,8 @@ typealias CustomAssociatedType = Swift.Equatable ```javascript @available(macOS, unavailable, message: "Unavailable on macOS") public struct NestedStruct { - @available(*, deprecated, renamed: "nestedVar") public let nestedLet: Swift.String - @available(swift 5.9) public let nestedVar: Swift.String + @available(*, deprecated, renamed: "nestedVar") public let nestedLet: Swift.String { get } + @available(swift 5.9) public let nestedVar: Swift.String { get } } ``` diff --git a/Tests/UnitTests/ABIGeneratorTests.swift b/Tests/UnitTests/ABIGeneratorTests.swift deleted file mode 100644 index c1c2632..0000000 --- a/Tests/UnitTests/ABIGeneratorTests.swift +++ /dev/null @@ -1,95 +0,0 @@ -// -// Copyright (c) 2024 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -@testable import public_api_diff -import XCTest - -class ABIGeneratorTests: XCTestCase { - - func test_noSchemeProvided_shouldHandleAsPackage() throws { - - var shell = MockShell() - shell.handleExecute = { _ in - let packageDescription = SwiftPackageDescription( - defaultLocalization: "en-en", - name: "Name", - toolsVersion: "1.0" - ) - let encodedPackageDescription = try! JSONEncoder().encode(packageDescription) - return String(data: encodedPackageDescription, encoding: .utf8)! - } - - var fileHandler = MockFileHandler() - fileHandler.handleFileExists = { _ in - true - } - fileHandler.handleLoadData = { _ in - try XCTUnwrap("".data(using: .utf8)) - } - - var logger = MockLogger() - logger.handleLog = { message, subsystem in - XCTAssertEqual(message, "πŸ“‹ Generating ABI files for `description`") - XCTAssertEqual(subsystem, "PackageABIGenerator") - } - - let abiGenerator = ABIGenerator( - shell: shell, - fileHandler: fileHandler, - logger: logger - ) - - let output = try abiGenerator.generate(for: URL(filePath: "projectDir"), scheme: nil, description: "description") - let expectedOutput = [ABIGeneratorOutput]() - XCTAssertEqual(output, expectedOutput) - } - - func test_schemeProvided_shouldHandleAsProject() throws { - - let scheme = "Scheme" - let pathToSwiftModule = "path/to/\(scheme).swiftmodule" - let expectedAbiJsonUrl = URL(filePath: "projectDir/\(pathToSwiftModule)/.abi.json") - - var shell = MockShell() - shell.handleExecute = { _ in - "\(pathToSwiftModule)\nsomeMoreStuff.txt" - } - - var fileHandler = MockFileHandler() - fileHandler.handleContentsOfDirectory = { _ in - [".abi.json"] - } - - var logger = MockLogger() - logger.handleLog = { message, subsystem in - XCTAssertEqual(message, "πŸ“‹ Locating ABI file for `Scheme` in `description`") - XCTAssertEqual(subsystem, "ProjectABIProvider") - } - logger.handleDebug = { message, subsystem in - XCTAssertEqual(message, "- `.abi.json`") - XCTAssertEqual(subsystem, "ProjectABIProvider") - } - - let abiGenerator = ABIGenerator( - shell: shell, - fileHandler: fileHandler, - logger: logger - ) - - let output = try abiGenerator.generate( - for: URL(filePath: "projectDir"), - scheme: scheme, - description: "description" - ) - - let expectedOutput: [ABIGeneratorOutput] = [.init( - targetName: scheme, - abiJsonFileUrl: expectedAbiJsonUrl - )] - - XCTAssertEqual(output, expectedOutput) - } -} diff --git a/Tests/UnitTests/PipelineTests.swift b/Tests/UnitTests/PipelineTests.swift index b1361d2..a5b7188 100644 --- a/Tests/UnitTests/PipelineTests.swift +++ b/Tests/UnitTests/PipelineTests.swift @@ -11,129 +11,6 @@ class PipelineTests: XCTestCase { func test_pipeline() async throws { - let projectBuilderExpectation = expectation(description: "ProjectBuilder is called twice") - projectBuilderExpectation.expectedFulfillmentCount = 2 - - let abiGeneratorExpectation = expectation(description: "ABIGenerator is called twice") - abiGeneratorExpectation.expectedFulfillmentCount = 2 - - let projectAnalyzerExpectation = expectation(description: "ProjectAnalyzer is called once") - - let dumpGeneratorExpectation = expectation(description: "SDKDumpGenerator is called twice") - dumpGeneratorExpectation.expectedFulfillmentCount = 2 - - let dumpAnalyzerExpectation = expectation(description: "SDKDumpAnalyzer is called once") - - let oldProjectSource = ProjectSource.local(path: "old") - let newProjectSource = ProjectSource.local(path: "new") - - var expectedSteps: [Any] = [ - URL(filePath: oldProjectSource.description), - URL(filePath: newProjectSource.description), - - URL(filePath: oldProjectSource.description), - "old", - - URL(filePath: newProjectSource.description), - "new", - - URL(filePath: oldProjectSource.description), - URL(filePath: newProjectSource.description), - - SDKDump(root: .init(kind: .var, name: "Name", printedName: URL(filePath: oldProjectSource.description).absoluteString)), - SDKDump(root: .init(kind: .var, name: "Name", printedName: URL(filePath: newProjectSource.description).absoluteString)), - - [ - "": [Change(changeType: .addition(description: "A Library was added"), parentPath: "Parent")], - "Target": [Change(changeType: .addition(description: "Something was added"), parentPath: "Parent")] - ], - ["Target"], - oldProjectSource, - newProjectSource, - - "Output" - ] - - let pipeline = SDKDumpPipeline( - newProjectSource: newProjectSource, - oldProjectSource: oldProjectSource, - scheme: nil, - projectBuilder: MockProjectBuilder(onBuild: { source, scheme in - projectBuilderExpectation.fulfill() - - XCTAssertNil(scheme) - - return URL(filePath: source.description) - }), - abiGenerator: MockABIGenerator(onGenerate: { url, scheme, description in - XCTAssertEqual(url, expectedSteps.first as? URL) - expectedSteps.removeFirst() - XCTAssertNil(scheme) - - XCTAssertEqual(description, expectedSteps.first as? String) - expectedSteps.removeFirst() - - abiGeneratorExpectation.fulfill() - - return [.init(targetName: "Target", abiJsonFileUrl: url)] - }), - projectAnalyzer: MockProjectAnalyzer(onAnalyze: { old, new in - XCTAssertEqual(old, expectedSteps.first as? URL) - expectedSteps.removeFirst() - XCTAssertEqual(new, expectedSteps.first as? URL) - expectedSteps.removeFirst() - projectAnalyzerExpectation.fulfill() - - return .init( - changes: [.init(changeType: .addition(description: "A Library was added"), parentPath: "Parent")], - warnings: [] - ) - }), - sdkDumpGenerator: MockSDKDumpGenerator(onGenerate: { url in - XCTAssertEqual(url, expectedSteps.first as? URL) - expectedSteps.removeFirst() - dumpGeneratorExpectation.fulfill() - - return .init(root: .init(kind: .var, name: "Name", printedName: url.absoluteString)) - }), - sdkDumpAnalyzer: MockSDKDumpAnalyzer(onAnalyze: { old, new in - XCTAssertEqual(old, expectedSteps.first as? SDKDump) - expectedSteps.removeFirst() - XCTAssertEqual(new, expectedSteps.first as? SDKDump) - expectedSteps.removeFirst() - dumpAnalyzerExpectation.fulfill() - - return [.init(changeType: .addition(description: "Something was added"), parentPath: "Parent")] - }), - outputGenerator: MockOutputGenerator(onGenerate: { changes, allTargets, old, new, warnings in - XCTAssertEqual(changes, expectedSteps.first as? [String: [Change]]) - expectedSteps.removeFirst() - XCTAssertEqual(allTargets, expectedSteps.first as? [String]) - expectedSteps.removeFirst() - XCTAssertEqual(old, expectedSteps.first as? ProjectSource) - expectedSteps.removeFirst() - XCTAssertEqual(new, expectedSteps.first as? ProjectSource) - expectedSteps.removeFirst() - XCTAssertTrue(warnings.isEmpty) - - return "Output" - }), - logger: MockLogger(logLevel: .debug) - ) - - let pipelineOutput = try await pipeline.run() - - await fulfillment(of: [ - projectBuilderExpectation, - abiGeneratorExpectation, - projectAnalyzerExpectation, - dumpGeneratorExpectation, - dumpAnalyzerExpectation - ]) - - XCTAssertEqual(pipelineOutput, expectedSteps.first as? String) - expectedSteps.removeFirst() - - XCTAssertEqual(expectedSteps.count, 0) + XCTFail("Implement!") } } diff --git a/Tests/UnitTests/ProjectBuilderTests.swift b/Tests/UnitTests/ProjectBuilderTests.swift deleted file mode 100644 index d98b9ff..0000000 --- a/Tests/UnitTests/ProjectBuilderTests.swift +++ /dev/null @@ -1,99 +0,0 @@ -// -// Copyright (c) 2024 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -@testable import public_api_diff -import XCTest - -class ProjectBuilderTests: XCTestCase { - - func test_buildPackage_success() throws { - - let baseWorkingDirectoryPath = "baseWorkingDirectoryPath" - let randomString = "RANDOM_STRING" - let localPath = "local/path" - - let dummyPackageContent = "products: []" - let expectedConsolidatedPackageContent = "products: [\n .library(\n name: \"_AllTargets\",\n targets: []\n ),]" - - let removeItemExpectation = expectation(description: "FileHandler.removeItem is called once") - - var fileHandler = MockFileHandler() - fileHandler.handleCreateDirectory = { path in - XCTAssertEqual(path, "\(baseWorkingDirectoryPath)/\(randomString)") - } - fileHandler.handleContentsOfDirectory = { path in - XCTAssertEqual(path, localPath) - return [] - } - fileHandler.handleLoadData = { path in - XCTAssertEqual(path, "\(baseWorkingDirectoryPath)/\(randomString)/Package.swift") - return try XCTUnwrap(dummyPackageContent.data(using: .utf8)) - } - fileHandler.handleRemoveItem = { path in - XCTAssertEqual(path, "\(baseWorkingDirectoryPath)/\(randomString)/Package.swift") - removeItemExpectation.fulfill() - } - fileHandler.handleCreateFile = { path, data in - XCTAssertEqual(String(data: data, encoding: .utf8), expectedConsolidatedPackageContent) - XCTAssertEqual(path, "\(baseWorkingDirectoryPath)/\(randomString)/Package.swift") - return true - } - fileHandler.handleFileExists = { path in - XCTAssertEqual(path, "\(baseWorkingDirectoryPath)/\(randomString)/.build") - return true - } - var shell = MockShell() - shell.handleExecute = { command in - if command == "cd \(baseWorkingDirectoryPath)/\(randomString); swift package describe --type json" { - let packageDescription = SwiftPackageDescription( - defaultLocalization: "en-en", - name: "Name", - toolsVersion: "1.0" - ) - let encodedPackageDescription = try! JSONEncoder().encode(packageDescription) - return String(data: encodedPackageDescription, encoding: .utf8)! - } else if command == "cd baseWorkingDirectoryPath/RANDOM_STRING; xcodebuild -scheme \"_AllTargets\" -derivedDataPath .build -sdk `xcrun --sdk iphonesimulator --show-sdk-path` -target x86_64-apple-ios17.4-simulator -destination \"platform=iOS,name=Any iOS Device\" -skipPackagePluginValidation" { - return "" - } else { - XCTFail("MockShell called with unhandled command \(command)") - return "" - } - } - - var expectedLogs: [(message: String, subsystem: String)] = [ - (message: "πŸ› οΈ Building project `\(localPath)` at\n`\(baseWorkingDirectoryPath)/\(randomString)`", subsystem: "ProjectBuilder"), - (message: "πŸ—οΈ Building _AllTargets from `\(baseWorkingDirectoryPath)/\(randomString)`", subsystem: "XcodeTools") - ] - - var logger = MockLogger() - logger.handleLog = { message, subsystem in - let expectedLog = expectedLogs.first! - XCTAssertEqual(message, expectedLog.message) - XCTAssertEqual(subsystem, expectedLog.subsystem) - expectedLogs.removeFirst() - } - logger.handleDebug = { message, subsystem in - XCTAssertEqual(message, "βœ… `\(localPath)` was built successfully") - XCTAssertEqual(subsystem, "ProjectBuilder") - } - - var randomStringGenerator = MockRandomStringGenerator() - randomStringGenerator.onGenerateRandomString = { randomString } - - let projectBuilder = ProjectBuilder( - baseWorkingDirectoryPath: baseWorkingDirectoryPath, - fileHandler: fileHandler, - shell: shell, - randomStringGenerator: randomStringGenerator, - logger: logger - ) - - let projectWorkingDirectoryUrl = try projectBuilder.build(source: .local(path: localPath), scheme: nil) - XCTAssertEqual(projectWorkingDirectoryUrl, URL(filePath: "\(baseWorkingDirectoryPath)/\(randomString)")) - - wait(for: [removeItemExpectation], timeout: 1) - } -} diff --git a/Tests/UnitTests/Resources/dummi-abi-flat-definition.md b/Tests/UnitTests/Resources/dummi-abi-flat-definition.md deleted file mode 100644 index 1ae76c2..0000000 --- a/Tests/UnitTests/Resources/dummi-abi-flat-definition.md +++ /dev/null @@ -1,10900 +0,0 @@ -```javascript -// Parent: Root -import AdyenNetworking -``` -```javascript -// Parent: Root -import Contacts -``` -```javascript -// Parent: Root -import Darwin -``` -```javascript -// Parent: Root -import DeveloperToolsSupport -``` -```javascript -// Parent: Root -import Foundation -``` -```javascript -// Parent: Root -import Foundation -``` -```javascript -// Parent: Root -import Foundation -``` -```javascript -// Parent: Root -import Foundation -``` -```javascript -// Parent: Root -import PassKit -``` -```javascript -// Parent: Root -import QuartzCore -``` -```javascript -// Parent: Root -import SwiftOnoneSupport -``` -```javascript -// Parent: Root -import SwiftUI -``` -```javascript -// Parent: Root -import UIKit -``` -```javascript -// Parent: Root -import WebKit -``` -```javascript -// Parent: Root -import _Concurrency -``` -```javascript -// Parent: Root -import _StringProcessing -``` -```javascript -// Parent: Root -import _SwiftConcurrencyShims -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public enum AnalyticsFlavor -``` -```javascript -// Parent: AnalyticsFlavor -@_spi(AdyenInternal) case components(type: Adyen.PaymentMethodType) -``` -```javascript -// Parent: AnalyticsFlavor -@_spi(AdyenInternal) case dropIn(type: Swift.String, paymentMethods: [Swift.String]) -``` -```javascript -// Parent: AnalyticsFlavor -@_spi(AdyenInternal) public var value: Swift.String { get } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol AnalyticsProviderProtocol -``` -```javascript -// Parent: AnalyticsProviderProtocol -@_spi(AdyenInternal) public var checkoutAttemptId: Swift.String? { get } -``` -```javascript -// Parent: AnalyticsProviderProtocol -@_spi(AdyenInternal) public func sendInitialAnalytics(with: Adyen.AnalyticsFlavor, additionalFields: Adyen.AdditionalAnalyticsFields?) -> Swift.Void -``` -```javascript -// Parent: AnalyticsProviderProtocol -@_spi(AdyenInternal) public func add(info: Adyen.AnalyticsEventInfo) -> Swift.Void -``` -```javascript -// Parent: AnalyticsProviderProtocol -@_spi(AdyenInternal) public func add(log: Adyen.AnalyticsEventLog) -> Swift.Void -``` -```javascript -// Parent: AnalyticsProviderProtocol -@_spi(AdyenInternal) public func add(error: Adyen.AnalyticsEventError) -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class AnalyticsForSession -``` -```javascript -// Parent: AnalyticsForSession -@_spi(AdyenInternal) public static var sessionId: Swift.String? { get set } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol AnalyticsEvent : Encodable -``` -```javascript -// Parent: AnalyticsEvent -@_spi(AdyenInternal) public var timestamp: Swift.Int { get } -``` -```javascript -// Parent: AnalyticsEvent -@_spi(AdyenInternal) public var component: Swift.String { get } -``` -```javascript -// Parent: AnalyticsEvent -@_spi(AdyenInternal) public var id: Swift.String { get } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public enum AnalyticsEventTarget : Encodable, Equatable, Hashable, RawRepresentable -``` -```javascript -// Parent: AnalyticsEventTarget -@_spi(AdyenInternal) case cardNumber -``` -```javascript -// Parent: AnalyticsEventTarget -@_spi(AdyenInternal) case expiryDate -``` -```javascript -// Parent: AnalyticsEventTarget -@_spi(AdyenInternal) case securityCode -``` -```javascript -// Parent: AnalyticsEventTarget -@_spi(AdyenInternal) case holderName -``` -```javascript -// Parent: AnalyticsEventTarget -@_spi(AdyenInternal) case dualBrand -``` -```javascript -// Parent: AnalyticsEventTarget -@_spi(AdyenInternal) case boletoSocialSecurityNumber -``` -```javascript -// Parent: AnalyticsEventTarget -@_spi(AdyenInternal) case taxNumber -``` -```javascript -// Parent: AnalyticsEventTarget -@_spi(AdyenInternal) case authPassWord -``` -```javascript -// Parent: AnalyticsEventTarget -@_spi(AdyenInternal) case addressStreet -``` -```javascript -// Parent: AnalyticsEventTarget -@_spi(AdyenInternal) case addressHouseNumber -``` -```javascript -// Parent: AnalyticsEventTarget -@_spi(AdyenInternal) case addressCity -``` -```javascript -// Parent: AnalyticsEventTarget -@_spi(AdyenInternal) case addressPostalCode -``` -```javascript -// Parent: AnalyticsEventTarget -@_spi(AdyenInternal) case issuerList -``` -```javascript -// Parent: AnalyticsEventTarget -@_spi(AdyenInternal) case listSearch -``` -```javascript -// Parent: AnalyticsEventTarget -@_spi(AdyenInternal) @inlinable public init(rawValue: Swift.String) -> Adyen.AnalyticsEventTarget? -``` -```javascript -// Parent: AnalyticsEventTarget -@_spi(AdyenInternal) public typealias RawValue = Swift.String -``` -```javascript -// Parent: AnalyticsEventTarget -@_spi(AdyenInternal) public var rawValue: Swift.String { get } -``` -```javascript -// Parent: Root -public struct AnalyticsConfiguration -``` -```javascript -// Parent: AnalyticsConfiguration -public var isEnabled: Swift.Bool { get set } -``` -```javascript -// Parent: AnalyticsConfiguration -@_spi(AdyenInternal) public var context: Adyen.AnalyticsContext { get set } -``` -```javascript -// Parent: AnalyticsConfiguration -public init() -> Adyen.AnalyticsConfiguration -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct AdditionalAnalyticsFields -``` -```javascript -// Parent: AdditionalAnalyticsFields -@_spi(AdyenInternal) public let amount: Adyen.Amount? { get } -``` -```javascript -// Parent: AdditionalAnalyticsFields -@_spi(AdyenInternal) public let sessionId: Swift.String? { get } -``` -```javascript -// Parent: AdditionalAnalyticsFields -@_spi(AdyenInternal) public init(amount: Adyen.Amount?, sessionId: Swift.String?) -> Adyen.AdditionalAnalyticsFields -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public enum AnalyticsConstants -``` -```javascript -// Parent: AnalyticsConstants -@_spi(AdyenInternal) public enum ValidationErrorCodes -``` -```javascript -// Parent: AnalyticsConstants.ValidationErrorCodes -@_spi(AdyenInternal) public static let cardNumberEmpty: Swift.Int { get } -``` -```javascript -// Parent: AnalyticsConstants.ValidationErrorCodes -@_spi(AdyenInternal) public static let cardNumberPartial: Swift.Int { get } -``` -```javascript -// Parent: AnalyticsConstants.ValidationErrorCodes -@_spi(AdyenInternal) public static let cardLuhnCheckFailed: Swift.Int { get } -``` -```javascript -// Parent: AnalyticsConstants.ValidationErrorCodes -@_spi(AdyenInternal) public static let cardUnsupported: Swift.Int { get } -``` -```javascript -// Parent: AnalyticsConstants.ValidationErrorCodes -@_spi(AdyenInternal) public static let expiryDateEmpty: Swift.Int { get } -``` -```javascript -// Parent: AnalyticsConstants.ValidationErrorCodes -@_spi(AdyenInternal) public static let expiryDatePartial: Swift.Int { get } -``` -```javascript -// Parent: AnalyticsConstants.ValidationErrorCodes -@_spi(AdyenInternal) public static let cardExpired: Swift.Int { get } -``` -```javascript -// Parent: AnalyticsConstants.ValidationErrorCodes -@_spi(AdyenInternal) public static let expiryDateTooFar: Swift.Int { get } -``` -```javascript -// Parent: AnalyticsConstants.ValidationErrorCodes -@_spi(AdyenInternal) public static let securityCodeEmpty: Swift.Int { get } -``` -```javascript -// Parent: AnalyticsConstants.ValidationErrorCodes -@_spi(AdyenInternal) public static let securityCodePartial: Swift.Int { get } -``` -```javascript -// Parent: AnalyticsConstants.ValidationErrorCodes -@_spi(AdyenInternal) public static let holderNameEmpty: Swift.Int { get } -``` -```javascript -// Parent: AnalyticsConstants.ValidationErrorCodes -@_spi(AdyenInternal) public static let brazilSSNEmpty: Swift.Int { get } -``` -```javascript -// Parent: AnalyticsConstants.ValidationErrorCodes -@_spi(AdyenInternal) public static let brazilSSNPartial: Swift.Int { get } -``` -```javascript -// Parent: AnalyticsConstants.ValidationErrorCodes -@_spi(AdyenInternal) public static let postalCodeEmpty: Swift.Int { get } -``` -```javascript -// Parent: AnalyticsConstants.ValidationErrorCodes -@_spi(AdyenInternal) public static let postalCodePartial: Swift.Int { get } -``` -```javascript -// Parent: AnalyticsConstants.ValidationErrorCodes -@_spi(AdyenInternal) public static let kcpPasswordEmpty: Swift.Int { get } -``` -```javascript -// Parent: AnalyticsConstants.ValidationErrorCodes -@_spi(AdyenInternal) public static let kcpPasswordPartial: Swift.Int { get } -``` -```javascript -// Parent: AnalyticsConstants.ValidationErrorCodes -@_spi(AdyenInternal) public static let kcpFieldEmpty: Swift.Int { get } -``` -```javascript -// Parent: AnalyticsConstants.ValidationErrorCodes -@_spi(AdyenInternal) public static let kcpFieldPartial: Swift.Int { get } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct AnalyticsContext -``` -```javascript -// Parent: AnalyticsContext -@_spi(AdyenInternal) public init(version: Swift.String = $DEFAULT_ARG, platform: Adyen.AnalyticsContext.Platform = $DEFAULT_ARG) -> Adyen.AnalyticsContext -``` -```javascript -// Parent: AnalyticsContext -@_spi(AdyenInternal) public enum Platform : Equatable, Hashable, RawRepresentable -``` -```javascript -// Parent: AnalyticsContext.Platform -@_spi(AdyenInternal) case iOS -``` -```javascript -// Parent: AnalyticsContext.Platform -@_spi(AdyenInternal) case reactNative -``` -```javascript -// Parent: AnalyticsContext.Platform -@_spi(AdyenInternal) case flutter -``` -```javascript -// Parent: AnalyticsContext.Platform -@_spi(AdyenInternal) @inlinable public init(rawValue: Swift.String) -> Adyen.AnalyticsContext.Platform? -``` -```javascript -// Parent: AnalyticsContext.Platform -@_spi(AdyenInternal) public typealias RawValue = Swift.String -``` -```javascript -// Parent: AnalyticsContext.Platform -@_spi(AdyenInternal) public var rawValue: Swift.String { get } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct AnalyticsEventError : AnalyticsEvent, Encodable -``` -```javascript -// Parent: AnalyticsEventError -@_spi(AdyenInternal) public var id: Swift.String { get set } -``` -```javascript -// Parent: AnalyticsEventError -@_spi(AdyenInternal) public var timestamp: Swift.Int { get set } -``` -```javascript -// Parent: AnalyticsEventError -@_spi(AdyenInternal) public var component: Swift.String { get set } -``` -```javascript -// Parent: AnalyticsEventError -@_spi(AdyenInternal) public var type: Adyen.AnalyticsEventError.ErrorType { get set } -``` -```javascript -// Parent: AnalyticsEventError -@_spi(AdyenInternal) public var code: Swift.String? { get set } -``` -```javascript -// Parent: AnalyticsEventError -@_spi(AdyenInternal) public var message: Swift.String? { get set } -``` -```javascript -// Parent: AnalyticsEventError -@_spi(AdyenInternal) public enum ErrorType : Encodable, Equatable, Hashable, RawRepresentable -``` -```javascript -// Parent: AnalyticsEventError.ErrorType -@_spi(AdyenInternal) case network -``` -```javascript -// Parent: AnalyticsEventError.ErrorType -@_spi(AdyenInternal) case implementation -``` -```javascript -// Parent: AnalyticsEventError.ErrorType -@_spi(AdyenInternal) case internal -``` -```javascript -// Parent: AnalyticsEventError.ErrorType -@_spi(AdyenInternal) case api -``` -```javascript -// Parent: AnalyticsEventError.ErrorType -@_spi(AdyenInternal) case sdk -``` -```javascript -// Parent: AnalyticsEventError.ErrorType -@_spi(AdyenInternal) case thirdParty -``` -```javascript -// Parent: AnalyticsEventError.ErrorType -@_spi(AdyenInternal) case generic -``` -```javascript -// Parent: AnalyticsEventError.ErrorType -@_spi(AdyenInternal) @inlinable public init(rawValue: Swift.String) -> Adyen.AnalyticsEventError.ErrorType? -``` -```javascript -// Parent: AnalyticsEventError.ErrorType -@_spi(AdyenInternal) public typealias RawValue = Swift.String -``` -```javascript -// Parent: AnalyticsEventError.ErrorType -@_spi(AdyenInternal) public var rawValue: Swift.String { get } -``` -```javascript -// Parent: AnalyticsEventError -@_spi(AdyenInternal) public init(component: Swift.String, type: Adyen.AnalyticsEventError.ErrorType) -> Adyen.AnalyticsEventError -``` -```javascript -// Parent: AnalyticsEventError -@_spi(AdyenInternal) public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct AnalyticsEventInfo : AnalyticsEvent, Encodable -``` -```javascript -// Parent: AnalyticsEventInfo -@_spi(AdyenInternal) public var id: Swift.String { get set } -``` -```javascript -// Parent: AnalyticsEventInfo -@_spi(AdyenInternal) public var timestamp: Swift.Int { get set } -``` -```javascript -// Parent: AnalyticsEventInfo -@_spi(AdyenInternal) public var component: Swift.String { get set } -``` -```javascript -// Parent: AnalyticsEventInfo -@_spi(AdyenInternal) public var type: Adyen.AnalyticsEventInfo.InfoType { get set } -``` -```javascript -// Parent: AnalyticsEventInfo -@_spi(AdyenInternal) public var target: Adyen.AnalyticsEventTarget? { get set } -``` -```javascript -// Parent: AnalyticsEventInfo -@_spi(AdyenInternal) public var isStoredPaymentMethod: Swift.Bool? { get set } -``` -```javascript -// Parent: AnalyticsEventInfo -@_spi(AdyenInternal) public var brand: Swift.String? { get set } -``` -```javascript -// Parent: AnalyticsEventInfo -@_spi(AdyenInternal) public var issuer: Swift.String? { get set } -``` -```javascript -// Parent: AnalyticsEventInfo -@_spi(AdyenInternal) public var validationErrorCode: Swift.String? { get set } -``` -```javascript -// Parent: AnalyticsEventInfo -@_spi(AdyenInternal) public var validationErrorMessage: Swift.String? { get set } -``` -```javascript -// Parent: AnalyticsEventInfo -@_spi(AdyenInternal) public enum InfoType : Encodable, Equatable, Hashable, RawRepresentable -``` -```javascript -// Parent: AnalyticsEventInfo.InfoType -@_spi(AdyenInternal) case selected -``` -```javascript -// Parent: AnalyticsEventInfo.InfoType -@_spi(AdyenInternal) case focus -``` -```javascript -// Parent: AnalyticsEventInfo.InfoType -@_spi(AdyenInternal) case unfocus -``` -```javascript -// Parent: AnalyticsEventInfo.InfoType -@_spi(AdyenInternal) case validationError -``` -```javascript -// Parent: AnalyticsEventInfo.InfoType -@_spi(AdyenInternal) case rendered -``` -```javascript -// Parent: AnalyticsEventInfo.InfoType -@_spi(AdyenInternal) case input -``` -```javascript -// Parent: AnalyticsEventInfo.InfoType -@_spi(AdyenInternal) @inlinable public init(rawValue: Swift.String) -> Adyen.AnalyticsEventInfo.InfoType? -``` -```javascript -// Parent: AnalyticsEventInfo.InfoType -@_spi(AdyenInternal) public typealias RawValue = Swift.String -``` -```javascript -// Parent: AnalyticsEventInfo.InfoType -@_spi(AdyenInternal) public var rawValue: Swift.String { get } -``` -```javascript -// Parent: AnalyticsEventInfo -@_spi(AdyenInternal) public init(component: Swift.String, type: Adyen.AnalyticsEventInfo.InfoType) -> Adyen.AnalyticsEventInfo -``` -```javascript -// Parent: AnalyticsEventInfo -@_spi(AdyenInternal) public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct AnalyticsEventLog : AnalyticsEvent, Encodable -``` -```javascript -// Parent: AnalyticsEventLog -@_spi(AdyenInternal) public var id: Swift.String { get set } -``` -```javascript -// Parent: AnalyticsEventLog -@_spi(AdyenInternal) public var timestamp: Swift.Int { get set } -``` -```javascript -// Parent: AnalyticsEventLog -@_spi(AdyenInternal) public var component: Swift.String { get set } -``` -```javascript -// Parent: AnalyticsEventLog -@_spi(AdyenInternal) public var type: Adyen.AnalyticsEventLog.LogType { get set } -``` -```javascript -// Parent: AnalyticsEventLog -@_spi(AdyenInternal) public var subType: Adyen.AnalyticsEventLog.LogSubType? { get set } -``` -```javascript -// Parent: AnalyticsEventLog -@_spi(AdyenInternal) public var target: Adyen.AnalyticsEventTarget? { get set } -``` -```javascript -// Parent: AnalyticsEventLog -@_spi(AdyenInternal) public var message: Swift.String? { get set } -``` -```javascript -// Parent: AnalyticsEventLog -@_spi(AdyenInternal) public enum LogType : Encodable, Equatable, Hashable, RawRepresentable -``` -```javascript -// Parent: AnalyticsEventLog.LogType -@_spi(AdyenInternal) case action -``` -```javascript -// Parent: AnalyticsEventLog.LogType -@_spi(AdyenInternal) case submit -``` -```javascript -// Parent: AnalyticsEventLog.LogType -@_spi(AdyenInternal) case redirect -``` -```javascript -// Parent: AnalyticsEventLog.LogType -@_spi(AdyenInternal) case threeDS2 -``` -```javascript -// Parent: AnalyticsEventLog.LogType -@_spi(AdyenInternal) @inlinable public init(rawValue: Swift.String) -> Adyen.AnalyticsEventLog.LogType? -``` -```javascript -// Parent: AnalyticsEventLog.LogType -@_spi(AdyenInternal) public typealias RawValue = Swift.String -``` -```javascript -// Parent: AnalyticsEventLog.LogType -@_spi(AdyenInternal) public var rawValue: Swift.String { get } -``` -```javascript -// Parent: AnalyticsEventLog -@_spi(AdyenInternal) public enum LogSubType : Encodable, Equatable, Hashable, RawRepresentable -``` -```javascript -// Parent: AnalyticsEventLog.LogSubType -@_spi(AdyenInternal) case threeDS2 -``` -```javascript -// Parent: AnalyticsEventLog.LogSubType -@_spi(AdyenInternal) case redirect -``` -```javascript -// Parent: AnalyticsEventLog.LogSubType -@_spi(AdyenInternal) case voucher -``` -```javascript -// Parent: AnalyticsEventLog.LogSubType -@_spi(AdyenInternal) case await -``` -```javascript -// Parent: AnalyticsEventLog.LogSubType -@_spi(AdyenInternal) case qrCode -``` -```javascript -// Parent: AnalyticsEventLog.LogSubType -@_spi(AdyenInternal) case bankTransfer -``` -```javascript -// Parent: AnalyticsEventLog.LogSubType -@_spi(AdyenInternal) case sdk -``` -```javascript -// Parent: AnalyticsEventLog.LogSubType -@_spi(AdyenInternal) case fingerprintSent -``` -```javascript -// Parent: AnalyticsEventLog.LogSubType -@_spi(AdyenInternal) case fingerprintComplete -``` -```javascript -// Parent: AnalyticsEventLog.LogSubType -@_spi(AdyenInternal) case challengeDataSent -``` -```javascript -// Parent: AnalyticsEventLog.LogSubType -@_spi(AdyenInternal) case challengeDisplayed -``` -```javascript -// Parent: AnalyticsEventLog.LogSubType -@_spi(AdyenInternal) case challengeComplete -``` -```javascript -// Parent: AnalyticsEventLog.LogSubType -@_spi(AdyenInternal) @inlinable public init(rawValue: Swift.String) -> Adyen.AnalyticsEventLog.LogSubType? -``` -```javascript -// Parent: AnalyticsEventLog.LogSubType -@_spi(AdyenInternal) public typealias RawValue = Swift.String -``` -```javascript -// Parent: AnalyticsEventLog.LogSubType -@_spi(AdyenInternal) public var rawValue: Swift.String { get } -``` -```javascript -// Parent: AnalyticsEventLog -@_spi(AdyenInternal) public init(component: Swift.String, type: Adyen.AnalyticsEventLog.LogType, subType: Adyen.AnalyticsEventLog.LogSubType? = $DEFAULT_ARG) -> Adyen.AnalyticsEventLog -``` -```javascript -// Parent: AnalyticsEventLog -@_spi(AdyenInternal) public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol AnalyticsValidationError : Error, LocalizedError, Sendable, ValidationError -``` -```javascript -// Parent: AnalyticsValidationError -@_spi(AdyenInternal) public var analyticsErrorCode: Swift.Int { get } -``` -```javascript -// Parent: AnalyticsValidationError -@_spi(AdyenInternal) public var analyticsErrorMessage: Swift.String { get } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct LocalizationKey -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let submitButton: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let submitButtonFormatted: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cancelButton: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let dismissButton: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let removeButton: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let errorTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let errorUnknown: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let validationAlertTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let paymentMethodsOtherMethods: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let paymentMethodsStoredMethods: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let paymentMethodsPaidMethods: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let paymentMethodsTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let paymentMethodRemoveButton: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let paymentRefusedMessage: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let sepaIbanItemTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let sepaIbanItemInvalid: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let sepaNameItemTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let sepaNameItemPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let sepaConsentLabel: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let sepaNameItemInvalid: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardStoreDetailsButton: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardNameItemTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardNameItemPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardNameItemInvalid: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardNumberItemTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardNumberItemPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardNumberItemInvalid: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardExpiryItemTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardExpiryItemTitleOptional: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardExpiryItemPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardExpiryItemInvalid: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardCvcItemInvalid: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardCvcItemTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardCvcItemPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardStoredTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardStoredMessage: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardStoredExpires: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardNumberItemUnsupportedBrand: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardNumberItemUnknownBrand: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let dropInStoredTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let dropInPreselectedOpenAllTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let continueTo: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let continueTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let phoneNumberTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let phoneNumberInvalid: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let telephonePrefix: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let phoneNumberPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardCvcItemPlaceholderDigits: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let emailItemTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let emailItemPlaceHolder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let emailItemInvalid: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let moreOptions: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let applePayTotal: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let mbwayConfirmPayment: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let awaitWaitForConfirmation: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let blikConfirmPayment: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let blikInvalid: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let blikCode: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let blikHelp: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let blikPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let preauthorizeWith: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let confirmPreauthorization: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardCvcItemTitleOptional: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let confirmPurchase: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let lastName: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let firstName: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardPinTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let missingField: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardApplyGiftcard: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let voucherCollectionInstitutionNumber: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let voucherMerchantName: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let voucherExpirationDate: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let voucherPaymentReferenceLabel: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let voucherShopperName: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let buttonCopy: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let voucherIntroduction: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let voucherReadInstructions: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let voucherSaveImage: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let voucherFinish: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardBrazilSSNPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let amount: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let voucherEntity: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let pixInstructions: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let pixExpirationLabel: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let pixCopyButton: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let pixInstructionsCopiedMessage: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let billingAddressSectionTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let billingAddressPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let deliveryAddressSectionTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let deliveryAddressPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let countryFieldTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let countryFieldPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let countryFieldInvalid: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let addressFieldTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let addressFieldPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let streetFieldTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let streetFieldPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let houseNumberFieldTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let houseNumberFieldPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cityFieldTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cityFieldPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cityTownFieldTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cityTownFieldPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let postalCodeFieldTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let postalCodeFieldPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let zipCodeFieldTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let zipCodeFieldPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let stateFieldTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let stateFieldPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let selectStateFieldPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let stateOrProvinceFieldTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let stateOrProvinceFieldPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let selectStateOrProvinceFieldPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let provinceOrTerritoryFieldTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let provinceOrTerritoryFieldPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let apartmentSuiteFieldTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let apartmentSuiteFieldPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let errorFeedbackEmptyField: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let errorFeedbackIncorrectFormat: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let fieldTitleOptional: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let boletobancarioBtnLabel: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let boletoSendCopyToEmail: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let boletoPersonalDetails: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let boletoSocialSecurityNumber: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let boletoDownloadPdf: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let giftcardCurrencyError: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let giftcardNoBalance: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let giftcardRemoveTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let giftcardRemoveMessage: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let giftcardPaymentMethodTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let partialPaymentRemainingBalance: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let partialPaymentPayRemainingAmount: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardTaxNumberLabel: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardTaxNumberPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardTaxNumberInvalid: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardEncryptedPasswordLabel: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardEncryptedPasswordPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardEncryptedPasswordInvalid: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardTaxNumberLabelShort: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let affirmDeliveryAddressToggleTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let voucherShopperReference: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let voucherAlternativeReference: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardInstallmentsNumberOfInstallments: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardInstallmentsOneTime: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardInstallmentsTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardInstallmentsRevolving: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardInstallmentsMonthsAndPrice: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardInstallmentsMonths: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cardInstallmentsPlan: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let bacsHolderNameFieldTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let bacsBankAccountNumberFieldTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let bacsBankLocationIdFieldTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let bacsLegalConsentToggleTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let bacsAmountConsentToggleTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let bacsSpecifiedAmountConsentToggleTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let bacsHolderNameFieldInvalidMessage: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let bacsBankAccountNumberFieldInvalidMessage: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let bacsBankLocationIdFieldInvalidMessage: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let bacsPaymentButtonTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let bacsDownloadMandate: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let achBankAccountTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let achAccountHolderNameFieldTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let achAccountHolderNameFieldInvalid: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let achAccountNumberFieldTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let achAccountNumberFieldInvalid: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let achAccountLocationFieldTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let achAccountLocationFieldInvalid: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let selectFieldTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let onlineBankingTermsAndConditions: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let qrCodeInstructionMessage: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let qrCodeTimerExpirationMessage: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let paybybankSubtitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let paybybankTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let searchPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let upiModeSelection: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let UPIVpaValidationMessage: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let UPIQrcodeGenerationMessage: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let UPIQrcodeTimerMessage: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let upiCollectConfirmPayment: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let upiVpaWaitingMessage: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let QRCodeGenerateQRCode: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let UPIQRCodeInstructions: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let UPIFirstTabTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let UPISecondTabTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let UPICollectDropdownLabel: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let UPICollectFieldLabel: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let UPIErrorNoAppSelected: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cashAppPayTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let cashAppPayCashtag: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let twintNoAppsInstalledMessage: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DARegistrationTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DABiometrics: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DAFaceID: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DATouchID: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DAOpticID: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DARegistrationDescription: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DARegistrationFirstInfo: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DARegistrationSecondInfo: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DARegistrationThirdInfo: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DARegistrationPositiveButton: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DARegistrationNegativeButton: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DAApprovalTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DAApprovalDescription: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DAApprovalPositiveButton: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DAApprovalNegativeButton: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DAApprovalActionSheetTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DAApprovalActionSheetFallback: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DAApprovalActionSheetRemove: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DAApprovalRemoveAlertTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DAApprovalRemoveAlertDescription: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DAApprovalRemoveAlertPositiveButton: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DAApprovalRemoveAlertNegativeButton: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DAApprovalErrorTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DAApprovalErrorMessage: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DAApprovalErrorButtonTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DARegistrationErrorTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DARegistrationErrorMessage: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DARegistrationErrorButtonTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DADeletionConfirmationTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DADeletionConfirmationMessage: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let threeds2DADeletionConfirmationButtonTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let pickerSearchEmptyTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let pickerSearchEmptySubtitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let addressLookupSearchPlaceholder: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let addressLookupSearchEmptyTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let addressLookupSearchEmptySubtitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let addressLookupSearchEmptyTitleNoResults: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let addressLookupSearchEmptySubtitleNoResults: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let addressLookupItemValidationFailureMessageEmpty: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let addressLookupItemValidationFailureMessageInvalid: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let addressLookupSearchManualEntryItemTitle: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public static let accessibilityLastFourDigits: Adyen.LocalizationKey { get } -``` -```javascript -// Parent: LocalizationKey -@_spi(AdyenInternal) public init(key: Swift.String) -> Adyen.LocalizationKey -``` -```javascript -// Parent: Root -public protocol AdyenContextAware -``` -```javascript -// Parent: AdyenContextAware -public var context: Adyen.AdyenContext { get } -``` -```javascript -// Parent: AdyenContextAware -public var payment: Adyen.Payment? { get } -``` -```javascript -// Parent: Root -public struct APIContext : AnyAPIContext -``` -```javascript -// Parent: APIContext -public var queryParameters: [Foundation.URLQueryItem] { get } -``` -```javascript -// Parent: APIContext -public let headers: [Swift.String : Swift.String] { get } -``` -```javascript -// Parent: APIContext -public let environment: any AdyenNetworking.AnyAPIEnvironment { get } -``` -```javascript -// Parent: APIContext -public let clientKey: Swift.String { get } -``` -```javascript -// Parent: APIContext -public init(environment: any AdyenNetworking.AnyAPIEnvironment, clientKey: Swift.String) throws -> Adyen.APIContext -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public enum AnalyticsEnvironment : AnyAPIEnvironment, Equatable, Hashable, RawRepresentable -``` -```javascript -// Parent: AnalyticsEnvironment -@_spi(AdyenInternal) case test -``` -```javascript -// Parent: AnalyticsEnvironment -@_spi(AdyenInternal) case liveEurope -``` -```javascript -// Parent: AnalyticsEnvironment -@_spi(AdyenInternal) case liveAustralia -``` -```javascript -// Parent: AnalyticsEnvironment -@_spi(AdyenInternal) case liveUnitedStates -``` -```javascript -// Parent: AnalyticsEnvironment -@_spi(AdyenInternal) case liveApse -``` -```javascript -// Parent: AnalyticsEnvironment -@_spi(AdyenInternal) case liveIndia -``` -```javascript -// Parent: AnalyticsEnvironment -@_spi(AdyenInternal) case beta -``` -```javascript -// Parent: AnalyticsEnvironment -@_spi(AdyenInternal) case local -``` -```javascript -// Parent: AnalyticsEnvironment -@_spi(AdyenInternal) public var baseURL: Foundation.URL { get } -``` -```javascript -// Parent: AnalyticsEnvironment -@_spi(AdyenInternal) @inlinable public init(rawValue: Swift.String) -> Adyen.AnalyticsEnvironment? -``` -```javascript -// Parent: AnalyticsEnvironment -@_spi(AdyenInternal) public typealias RawValue = Swift.String -``` -```javascript -// Parent: AnalyticsEnvironment -@_spi(AdyenInternal) public var rawValue: Swift.String { get } -``` -```javascript -// Parent: Root -public struct Environment : AnyAPIEnvironment, Equatable -``` -```javascript -// Parent: Environment -public var baseURL: Foundation.URL { get set } -``` -```javascript -// Parent: Environment -public static let test: Adyen.Environment { get } -``` -```javascript -// Parent: Environment -@_spi(AdyenInternal) public static let beta: Adyen.Environment { get } -``` -```javascript -// Parent: Environment -@_spi(AdyenInternal) public static let local: Adyen.Environment { get } -``` -```javascript -// Parent: Environment -public static let live: Adyen.Environment { get } -``` -```javascript -// Parent: Environment -public static let liveEurope: Adyen.Environment { get } -``` -```javascript -// Parent: Environment -public static let liveAustralia: Adyen.Environment { get } -``` -```javascript -// Parent: Environment -public static let liveUnitedStates: Adyen.Environment { get } -``` -```javascript -// Parent: Environment -public static let liveApse: Adyen.Environment { get } -``` -```javascript -// Parent: Environment -public static let liveIndia: Adyen.Environment { get } -``` -```javascript -// Parent: Environment -@_spi(AdyenInternal) public var isLive: Swift.Bool { get } -``` -```javascript -// Parent: Environment -@_spi(AdyenInternal) public static func __derived_struct_equals(_: Adyen.Environment, _: Adyen.Environment) -> Swift.Bool -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol APIRequest : Encodable, Request -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct AppleWalletPassRequest : APIRequest, Encodable, Request -``` -```javascript -// Parent: AppleWalletPassRequest -@_spi(AdyenInternal) public typealias ResponseType = Adyen.AppleWalletPassResponse -``` -```javascript -// Parent: AppleWalletPassRequest -@_spi(AdyenInternal) public let path: Swift.String { get } -``` -```javascript -// Parent: AppleWalletPassRequest -@_spi(AdyenInternal) public var counter: Swift.UInt { get set } -``` -```javascript -// Parent: AppleWalletPassRequest -@_spi(AdyenInternal) public let headers: [Swift.String : Swift.String] { get } -``` -```javascript -// Parent: AppleWalletPassRequest -@_spi(AdyenInternal) public let queryParameters: [Foundation.URLQueryItem] { get } -``` -```javascript -// Parent: AppleWalletPassRequest -@_spi(AdyenInternal) public let method: AdyenNetworking.HTTPMethod { get } -``` -```javascript -// Parent: AppleWalletPassRequest -@_spi(AdyenInternal) public let platform: Swift.String { get } -``` -```javascript -// Parent: AppleWalletPassRequest -@_spi(AdyenInternal) public let passToken: Swift.String { get } -``` -```javascript -// Parent: AppleWalletPassRequest -@_spi(AdyenInternal) public init(passToken: Swift.String) -> Adyen.AppleWalletPassRequest -``` -```javascript -// Parent: AppleWalletPassRequest -@_spi(AdyenInternal) public enum CodingKeys : CodingKey, CustomDebugStringConvertible, CustomStringConvertible, Equatable, Hashable, Sendable -``` -```javascript -// Parent: AppleWalletPassRequest.CodingKeys -@_spi(AdyenInternal) case platform -``` -```javascript -// Parent: AppleWalletPassRequest.CodingKeys -@_spi(AdyenInternal) case passToken -``` -```javascript -// Parent: AppleWalletPassRequest.CodingKeys -@_spi(AdyenInternal) public static func __derived_enum_equals(_: Adyen.AppleWalletPassRequest.CodingKeys, _: Adyen.AppleWalletPassRequest.CodingKeys) -> Swift.Bool -``` -```javascript -// Parent: AppleWalletPassRequest.CodingKeys -@_spi(AdyenInternal) public func hash(into: inout Swift.Hasher) -> Swift.Void -``` -```javascript -// Parent: AppleWalletPassRequest.CodingKeys -@_spi(AdyenInternal) public init(stringValue: Swift.String) -> Adyen.AppleWalletPassRequest.CodingKeys? -``` -```javascript -// Parent: AppleWalletPassRequest.CodingKeys -@_spi(AdyenInternal) public init(intValue: Swift.Int) -> Adyen.AppleWalletPassRequest.CodingKeys? -``` -```javascript -// Parent: AppleWalletPassRequest.CodingKeys -@_spi(AdyenInternal) public var hashValue: Swift.Int { get } -``` -```javascript -// Parent: AppleWalletPassRequest.CodingKeys -@_spi(AdyenInternal) public var intValue: Swift.Int? { get } -``` -```javascript -// Parent: AppleWalletPassRequest.CodingKeys -@_spi(AdyenInternal) public var stringValue: Swift.String { get } -``` -```javascript -// Parent: AppleWalletPassRequest -@_spi(AdyenInternal) public typealias ErrorResponseType = Adyen.APIError -``` -```javascript -// Parent: AppleWalletPassRequest -@_spi(AdyenInternal) public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct ClientKeyRequest : APIRequest, Encodable, Request -``` -```javascript -// Parent: ClientKeyRequest -@_spi(AdyenInternal) public typealias ResponseType = Adyen.ClientKeyResponse -``` -```javascript -// Parent: ClientKeyRequest -@_spi(AdyenInternal) public var path: Swift.String { get } -``` -```javascript -// Parent: ClientKeyRequest -@_spi(AdyenInternal) public let clientKey: Swift.String { get } -``` -```javascript -// Parent: ClientKeyRequest -@_spi(AdyenInternal) public var counter: Swift.UInt { get set } -``` -```javascript -// Parent: ClientKeyRequest -@_spi(AdyenInternal) public let headers: [Swift.String : Swift.String] { get } -``` -```javascript -// Parent: ClientKeyRequest -@_spi(AdyenInternal) public let queryParameters: [Foundation.URLQueryItem] { get } -``` -```javascript -// Parent: ClientKeyRequest -@_spi(AdyenInternal) public let method: AdyenNetworking.HTTPMethod { get } -``` -```javascript -// Parent: ClientKeyRequest -@_spi(AdyenInternal) public init(clientKey: Swift.String) -> Adyen.ClientKeyRequest -``` -```javascript -// Parent: ClientKeyRequest -@_spi(AdyenInternal) public typealias ErrorResponseType = Adyen.APIError -``` -```javascript -// Parent: ClientKeyRequest -@_spi(AdyenInternal) public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct OrderStatusRequest : APIRequest, Encodable, Request -``` -```javascript -// Parent: OrderStatusRequest -@_spi(AdyenInternal) public typealias ResponseType = Adyen.OrderStatusResponse -``` -```javascript -// Parent: OrderStatusRequest -@_spi(AdyenInternal) public var path: Swift.String { get } -``` -```javascript -// Parent: OrderStatusRequest -@_spi(AdyenInternal) public var counter: Swift.UInt { get set } -``` -```javascript -// Parent: OrderStatusRequest -@_spi(AdyenInternal) public let headers: [Swift.String : Swift.String] { get } -``` -```javascript -// Parent: OrderStatusRequest -@_spi(AdyenInternal) public let queryParameters: [Foundation.URLQueryItem] { get } -``` -```javascript -// Parent: OrderStatusRequest -@_spi(AdyenInternal) public let method: AdyenNetworking.HTTPMethod { get } -``` -```javascript -// Parent: OrderStatusRequest -@_spi(AdyenInternal) public let orderData: Swift.String { get } -``` -```javascript -// Parent: OrderStatusRequest -@_spi(AdyenInternal) public init(orderData: Swift.String) -> Adyen.OrderStatusRequest -``` -```javascript -// Parent: OrderStatusRequest -@_spi(AdyenInternal) public typealias ErrorResponseType = Adyen.APIError -``` -```javascript -// Parent: OrderStatusRequest -@_spi(AdyenInternal) public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct PaymentStatusRequest : APIRequest, Encodable, Request -``` -```javascript -// Parent: PaymentStatusRequest -@_spi(AdyenInternal) public typealias ResponseType = Adyen.PaymentStatusResponse -``` -```javascript -// Parent: PaymentStatusRequest -@_spi(AdyenInternal) public let path: Swift.String { get } -``` -```javascript -// Parent: PaymentStatusRequest -@_spi(AdyenInternal) public var counter: Swift.UInt { get set } -``` -```javascript -// Parent: PaymentStatusRequest -@_spi(AdyenInternal) public let headers: [Swift.String : Swift.String] { get } -``` -```javascript -// Parent: PaymentStatusRequest -@_spi(AdyenInternal) public let queryParameters: [Foundation.URLQueryItem] { get } -``` -```javascript -// Parent: PaymentStatusRequest -@_spi(AdyenInternal) public let method: AdyenNetworking.HTTPMethod { get } -``` -```javascript -// Parent: PaymentStatusRequest -@_spi(AdyenInternal) public let paymentData: Swift.String { get } -``` -```javascript -// Parent: PaymentStatusRequest -@_spi(AdyenInternal) public init(paymentData: Swift.String) -> Adyen.PaymentStatusRequest -``` -```javascript -// Parent: PaymentStatusRequest -@_spi(AdyenInternal) public typealias ErrorResponseType = Adyen.APIError -``` -```javascript -// Parent: PaymentStatusRequest -@_spi(AdyenInternal) public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct AppleWalletPassResponse : Decodable, Response -``` -```javascript -// Parent: AppleWalletPassResponse -@_spi(AdyenInternal) public let passData: Foundation.Data { get } -``` -```javascript -// Parent: AppleWalletPassResponse -@_spi(AdyenInternal) public init(passBase64String: Swift.String) throws -> Adyen.AppleWalletPassResponse -``` -```javascript -// Parent: AppleWalletPassResponse -@_spi(AdyenInternal) public init(from: any Swift.Decoder) throws -> Adyen.AppleWalletPassResponse -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct ClientKeyResponse : Decodable, Response -``` -```javascript -// Parent: ClientKeyResponse -@_spi(AdyenInternal) public let cardPublicKey: Swift.String { get } -``` -```javascript -// Parent: ClientKeyResponse -@_spi(AdyenInternal) public init(from: any Swift.Decoder) throws -> Adyen.ClientKeyResponse -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct OrderStatusResponse : Decodable, Response -``` -```javascript -// Parent: OrderStatusResponse -@_spi(AdyenInternal) public let remainingAmount: Adyen.Amount { get } -``` -```javascript -// Parent: OrderStatusResponse -@_spi(AdyenInternal) public let paymentMethods: [Adyen.OrderPaymentMethod]? { get } -``` -```javascript -// Parent: OrderStatusResponse -@_spi(AdyenInternal) public init(remainingAmount: Adyen.Amount, paymentMethods: [Adyen.OrderPaymentMethod]?) -> Adyen.OrderStatusResponse -``` -```javascript -// Parent: OrderStatusResponse -@_spi(AdyenInternal) public init(from: any Swift.Decoder) throws -> Adyen.OrderStatusResponse -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct OrderPaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: OrderPaymentMethod -@_spi(AdyenInternal) public var name: Swift.String { get } -``` -```javascript -// Parent: OrderPaymentMethod -@_spi(AdyenInternal) public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: OrderPaymentMethod -@_spi(AdyenInternal) public let lastFour: Swift.String { get } -``` -```javascript -// Parent: OrderPaymentMethod -@_spi(AdyenInternal) public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: OrderPaymentMethod -@_spi(AdyenInternal) public let transactionLimit: Adyen.Amount? { get } -``` -```javascript -// Parent: OrderPaymentMethod -@_spi(AdyenInternal) public let amount: Adyen.Amount { get } -``` -```javascript -// Parent: OrderPaymentMethod -@_spi(AdyenInternal) public init(lastFour: Swift.String, type: Adyen.PaymentMethodType, transactionLimit: Adyen.Amount?, amount: Adyen.Amount) -> Adyen.OrderPaymentMethod -``` -```javascript -// Parent: OrderPaymentMethod -@_spi(AdyenInternal) public func defaultDisplayInformation(using: Adyen.LocalizationParameters?) -> Adyen.DisplayInformation -``` -```javascript -// Parent: OrderPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: OrderPaymentMethod -@_spi(AdyenInternal) public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: OrderPaymentMethod -@_spi(AdyenInternal) public init(from: any Swift.Decoder) throws -> Adyen.OrderPaymentMethod -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public enum PaymentResultCode : Decodable, Equatable, Hashable, RawRepresentable -``` -```javascript -// Parent: PaymentResultCode -@_spi(AdyenInternal) case authorised -``` -```javascript -// Parent: PaymentResultCode -@_spi(AdyenInternal) case refused -``` -```javascript -// Parent: PaymentResultCode -@_spi(AdyenInternal) case pending -``` -```javascript -// Parent: PaymentResultCode -@_spi(AdyenInternal) case cancelled -``` -```javascript -// Parent: PaymentResultCode -@_spi(AdyenInternal) case error -``` -```javascript -// Parent: PaymentResultCode -@_spi(AdyenInternal) case received -``` -```javascript -// Parent: PaymentResultCode -@_spi(AdyenInternal) case redirectShopper -``` -```javascript -// Parent: PaymentResultCode -@_spi(AdyenInternal) case identifyShopper -``` -```javascript -// Parent: PaymentResultCode -@_spi(AdyenInternal) case challengeShopper -``` -```javascript -// Parent: PaymentResultCode -@_spi(AdyenInternal) @inlinable public init(rawValue: Swift.String) -> Adyen.PaymentResultCode? -``` -```javascript -// Parent: PaymentResultCode -@_spi(AdyenInternal) public typealias RawValue = Swift.String -``` -```javascript -// Parent: PaymentResultCode -@_spi(AdyenInternal) public var rawValue: Swift.String { get } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct PaymentStatusResponse : Decodable, Response -``` -```javascript -// Parent: PaymentStatusResponse -@_spi(AdyenInternal) public let payload: Swift.String { get } -``` -```javascript -// Parent: PaymentStatusResponse -@_spi(AdyenInternal) public let resultCode: Adyen.PaymentResultCode { get } -``` -```javascript -// Parent: PaymentStatusResponse -@_spi(AdyenInternal) public init(from: any Swift.Decoder) throws -> Adyen.PaymentStatusResponse -``` -```javascript -// Parent: Root -public final class AdyenContext : PaymentAware -``` -```javascript -// Parent: AdyenContext -public let apiContext: Adyen.APIContext { get } -``` -```javascript -// Parent: AdyenContext -public var payment: Adyen.Payment? { get } -``` -```javascript -// Parent: AdyenContext -@_spi(AdyenInternal) public let analyticsProvider: (any Adyen.AnalyticsProviderProtocol)? { get } -``` -```javascript -// Parent: AdyenContext -public convenience init(apiContext: Adyen.APIContext, payment: Adyen.Payment?, analyticsConfiguration: Adyen.AnalyticsConfiguration = $DEFAULT_ARG) -> Adyen.AdyenContext -``` -```javascript -// Parent: AdyenContext -@_spi(AdyenInternal) public func update(payment: Adyen.Payment?) -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public enum PersonalInformation : Equatable -``` -```javascript -// Parent: PersonalInformation -@_spi(AdyenInternal) case firstName -``` -```javascript -// Parent: PersonalInformation -@_spi(AdyenInternal) case lastName -``` -```javascript -// Parent: PersonalInformation -@_spi(AdyenInternal) case email -``` -```javascript -// Parent: PersonalInformation -@_spi(AdyenInternal) case phone -``` -```javascript -// Parent: PersonalInformation -@_spi(AdyenInternal) case address -``` -```javascript -// Parent: PersonalInformation -@_spi(AdyenInternal) case deliveryAddress -``` -```javascript -// Parent: PersonalInformation -@_spi(AdyenInternal) case custom(any Adyen.FormItemInjector) -``` -```javascript -// Parent: PersonalInformation -@_spi(AdyenInternal) public static func ==(_: Adyen.PersonalInformation, _: Adyen.PersonalInformation) -> Swift.Bool -``` -```javascript -// Parent: Root -open class AbstractPersonalInformationComponent : AdyenContextAware, Component, LoadingComponent, PartialPaymentOrderAware, PaymentAware, PaymentComponent, PaymentMethodAware, PresentableComponent, TrackableComponent, ViewControllerDelegate, ViewControllerPresenter -``` -```javascript -// Parent: AbstractPersonalInformationComponent -public typealias Configuration = Adyen.PersonalInformationConfiguration -``` -```javascript -// Parent: AbstractPersonalInformationComponent -@_spi(AdyenInternal) public let context: Adyen.AdyenContext { get } -``` -```javascript -// Parent: AbstractPersonalInformationComponent -public let paymentMethod: any Adyen.PaymentMethod { get } -``` -```javascript -// Parent: AbstractPersonalInformationComponent -public weak var delegate: (any Adyen.PaymentComponentDelegate)? { get set } -``` -```javascript -// Parent: AbstractPersonalInformationComponent -public lazy var viewController: UIKit.UIViewController { get set } -``` -```javascript -// Parent: AbstractPersonalInformationComponent -public let requiresModalPresentation: Swift.Bool { get } -``` -```javascript -// Parent: AbstractPersonalInformationComponent -@_spi(AdyenInternal) public var configuration: Adyen.AbstractPersonalInformationComponent.Configuration { get set } -``` -```javascript -// Parent: AbstractPersonalInformationComponent -@_spi(AdyenInternal) public init(paymentMethod: any Adyen.PaymentMethod, context: Adyen.AdyenContext, fields: [Adyen.PersonalInformation], configuration: Adyen.AbstractPersonalInformationComponent.Configuration) -> Adyen.AbstractPersonalInformationComponent -``` -```javascript -// Parent: AbstractPersonalInformationComponent -@_spi(AdyenInternal) public var firstNameItem: Adyen.FormTextInputItem? { get } -``` -```javascript -// Parent: AbstractPersonalInformationComponent -@_spi(AdyenInternal) public var lastNameItem: Adyen.FormTextInputItem? { get } -``` -```javascript -// Parent: AbstractPersonalInformationComponent -@_spi(AdyenInternal) public var emailItem: Adyen.FormTextInputItem? { get } -``` -```javascript -// Parent: AbstractPersonalInformationComponent -@_spi(AdyenInternal) public var addressItem: Adyen.FormAddressPickerItem? { get } -``` -```javascript -// Parent: AbstractPersonalInformationComponent -@_spi(AdyenInternal) public var deliveryAddressItem: Adyen.FormAddressPickerItem? { get } -``` -```javascript -// Parent: AbstractPersonalInformationComponent -@_spi(AdyenInternal) public var phoneItem: Adyen.FormPhoneNumberItem? { get } -``` -```javascript -// Parent: AbstractPersonalInformationComponent -@_spi(AdyenInternal) open func submitButtonTitle() -> Swift.String -``` -```javascript -// Parent: AbstractPersonalInformationComponent -@_spi(AdyenInternal) open func createPaymentDetails() throws -> any Adyen.PaymentMethodDetails -``` -```javascript -// Parent: AbstractPersonalInformationComponent -@_spi(AdyenInternal) open func phoneExtensions() -> [Adyen.PhoneExtension] -``` -```javascript -// Parent: AbstractPersonalInformationComponent -@_spi(AdyenInternal) open func addressViewModelBuilder() -> any Adyen.AddressViewModelBuilder -``` -```javascript -// Parent: AbstractPersonalInformationComponent -@_spi(AdyenInternal) public func showValidation() -> Swift.Void -``` -```javascript -// Parent: AbstractPersonalInformationComponent -public func stopLoading() -> Swift.Void -``` -```javascript -// Parent: AbstractPersonalInformationComponent -@_spi(AdyenInternal) public func presentViewController(_: UIKit.UIViewController, animated: Swift.Bool) -> Swift.Void -``` -```javascript -// Parent: AbstractPersonalInformationComponent -@_spi(AdyenInternal) public func dismissViewController(animated: Swift.Bool) -> Swift.Void -``` -```javascript -// Parent: AbstractPersonalInformationComponent -@_spi(AdyenInternal) public func viewWillAppear(viewController: UIKit.UIViewController) -> Swift.Void -``` -```javascript -// Parent: AbstractPersonalInformationComponent -@_spi(AdyenInternal) public func viewDidLoad(viewController: UIKit.UIViewController) -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol FormItemInjector -``` -```javascript -// Parent: FormItemInjector -@_spi(AdyenInternal) public func inject(into: Adyen.FormViewController) -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct CustomFormItemInjector : FormItemInjector -``` -```javascript -// Parent: CustomFormItemInjector -@_spi(AdyenInternal) public init(item: T) -> Adyen.CustomFormItemInjector -``` -```javascript -// Parent: CustomFormItemInjector -@_spi(AdyenInternal) public func inject(into: Adyen.FormViewController) -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class AlreadyPaidPaymentComponent : AdyenContextAware, Component, PartialPaymentOrderAware, PaymentComponent, PaymentMethodAware -``` -```javascript -// Parent: AlreadyPaidPaymentComponent -@_spi(AdyenInternal) public let context: Adyen.AdyenContext { get } -``` -```javascript -// Parent: AlreadyPaidPaymentComponent -@_spi(AdyenInternal) public let paymentMethod: any Adyen.PaymentMethod { get } -``` -```javascript -// Parent: AlreadyPaidPaymentComponent -@_spi(AdyenInternal) public weak var delegate: (any Adyen.PaymentComponentDelegate)? { get set } -``` -```javascript -// Parent: AlreadyPaidPaymentComponent -@_spi(AdyenInternal) public init(paymentMethod: any Adyen.PaymentMethod, context: Adyen.AdyenContext) -> Adyen.AlreadyPaidPaymentComponent -``` -```javascript -// Parent: Root -public protocol AnyCashAppPayConfiguration -``` -```javascript -// Parent: AnyCashAppPayConfiguration -public var redirectURL: Foundation.URL { get } -``` -```javascript -// Parent: AnyCashAppPayConfiguration -public var referenceId: Swift.String? { get } -``` -```javascript -// Parent: AnyCashAppPayConfiguration -public var showsStorePaymentMethodField: Swift.Bool { get } -``` -```javascript -// Parent: AnyCashAppPayConfiguration -public var storePaymentMethod: Swift.Bool { get } -``` -```javascript -// Parent: Root -public struct ActionComponentData -``` -```javascript -// Parent: ActionComponentData -public let details: any Adyen.AdditionalDetails { get } -``` -```javascript -// Parent: ActionComponentData -public let paymentData: Swift.String? { get } -``` -```javascript -// Parent: ActionComponentData -public init(details: any Adyen.AdditionalDetails, paymentData: Swift.String?) -> Adyen.ActionComponentData -``` -```javascript -// Parent: Root -public protocol AnyBasicComponentConfiguration : Localizable -``` -```javascript -// Parent: Root -public protocol AnyPersonalInformationConfiguration : AnyBasicComponentConfiguration, Localizable -``` -```javascript -// Parent: AnyPersonalInformationConfiguration -public var shopperInformation: Adyen.PrefilledShopperInformation? { get } -``` -```javascript -// Parent: Root -public struct BasicComponentConfiguration : AnyBasicComponentConfiguration, Localizable -``` -```javascript -// Parent: BasicComponentConfiguration -public var style: Adyen.FormComponentStyle { get set } -``` -```javascript -// Parent: BasicComponentConfiguration -public var localizationParameters: Adyen.LocalizationParameters? { get set } -``` -```javascript -// Parent: BasicComponentConfiguration -public init(style: Adyen.FormComponentStyle = $DEFAULT_ARG, localizationParameters: Adyen.LocalizationParameters? = $DEFAULT_ARG) -> Adyen.BasicComponentConfiguration -``` -```javascript -// Parent: Root -public struct PersonalInformationConfiguration : AnyBasicComponentConfiguration, AnyPersonalInformationConfiguration, Localizable -``` -```javascript -// Parent: PersonalInformationConfiguration -public var style: Adyen.FormComponentStyle { get set } -``` -```javascript -// Parent: PersonalInformationConfiguration -public var shopperInformation: Adyen.PrefilledShopperInformation? { get set } -``` -```javascript -// Parent: PersonalInformationConfiguration -public var localizationParameters: Adyen.LocalizationParameters? { get set } -``` -```javascript -// Parent: PersonalInformationConfiguration -public init(style: Adyen.FormComponentStyle = $DEFAULT_ARG, shopperInformation: Adyen.PrefilledShopperInformation? = $DEFAULT_ARG, localizationParameters: Adyen.LocalizationParameters? = $DEFAULT_ARG) -> Adyen.PersonalInformationConfiguration -``` -```javascript -// Parent: Root -public enum PartialPaymentError : Equatable, Error, Hashable, LocalizedError, Sendable -``` -```javascript -// Parent: PartialPaymentError -case zeroRemainingAmount -``` -```javascript -// Parent: PartialPaymentError -case missingOrderData -``` -```javascript -// Parent: PartialPaymentError -case notSupportedForComponent -``` -```javascript -// Parent: PartialPaymentError -public var errorDescription: Swift.String? { get } -``` -```javascript -// Parent: PartialPaymentError -public static func __derived_enum_equals(_: Adyen.PartialPaymentError, _: Adyen.PartialPaymentError) -> Swift.Bool -``` -```javascript -// Parent: PartialPaymentError -public func hash(into: inout Swift.Hasher) -> Swift.Void -``` -```javascript -// Parent: PartialPaymentError -public var hashValue: Swift.Int { get } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class PresentableComponentWrapper : AdyenContextAware, Cancellable, Component, FinalizableComponent, LoadingComponent, PresentableComponent -``` -```javascript -// Parent: PresentableComponentWrapper -@_spi(AdyenInternal) public var apiContext: Adyen.APIContext { get } -``` -```javascript -// Parent: PresentableComponentWrapper -@_spi(AdyenInternal) public var context: Adyen.AdyenContext { get } -``` -```javascript -// Parent: PresentableComponentWrapper -@_spi(AdyenInternal) public let viewController: UIKit.UIViewController { get } -``` -```javascript -// Parent: PresentableComponentWrapper -@_spi(AdyenInternal) public let component: any Adyen.Component { get } -``` -```javascript -// Parent: PresentableComponentWrapper -@_spi(AdyenInternal) public var requiresModalPresentation: Swift.Bool { get set } -``` -```javascript -// Parent: PresentableComponentWrapper -@_spi(AdyenInternal) public var navBarType: Adyen.NavigationBarType { get set } -``` -```javascript -// Parent: PresentableComponentWrapper -@_spi(AdyenInternal) public init(component: any Adyen.Component, viewController: UIKit.UIViewController, navBarType: Adyen.NavigationBarType = $DEFAULT_ARG) -> Adyen.PresentableComponentWrapper -``` -```javascript -// Parent: PresentableComponentWrapper -@_spi(AdyenInternal) public func didCancel() -> Swift.Void -``` -```javascript -// Parent: PresentableComponentWrapper -@_spi(AdyenInternal) public func didFinalize(with: Swift.Bool, completion: (() -> Swift.Void)?) -> Swift.Void -``` -```javascript -// Parent: PresentableComponentWrapper -@_spi(AdyenInternal) public func stopLoading() -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol InstallmentConfigurationAware : AdyenSessionAware -``` -```javascript -// Parent: InstallmentConfigurationAware -@_spi(AdyenInternal) public var installmentConfiguration: Adyen.InstallmentConfiguration? { get } -``` -```javascript -// Parent: Root -public struct InstallmentOptions : Decodable, Encodable, Equatable -``` -```javascript -// Parent: InstallmentOptions -@_spi(AdyenInternal) public let regularInstallmentMonths: [Swift.UInt] { get } -``` -```javascript -// Parent: InstallmentOptions -@_spi(AdyenInternal) public let includesRevolving: Swift.Bool { get } -``` -```javascript -// Parent: InstallmentOptions -public init(monthValues: [Swift.UInt], includesRevolving: Swift.Bool) -> Adyen.InstallmentOptions -``` -```javascript -// Parent: InstallmentOptions -public init(maxInstallmentMonth: Swift.UInt, includesRevolving: Swift.Bool) -> Adyen.InstallmentOptions -``` -```javascript -// Parent: InstallmentOptions -@_spi(AdyenInternal) public init(from: any Swift.Decoder) throws -> Adyen.InstallmentOptions -``` -```javascript -// Parent: InstallmentOptions -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: InstallmentOptions -public static func __derived_struct_equals(_: Adyen.InstallmentOptions, _: Adyen.InstallmentOptions) -> Swift.Bool -``` -```javascript -// Parent: Root -public struct InstallmentConfiguration : Decodable -``` -```javascript -// Parent: InstallmentConfiguration -@_spi(AdyenInternal) public let defaultOptions: Adyen.InstallmentOptions? { get } -``` -```javascript -// Parent: InstallmentConfiguration -@_spi(AdyenInternal) public let cardBasedOptions: [Adyen.CardType : Adyen.InstallmentOptions]? { get } -``` -```javascript -// Parent: InstallmentConfiguration -@_spi(AdyenInternal) public var showInstallmentAmount: Swift.Bool { get set } -``` -```javascript -// Parent: InstallmentConfiguration -public init(cardBasedOptions: [Adyen.CardType : Adyen.InstallmentOptions], defaultOptions: Adyen.InstallmentOptions, showInstallmentAmount: Swift.Bool = $DEFAULT_ARG) -> Adyen.InstallmentConfiguration -``` -```javascript -// Parent: InstallmentConfiguration -public init(cardBasedOptions: [Adyen.CardType : Adyen.InstallmentOptions], showInstallmentAmount: Swift.Bool = $DEFAULT_ARG) -> Adyen.InstallmentConfiguration -``` -```javascript -// Parent: InstallmentConfiguration -public init(defaultOptions: Adyen.InstallmentOptions, showInstallmentAmount: Swift.Bool = $DEFAULT_ARG) -> Adyen.InstallmentConfiguration -``` -```javascript -// Parent: InstallmentConfiguration -@_spi(AdyenInternal) public init(from: any Swift.Decoder) throws -> Adyen.InstallmentConfiguration -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol PaymentInitiable -``` -```javascript -// Parent: PaymentInitiable -@_spi(AdyenInternal) public func initiatePayment() -> Swift.Void -``` -```javascript -// Parent: Root -public final class InstantPaymentComponent : AdyenContextAware, Component, PartialPaymentOrderAware, PaymentComponent, PaymentInitiable, PaymentMethodAware -``` -```javascript -// Parent: InstantPaymentComponent -@_spi(AdyenInternal) public let context: Adyen.AdyenContext { get } -``` -```javascript -// Parent: InstantPaymentComponent -public let paymentData: Adyen.PaymentComponentData { get } -``` -```javascript -// Parent: InstantPaymentComponent -public let paymentMethod: any Adyen.PaymentMethod { get } -``` -```javascript -// Parent: InstantPaymentComponent -public weak var delegate: (any Adyen.PaymentComponentDelegate)? { get set } -``` -```javascript -// Parent: InstantPaymentComponent -public init(paymentMethod: any Adyen.PaymentMethod, context: Adyen.AdyenContext, paymentData: Adyen.PaymentComponentData) -> Adyen.InstantPaymentComponent -``` -```javascript -// Parent: InstantPaymentComponent -public init(paymentMethod: any Adyen.PaymentMethod, context: Adyen.AdyenContext, order: Adyen.PartialPaymentOrder?) -> Adyen.InstantPaymentComponent -``` -```javascript -// Parent: InstantPaymentComponent -public func initiatePayment() -> Swift.Void -``` -```javascript -// Parent: Root -public struct InstantPaymentDetails : Details, Encodable, OpaqueEncodable, PaymentMethodDetails -``` -```javascript -// Parent: InstantPaymentDetails -@_spi(AdyenInternal) public var checkoutAttemptId: Swift.String? { get set } -``` -```javascript -// Parent: InstantPaymentDetails -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: InstantPaymentDetails -public init(type: Adyen.PaymentMethodType) -> Adyen.InstantPaymentDetails -``` -```javascript -// Parent: InstantPaymentDetails -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: Root -public final class StoredPaymentMethodComponent : AdyenContextAware, Component, PartialPaymentOrderAware, PaymentAware, PaymentComponent, PaymentMethodAware, PresentableComponent, TrackableComponent -``` -```javascript -// Parent: StoredPaymentMethodComponent -public var configuration: Adyen.StoredPaymentMethodComponent.Configuration { get set } -``` -```javascript -// Parent: StoredPaymentMethodComponent -public let context: Adyen.AdyenContext { get } -``` -```javascript -// Parent: StoredPaymentMethodComponent -public var paymentMethod: any Adyen.PaymentMethod { get } -``` -```javascript -// Parent: StoredPaymentMethodComponent -public weak var delegate: (any Adyen.PaymentComponentDelegate)? { get set } -``` -```javascript -// Parent: StoredPaymentMethodComponent -public init(paymentMethod: any Adyen.StoredPaymentMethod, context: Adyen.AdyenContext, configuration: Adyen.StoredPaymentMethodComponent.Configuration = $DEFAULT_ARG) -> Adyen.StoredPaymentMethodComponent -``` -```javascript -// Parent: StoredPaymentMethodComponent -public lazy var viewController: UIKit.UIViewController { get set } -``` -```javascript -// Parent: StoredPaymentMethodComponent -public struct Configuration : AnyBasicComponentConfiguration, Localizable -``` -```javascript -// Parent: StoredPaymentMethodComponent.Configuration -public var localizationParameters: Adyen.LocalizationParameters? { get set } -``` -```javascript -// Parent: StoredPaymentMethodComponent.Configuration -public init(localizationParameters: Adyen.LocalizationParameters? = $DEFAULT_ARG) -> Adyen.StoredPaymentMethodComponent.Configuration -``` -```javascript -// Parent: Root -public struct StoredPaymentDetails : Details, Encodable, OpaqueEncodable, PaymentMethodDetails -``` -```javascript -// Parent: StoredPaymentDetails -@_spi(AdyenInternal) public var checkoutAttemptId: Swift.String? { get set } -``` -```javascript -// Parent: StoredPaymentDetails -public init(paymentMethod: any Adyen.StoredPaymentMethod) -> Adyen.StoredPaymentDetails -``` -```javascript -// Parent: StoredPaymentDetails -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: Root -public protocol ActionComponent : AdyenContextAware, Component -``` -```javascript -// Parent: ActionComponent -public var delegate: (any Adyen.ActionComponentDelegate)? { get set } -``` -```javascript -// Parent: Root -public protocol ActionComponentDelegate -``` -```javascript -// Parent: ActionComponentDelegate -public func didOpenExternalApplication(component: any Adyen.ActionComponent) -> Swift.Void -``` -```javascript -// Parent: ActionComponentDelegate -public func didProvide(_: Adyen.ActionComponentData, from: any Adyen.ActionComponent) -> Swift.Void -``` -```javascript -// Parent: ActionComponentDelegate -public func didComplete(from: any Adyen.ActionComponent) -> Swift.Void -``` -```javascript -// Parent: ActionComponentDelegate -public func didFail(with: any Swift.Error, from: any Adyen.ActionComponent) -> Swift.Void -``` -```javascript -// Parent: ActionComponentDelegate -public func didOpenExternalApplication(component: any Adyen.ActionComponent) -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol AdyenSessionAware -``` -```javascript -// Parent: AdyenSessionAware -@_spi(AdyenInternal) public var isSession: Swift.Bool { get } -``` -```javascript -// Parent: Root -public protocol AnyDropInComponent : AdyenContextAware, Component, PresentableComponent -``` -```javascript -// Parent: AnyDropInComponent -public var delegate: (any Adyen.DropInComponentDelegate)? { get set } -``` -```javascript -// Parent: AnyDropInComponent -public func reload(with: Adyen.PartialPaymentOrder, _: Adyen.PaymentMethods) throws -> Swift.Void -``` -```javascript -// Parent: Root -public protocol Component : AdyenContextAware -``` -```javascript -// Parent: Component -public func finalizeIfNeeded(with: Swift.Bool, completion: (() -> Swift.Void)?) -> Swift.Void -``` -```javascript -// Parent: Component -public func cancelIfNeeded() -> Swift.Void -``` -```javascript -// Parent: Component -public func stopLoadingIfNeeded() -> Swift.Void -``` -```javascript -// Parent: Component -@_spi(AdyenInternal) public var _isDropIn: Swift.Bool { get set } -``` -```javascript -// Parent: Root -public protocol FinalizableComponent : AdyenContextAware, Component -``` -```javascript -// Parent: FinalizableComponent -public func didFinalize(with: Swift.Bool, completion: (() -> Swift.Void)?) -> Swift.Void -``` -```javascript -// Parent: Root -public protocol Details : Encodable, OpaqueEncodable -``` -```javascript -// Parent: Root -public protocol PaymentMethodDetails : Details, Encodable, OpaqueEncodable -``` -```javascript -// Parent: PaymentMethodDetails -@_spi(AdyenInternal) public var checkoutAttemptId: Swift.String? { get set } -``` -```javascript -// Parent: PaymentMethodDetails -@_spi(AdyenInternal) public var checkoutAttemptId: Swift.String? { get set } -``` -```javascript -// Parent: Root -public protocol AdditionalDetails : Details, Encodable, OpaqueEncodable -``` -```javascript -// Parent: Root -public protocol DeviceDependent -``` -```javascript -// Parent: DeviceDependent -public static func isDeviceSupported() -> Swift.Bool -``` -```javascript -// Parent: Root -public protocol DropInComponentDelegate -``` -```javascript -// Parent: DropInComponentDelegate -public func didSubmit(_: Adyen.PaymentComponentData, from: any Adyen.PaymentComponent, in: any Adyen.AnyDropInComponent) -> Swift.Void -``` -```javascript -// Parent: DropInComponentDelegate -public func didFail(with: any Swift.Error, from: any Adyen.PaymentComponent, in: any Adyen.AnyDropInComponent) -> Swift.Void -``` -```javascript -// Parent: DropInComponentDelegate -public func didProvide(_: Adyen.ActionComponentData, from: any Adyen.ActionComponent, in: any Adyen.AnyDropInComponent) -> Swift.Void -``` -```javascript -// Parent: DropInComponentDelegate -public func didComplete(from: any Adyen.ActionComponent, in: any Adyen.AnyDropInComponent) -> Swift.Void -``` -```javascript -// Parent: DropInComponentDelegate -public func didFail(with: any Swift.Error, from: any Adyen.ActionComponent, in: any Adyen.AnyDropInComponent) -> Swift.Void -``` -```javascript -// Parent: DropInComponentDelegate -public func didOpenExternalApplication(component: any Adyen.ActionComponent, in: any Adyen.AnyDropInComponent) -> Swift.Void -``` -```javascript -// Parent: DropInComponentDelegate -public func didFail(with: any Swift.Error, from: any Adyen.AnyDropInComponent) -> Swift.Void -``` -```javascript -// Parent: DropInComponentDelegate -public func didCancel(component: any Adyen.PaymentComponent, from: any Adyen.AnyDropInComponent) -> Swift.Void -``` -```javascript -// Parent: DropInComponentDelegate -public func didCancel(component: any Adyen.PaymentComponent, from: any Adyen.AnyDropInComponent) -> Swift.Void -``` -```javascript -// Parent: DropInComponentDelegate -public func didOpenExternalApplication(component: any Adyen.ActionComponent, in: any Adyen.AnyDropInComponent) -> Swift.Void -``` -```javascript -// Parent: Root -public protocol ComponentLoader : LoadingComponent -``` -```javascript -// Parent: ComponentLoader -public func startLoading(for: any Adyen.PaymentComponent) -> Swift.Void -``` -```javascript -// Parent: Root -public protocol LoadingComponent -``` -```javascript -// Parent: LoadingComponent -public func stopLoading() -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol PartialPaymentComponent : AdyenContextAware, Component, PartialPaymentOrderAware, PaymentComponent, PaymentMethodAware -``` -```javascript -// Parent: PartialPaymentComponent -@_spi(AdyenInternal) public var partialPaymentDelegate: (any Adyen.PartialPaymentDelegate)? { get set } -``` -```javascript -// Parent: PartialPaymentComponent -@_spi(AdyenInternal) public var readyToSubmitComponentDelegate: (any Adyen.ReadyToSubmitPaymentComponentDelegate)? { get set } -``` -```javascript -// Parent: Root -public protocol PartialPaymentDelegate -``` -```javascript -// Parent: PartialPaymentDelegate -public func checkBalance(with: Adyen.PaymentComponentData, component: any Adyen.Component, completion: (Swift.Result) -> Swift.Void) -> Swift.Void -``` -```javascript -// Parent: PartialPaymentDelegate -public func requestOrder(for: any Adyen.Component, completion: (Swift.Result) -> Swift.Void) -> Swift.Void -``` -```javascript -// Parent: PartialPaymentDelegate -public func cancelOrder(_: Adyen.PartialPaymentOrder, component: any Adyen.Component) -> Swift.Void -``` -```javascript -// Parent: Root -public protocol PartialPaymentOrderAware -``` -```javascript -// Parent: PartialPaymentOrderAware -public var order: Adyen.PartialPaymentOrder? { get set } -``` -```javascript -// Parent: PartialPaymentOrderAware -@_spi(AdyenInternal) public var order: Adyen.PartialPaymentOrder? { get set } -``` -```javascript -// Parent: Root -public protocol PaymentAware -``` -```javascript -// Parent: PaymentAware -public var payment: Adyen.Payment? { get } -``` -```javascript -// Parent: Root -public protocol PaymentMethodAware -``` -```javascript -// Parent: PaymentMethodAware -public var paymentMethod: any Adyen.PaymentMethod { get } -``` -```javascript -// Parent: Root -public protocol PaymentComponent : AdyenContextAware, Component, PartialPaymentOrderAware, PaymentMethodAware -``` -```javascript -// Parent: PaymentComponent -public var delegate: (any Adyen.PaymentComponentDelegate)? { get set } -``` -```javascript -// Parent: PaymentComponent -@_spi(AdyenInternal) public func submit(data: Adyen.PaymentComponentData, component: (any Adyen.PaymentComponent)? = $DEFAULT_ARG) -> Swift.Void -``` -```javascript -// Parent: Root -public protocol PaymentComponentDelegate -``` -```javascript -// Parent: PaymentComponentDelegate -public func didSubmit(_: Adyen.PaymentComponentData, from: any Adyen.PaymentComponent) -> Swift.Void -``` -```javascript -// Parent: PaymentComponentDelegate -public func didFail(with: any Swift.Error, from: any Adyen.PaymentComponent) -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol PaymentComponentBuilder : AdyenContextAware -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.StoredCardPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: any Adyen.StoredPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.StoredBCMCPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.StoredACHDirectDebitPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.CardPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.BCMCPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.IssuerListPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.SEPADirectDebitPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.BACSDirectDebitPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.ACHDirectDebitPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.ApplePayPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.WeChatPayPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.QiwiWalletPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.MBWayPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.BLIKPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.DokuPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.EContextPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.GiftCardPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.MealVoucherPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.BoletoPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.AffirmPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.AtomePaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.OnlineBankingPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.UPIPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.CashAppPayPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.StoredCashAppPayPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: Adyen.TwintPaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentComponentBuilder -@_spi(AdyenInternal) public func build(paymentMethod: any Adyen.PaymentMethod) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: Root -public protocol PaymentMethod : Decodable, Encodable -``` -```javascript -// Parent: PaymentMethod -public var type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: PaymentMethod -public var name: Swift.String { get } -``` -```javascript -// Parent: PaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: PaymentMethod -@_spi(AdyenInternal) public func defaultDisplayInformation(using: Adyen.LocalizationParameters?) -> Adyen.DisplayInformation -``` -```javascript -// Parent: PaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: PaymentMethod -@_spi(AdyenInternal) public func displayInformation(using: Adyen.LocalizationParameters?) -> Adyen.DisplayInformation -``` -```javascript -// Parent: PaymentMethod -@_spi(AdyenInternal) public func defaultDisplayInformation(using: Adyen.LocalizationParameters?) -> Adyen.DisplayInformation -``` -```javascript -// Parent: Root -public protocol PartialPaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: Root -public protocol StoredPaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: StoredPaymentMethod -public var identifier: Swift.String { get } -``` -```javascript -// Parent: StoredPaymentMethod -public var supportedShopperInteractions: [Adyen.ShopperInteraction] { get } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public func ==(_: any Adyen.StoredPaymentMethod, _: any Adyen.StoredPaymentMethod) -> Swift.Bool -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public func !=(_: any Adyen.StoredPaymentMethod, _: any Adyen.StoredPaymentMethod) -> Swift.Bool -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public func ==(_: any Adyen.PaymentMethod, _: any Adyen.PaymentMethod) -> Swift.Bool -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public func !=(_: any Adyen.PaymentMethod, _: any Adyen.PaymentMethod) -> Swift.Bool -``` -```javascript -// Parent: Root -public protocol Localizable -``` -```javascript -// Parent: Localizable -public var localizationParameters: Adyen.LocalizationParameters? { get set } -``` -```javascript -// Parent: Root -public protocol Cancellable -``` -```javascript -// Parent: Cancellable -public func didCancel() -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol AnyNavigationBar -``` -```javascript -// Parent: AnyNavigationBar -@_spi(AdyenInternal) public var onCancelHandler: (() -> Swift.Void)? { get set } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public enum NavigationBarType -``` -```javascript -// Parent: NavigationBarType -@_spi(AdyenInternal) case regular -``` -```javascript -// Parent: NavigationBarType -@_spi(AdyenInternal) case custom(any Adyen.AnyNavigationBar) -``` -```javascript -// Parent: Root -public protocol PresentableComponent : AdyenContextAware, Component -``` -```javascript -// Parent: PresentableComponent -public var requiresModalPresentation: Swift.Bool { get } -``` -```javascript -// Parent: PresentableComponent -public var viewController: UIKit.UIViewController { get } -``` -```javascript -// Parent: PresentableComponent -@_spi(AdyenInternal) public var navBarType: Adyen.NavigationBarType { get } -``` -```javascript -// Parent: PresentableComponent -@_spi(AdyenInternal) public var requiresModalPresentation: Swift.Bool { get } -``` -```javascript -// Parent: PresentableComponent -@_spi(AdyenInternal) public var navBarType: Adyen.NavigationBarType { get } -``` -```javascript -// Parent: Root -public protocol PresentationDelegate -``` -```javascript -// Parent: PresentationDelegate -public func present(component: any Adyen.PresentableComponent) -> Swift.Void -``` -```javascript -// Parent: Root -public protocol ReadyToSubmitPaymentComponentDelegate -``` -```javascript -// Parent: ReadyToSubmitPaymentComponentDelegate -public func showConfirmation(for: Adyen.InstantPaymentComponent, with: Adyen.PartialPaymentOrder?) -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol StorePaymentMethodFieldAware : AdyenSessionAware -``` -```javascript -// Parent: StorePaymentMethodFieldAware -@_spi(AdyenInternal) public var showStorePaymentMethodField: Swift.Bool? { get } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol SessionStoredPaymentMethodsDelegate : AdyenSessionAware, StoredPaymentMethodsDelegate -``` -```javascript -// Parent: SessionStoredPaymentMethodsDelegate -@_spi(AdyenInternal) public var showRemovePaymentMethodButton: Swift.Bool { get } -``` -```javascript -// Parent: SessionStoredPaymentMethodsDelegate -@_spi(AdyenInternal) public func disable(storedPaymentMethod: any Adyen.StoredPaymentMethod, dropInComponent: any Adyen.AnyDropInComponent, completion: Adyen.Completion) -> Swift.Void -``` -```javascript -// Parent: Root -public protocol StoredPaymentMethodsDelegate -``` -```javascript -// Parent: StoredPaymentMethodsDelegate -public func disable(storedPaymentMethod: any Adyen.StoredPaymentMethod, completion: Adyen.Completion) -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol TrackableComponent : AdyenContextAware, Component -``` -```javascript -// Parent: TrackableComponent -@_spi(AdyenInternal) public var analyticsFlavor: Adyen.AnalyticsFlavor { get } -``` -```javascript -// Parent: TrackableComponent -@_spi(AdyenInternal) public func sendInitialAnalytics() -> Swift.Void -``` -```javascript -// Parent: TrackableComponent -@_spi(AdyenInternal) public func sendDidLoadEvent() -> Swift.Void -``` -```javascript -// Parent: TrackableComponent -@_spi(AdyenInternal) public func viewDidLoad(viewController: UIKit.UIViewController) -> Swift.Void -``` -```javascript -// Parent: TrackableComponent -@_spi(AdyenInternal) public func sendInitialAnalytics() -> Swift.Void -``` -```javascript -// Parent: TrackableComponent -@_spi(AdyenInternal) public var analyticsFlavor: Adyen.AnalyticsFlavor { get } -``` -```javascript -// Parent: TrackableComponent -@_spi(AdyenInternal) public func sendDidLoadEvent() -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol ViewControllerPresenter -``` -```javascript -// Parent: ViewControllerPresenter -@_spi(AdyenInternal) public func presentViewController(_: UIKit.UIViewController, animated: Swift.Bool) -> Swift.Void -``` -```javascript -// Parent: ViewControllerPresenter -@_spi(AdyenInternal) public func dismissViewController(animated: Swift.Bool) -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public class WeakReferenceViewControllerPresenter : ViewControllerPresenter -``` -```javascript -// Parent: WeakReferenceViewControllerPresenter -@_spi(AdyenInternal) public init(_: any Adyen.ViewControllerPresenter) -> Adyen.WeakReferenceViewControllerPresenter -``` -```javascript -// Parent: WeakReferenceViewControllerPresenter -@_spi(AdyenInternal) public func presentViewController(_: UIKit.UIViewController, animated: Swift.Bool) -> Swift.Void -``` -```javascript -// Parent: WeakReferenceViewControllerPresenter -@_spi(AdyenInternal) public func dismissViewController(animated: Swift.Bool) -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct APIError : Decodable, Error, ErrorResponse, LocalizedError, Response, Sendable -``` -```javascript -// Parent: APIError -@_spi(AdyenInternal) public let status: Swift.Int? { get } -``` -```javascript -// Parent: APIError -@_spi(AdyenInternal) public let errorCode: Swift.String { get } -``` -```javascript -// Parent: APIError -@_spi(AdyenInternal) public let errorMessage: Swift.String { get } -``` -```javascript -// Parent: APIError -@_spi(AdyenInternal) public let type: Adyen.APIErrorType { get } -``` -```javascript -// Parent: APIError -@_spi(AdyenInternal) public var errorDescription: Swift.String? { get } -``` -```javascript -// Parent: APIError -@_spi(AdyenInternal) public init(from: any Swift.Decoder) throws -> Adyen.APIError -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public enum APIErrorType : Decodable, Equatable, Hashable, RawRepresentable -``` -```javascript -// Parent: APIErrorType -@_spi(AdyenInternal) case internal -``` -```javascript -// Parent: APIErrorType -@_spi(AdyenInternal) case validation -``` -```javascript -// Parent: APIErrorType -@_spi(AdyenInternal) case security -``` -```javascript -// Parent: APIErrorType -@_spi(AdyenInternal) case configuration -``` -```javascript -// Parent: APIErrorType -@_spi(AdyenInternal) case urlError -``` -```javascript -// Parent: APIErrorType -@_spi(AdyenInternal) case noInternet -``` -```javascript -// Parent: APIErrorType -@_spi(AdyenInternal) case sessionExpired -``` -```javascript -// Parent: APIErrorType -@_spi(AdyenInternal) @inlinable public init(rawValue: Swift.String) -> Adyen.APIErrorType? -``` -```javascript -// Parent: APIErrorType -@_spi(AdyenInternal) public typealias RawValue = Swift.String -``` -```javascript -// Parent: APIErrorType -@_spi(AdyenInternal) public var rawValue: Swift.String { get } -``` -```javascript -// Parent: Root -public enum AppleWalletError : Equatable, Error, Hashable, LocalizedError, Sendable -``` -```javascript -// Parent: AppleWalletError -case failedToAddToAppleWallet -``` -```javascript -// Parent: AppleWalletError -public static func __derived_enum_equals(_: Adyen.AppleWalletError, _: Adyen.AppleWalletError) -> Swift.Bool -``` -```javascript -// Parent: AppleWalletError -public func hash(into: inout Swift.Hasher) -> Swift.Void -``` -```javascript -// Parent: AppleWalletError -public var hashValue: Swift.Int { get } -``` -```javascript -// Parent: Root -public enum ComponentError : Equatable, Error, Hashable, Sendable -``` -```javascript -// Parent: ComponentError -case cancelled -``` -```javascript -// Parent: ComponentError -case paymentMethodNotSupported -``` -```javascript -// Parent: ComponentError -public static func __derived_enum_equals(_: Adyen.ComponentError, _: Adyen.ComponentError) -> Swift.Bool -``` -```javascript -// Parent: ComponentError -public func hash(into: inout Swift.Hasher) -> Swift.Void -``` -```javascript -// Parent: ComponentError -public var hashValue: Swift.Int { get } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct UnknownError : Error, LocalizedError, Sendable -``` -```javascript -// Parent: UnknownError -@_spi(AdyenInternal) public var errorDescription: Swift.String? { get set } -``` -```javascript -// Parent: UnknownError -@_spi(AdyenInternal) public init(errorDescription: Swift.String? = $DEFAULT_ARG) -> Adyen.UnknownError -``` -```javascript -// Parent: Root -public enum CardType : Decodable, Encodable, Equatable, Hashable, RawRepresentable -``` -```javascript -// Parent: CardType -case accel -``` -```javascript -// Parent: CardType -case alphaBankBonusMasterCard -``` -```javascript -// Parent: CardType -case alphaBankBonusVISA -``` -```javascript -// Parent: CardType -case argencard -``` -```javascript -// Parent: CardType -case americanExpress -``` -```javascript -// Parent: CardType -case bcmc -``` -```javascript -// Parent: CardType -case bijenkorfCard -``` -```javascript -// Parent: CardType -case cabal -``` -```javascript -// Parent: CardType -case carteBancaire -``` -```javascript -// Parent: CardType -case cencosud -``` -```javascript -// Parent: CardType -case chequeDejeneur -``` -```javascript -// Parent: CardType -case chinaUnionPay -``` -```javascript -// Parent: CardType -case codensa -``` -```javascript -// Parent: CardType -case creditUnion24 -``` -```javascript -// Parent: CardType -case dankort -``` -```javascript -// Parent: CardType -case dankortVISA -``` -```javascript -// Parent: CardType -case diners -``` -```javascript -// Parent: CardType -case discover -``` -```javascript -// Parent: CardType -case elo -``` -```javascript -// Parent: CardType -case forbrugsforeningen -``` -```javascript -// Parent: CardType -case hiper -``` -```javascript -// Parent: CardType -case hipercard -``` -```javascript -// Parent: CardType -case jcb -``` -```javascript -// Parent: CardType -case karenMillen -``` -```javascript -// Parent: CardType -case kcp -``` -```javascript -// Parent: CardType -case koreanLocalCard -``` -```javascript -// Parent: CardType -case laser -``` -```javascript -// Parent: CardType -case maestro -``` -```javascript -// Parent: CardType -case maestroUK -``` -```javascript -// Parent: CardType -case masterCard -``` -```javascript -// Parent: CardType -case mir -``` -```javascript -// Parent: CardType -case naranja -``` -```javascript -// Parent: CardType -case netplus -``` -```javascript -// Parent: CardType -case nyce -``` -```javascript -// Parent: CardType -case oasis -``` -```javascript -// Parent: CardType -case pulse -``` -```javascript -// Parent: CardType -case shopping -``` -```javascript -// Parent: CardType -case solo -``` -```javascript -// Parent: CardType -case star -``` -```javascript -// Parent: CardType -case troy -``` -```javascript -// Parent: CardType -case uatp -``` -```javascript -// Parent: CardType -case visa -``` -```javascript -// Parent: CardType -case warehouse -``` -```javascript -// Parent: CardType -case other(named: Swift.String) -``` -```javascript -// Parent: CardType -public init(rawValue: Swift.String) -> Adyen.CardType -``` -```javascript -// Parent: CardType -public var rawValue: Swift.String { get } -``` -```javascript -// Parent: CardType -@_spi(AdyenInternal) public var name: Swift.String { get } -``` -```javascript -// Parent: CardType -public typealias RawValue = Swift.String -``` -```javascript -// Parent: CardType -@_spi(AdyenInternal) public func matches(cardNumber: Swift.String) -> Swift.Bool -``` -```javascript -// Parent: Root -public struct DisplayInformation : Equatable -``` -```javascript -// Parent: DisplayInformation -public let title: Swift.String { get } -``` -```javascript -// Parent: DisplayInformation -public let subtitle: Swift.String? { get } -``` -```javascript -// Parent: DisplayInformation -@_spi(AdyenInternal) public let logoName: Swift.String { get } -``` -```javascript -// Parent: DisplayInformation -@_spi(AdyenInternal) public let disclosureText: Swift.String? { get } -``` -```javascript -// Parent: DisplayInformation -@_spi(AdyenInternal) public let footnoteText: Swift.String? { get } -``` -```javascript -// Parent: DisplayInformation -@_spi(AdyenInternal) public let accessibilityLabel: Swift.String? { get } -``` -```javascript -// Parent: DisplayInformation -public init(title: Swift.String, subtitle: Swift.String?, logoName: Swift.String, disclosureText: Swift.String? = $DEFAULT_ARG, footnoteText: Swift.String? = $DEFAULT_ARG, accessibilityLabel: Swift.String? = $DEFAULT_ARG) -> Adyen.DisplayInformation -``` -```javascript -// Parent: DisplayInformation -public static func __derived_struct_equals(_: Adyen.DisplayInformation, _: Adyen.DisplayInformation) -> Swift.Bool -``` -```javascript -// Parent: Root -public struct MerchantCustomDisplayInformation -``` -```javascript -// Parent: MerchantCustomDisplayInformation -public let title: Swift.String { get } -``` -```javascript -// Parent: MerchantCustomDisplayInformation -public let subtitle: Swift.String? { get } -``` -```javascript -// Parent: MerchantCustomDisplayInformation -public init(title: Swift.String, subtitle: Swift.String? = $DEFAULT_ARG) -> Adyen.MerchantCustomDisplayInformation -``` -```javascript -// Parent: Root -public enum ShopperInteraction : Decodable, Encodable, Equatable, Hashable, RawRepresentable -``` -```javascript -// Parent: ShopperInteraction -case shopperPresent -``` -```javascript -// Parent: ShopperInteraction -case shopperNotPresent -``` -```javascript -// Parent: ShopperInteraction -@inlinable public init(rawValue: Swift.String) -> Adyen.ShopperInteraction? -``` -```javascript -// Parent: ShopperInteraction -public typealias RawValue = Swift.String -``` -```javascript -// Parent: ShopperInteraction -public var rawValue: Swift.String { get } -``` -```javascript -// Parent: Root -public struct ACHDirectDebitPaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: ACHDirectDebitPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: ACHDirectDebitPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: ACHDirectDebitPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: ACHDirectDebitPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: ACHDirectDebitPaymentMethod -@_spi(AdyenInternal) public func defaultDisplayInformation(using: Adyen.LocalizationParameters?) -> Adyen.DisplayInformation -``` -```javascript -// Parent: ACHDirectDebitPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: ACHDirectDebitPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.ACHDirectDebitPaymentMethod -``` -```javascript -// Parent: Root -public struct StoredACHDirectDebitPaymentMethod : Decodable, Encodable, PaymentMethod, StoredPaymentMethod -``` -```javascript -// Parent: StoredACHDirectDebitPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: StoredACHDirectDebitPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: StoredACHDirectDebitPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: StoredACHDirectDebitPaymentMethod -public let identifier: Swift.String { get } -``` -```javascript -// Parent: StoredACHDirectDebitPaymentMethod -public let supportedShopperInteractions: [Adyen.ShopperInteraction] { get } -``` -```javascript -// Parent: StoredACHDirectDebitPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: StoredACHDirectDebitPaymentMethod -@_spi(AdyenInternal) public func defaultDisplayInformation(using: Adyen.LocalizationParameters?) -> Adyen.DisplayInformation -``` -```javascript -// Parent: StoredACHDirectDebitPaymentMethod -public let bankAccountNumber: Swift.String { get } -``` -```javascript -// Parent: StoredACHDirectDebitPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: StoredACHDirectDebitPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.StoredACHDirectDebitPaymentMethod -``` -```javascript -// Parent: Root -public protocol AnyCardPaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: AnyCardPaymentMethod -public var brands: [Adyen.CardType] { get } -``` -```javascript -// Parent: AnyCardPaymentMethod -public var fundingSource: Adyen.CardFundingSource? { get } -``` -```javascript -// Parent: Root -public enum CardFundingSource : Decodable, Encodable, Equatable, Hashable, RawRepresentable -``` -```javascript -// Parent: CardFundingSource -case debit -``` -```javascript -// Parent: CardFundingSource -case credit -``` -```javascript -// Parent: CardFundingSource -@inlinable public init(rawValue: Swift.String) -> Adyen.CardFundingSource? -``` -```javascript -// Parent: CardFundingSource -public typealias RawValue = Swift.String -``` -```javascript -// Parent: CardFundingSource -public var rawValue: Swift.String { get } -``` -```javascript -// Parent: Root -public enum PaymentMethodType : Decodable, Encodable, Equatable, Hashable, RawRepresentable -``` -```javascript -// Parent: PaymentMethodType -case card -``` -```javascript -// Parent: PaymentMethodType -case scheme -``` -```javascript -// Parent: PaymentMethodType -case ideal -``` -```javascript -// Parent: PaymentMethodType -case entercash -``` -```javascript -// Parent: PaymentMethodType -case eps -``` -```javascript -// Parent: PaymentMethodType -case dotpay -``` -```javascript -// Parent: PaymentMethodType -case onlineBankingPoland -``` -```javascript -// Parent: PaymentMethodType -case openBankingUK -``` -```javascript -// Parent: PaymentMethodType -case molPayEBankingFPXMY -``` -```javascript -// Parent: PaymentMethodType -case molPayEBankingTH -``` -```javascript -// Parent: PaymentMethodType -case molPayEBankingVN -``` -```javascript -// Parent: PaymentMethodType -case sepaDirectDebit -``` -```javascript -// Parent: PaymentMethodType -case applePay -``` -```javascript -// Parent: PaymentMethodType -case payPal -``` -```javascript -// Parent: PaymentMethodType -case bcmc -``` -```javascript -// Parent: PaymentMethodType -case bcmcMobile -``` -```javascript -// Parent: PaymentMethodType -case qiwiWallet -``` -```javascript -// Parent: PaymentMethodType -case weChatPaySDK -``` -```javascript -// Parent: PaymentMethodType -case mbWay -``` -```javascript -// Parent: PaymentMethodType -case blik -``` -```javascript -// Parent: PaymentMethodType -case dokuWallet -``` -```javascript -// Parent: PaymentMethodType -case dokuAlfamart -``` -```javascript -// Parent: PaymentMethodType -case dokuIndomaret -``` -```javascript -// Parent: PaymentMethodType -case giftcard -``` -```javascript -// Parent: PaymentMethodType -case doku -``` -```javascript -// Parent: PaymentMethodType -case econtextSevenEleven -``` -```javascript -// Parent: PaymentMethodType -case econtextStores -``` -```javascript -// Parent: PaymentMethodType -case econtextATM -``` -```javascript -// Parent: PaymentMethodType -case econtextOnline -``` -```javascript -// Parent: PaymentMethodType -case boleto -``` -```javascript -// Parent: PaymentMethodType -case affirm -``` -```javascript -// Parent: PaymentMethodType -case oxxo -``` -```javascript -// Parent: PaymentMethodType -case bacsDirectDebit -``` -```javascript -// Parent: PaymentMethodType -case achDirectDebit -``` -```javascript -// Parent: PaymentMethodType -case multibanco -``` -```javascript -// Parent: PaymentMethodType -case atome -``` -```javascript -// Parent: PaymentMethodType -case onlineBankingCZ -``` -```javascript -// Parent: PaymentMethodType -case onlineBankingSK -``` -```javascript -// Parent: PaymentMethodType -case mealVoucherNatixis -``` -```javascript -// Parent: PaymentMethodType -case mealVoucherGroupeUp -``` -```javascript -// Parent: PaymentMethodType -case mealVoucherSodexo -``` -```javascript -// Parent: PaymentMethodType -case upi -``` -```javascript -// Parent: PaymentMethodType -case cashAppPay -``` -```javascript -// Parent: PaymentMethodType -case twint -``` -```javascript -// Parent: PaymentMethodType -case other(Swift.String) -``` -```javascript -// Parent: PaymentMethodType -case bcmcMobileQR -``` -```javascript -// Parent: PaymentMethodType -case weChatMiniProgram -``` -```javascript -// Parent: PaymentMethodType -case weChatQR -``` -```javascript -// Parent: PaymentMethodType -case weChatPayWeb -``` -```javascript -// Parent: PaymentMethodType -case googlePay -``` -```javascript -// Parent: PaymentMethodType -case afterpay -``` -```javascript -// Parent: PaymentMethodType -case androidPay -``` -```javascript -// Parent: PaymentMethodType -case amazonPay -``` -```javascript -// Parent: PaymentMethodType -case upiCollect -``` -```javascript -// Parent: PaymentMethodType -case upiIntent -``` -```javascript -// Parent: PaymentMethodType -case upiQr -``` -```javascript -// Parent: PaymentMethodType -case bizum -``` -```javascript -// Parent: PaymentMethodType -public init(rawValue: Swift.String) -> Adyen.PaymentMethodType? -``` -```javascript -// Parent: PaymentMethodType -public var rawValue: Swift.String { get } -``` -```javascript -// Parent: PaymentMethodType -public typealias RawValue = Swift.String -``` -```javascript -// Parent: PaymentMethodType -@_spi(AdyenInternal) public var name: Swift.String { get } -``` -```javascript -// Parent: Root -public struct PaymentMethods : Decodable, Encodable -``` -```javascript -// Parent: PaymentMethods -public var paid: [any Adyen.PaymentMethod] { get set } -``` -```javascript -// Parent: PaymentMethods -public var regular: [any Adyen.PaymentMethod] { get set } -``` -```javascript -// Parent: PaymentMethods -public var stored: [any Adyen.StoredPaymentMethod] { get set } -``` -```javascript -// Parent: PaymentMethods -public init(regular: [any Adyen.PaymentMethod], stored: [any Adyen.StoredPaymentMethod]) -> Adyen.PaymentMethods -``` -```javascript -// Parent: PaymentMethods -public mutating func overrideDisplayInformation(ofStoredPaymentMethod: Adyen.PaymentMethodType, with: Adyen.MerchantCustomDisplayInformation, where: (T) -> Swift.Bool) -> Swift.Void -``` -```javascript -// Parent: PaymentMethods -public mutating func overrideDisplayInformation(ofStoredPaymentMethod: Adyen.PaymentMethodType, with: Adyen.MerchantCustomDisplayInformation) -> Swift.Void -``` -```javascript -// Parent: PaymentMethods -public mutating func overrideDisplayInformation(ofRegularPaymentMethod: Adyen.PaymentMethodType, with: Adyen.MerchantCustomDisplayInformation, where: (T) -> Swift.Bool) -> Swift.Void -``` -```javascript -// Parent: PaymentMethods -public mutating func overrideDisplayInformation(ofRegularPaymentMethod: Adyen.PaymentMethodType, with: Adyen.MerchantCustomDisplayInformation) -> Swift.Void -``` -```javascript -// Parent: PaymentMethods -public func paymentMethod(ofType: T.Type) -> T? -``` -```javascript -// Parent: PaymentMethods -public func paymentMethod(ofType: T.Type, where: (T) -> Swift.Bool) -> T? -``` -```javascript -// Parent: PaymentMethods -public func paymentMethod(ofType: Adyen.PaymentMethodType) -> (any Adyen.PaymentMethod)? -``` -```javascript -// Parent: PaymentMethods -public func paymentMethod(ofType: Adyen.PaymentMethodType, where: (T) -> Swift.Bool) -> T? -``` -```javascript -// Parent: PaymentMethods -public init(from: any Swift.Decoder) throws -> Adyen.PaymentMethods -``` -```javascript -// Parent: PaymentMethods -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: Root -public struct AffirmPaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: AffirmPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: AffirmPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: AffirmPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: AffirmPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: AffirmPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: AffirmPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.AffirmPaymentMethod -``` -```javascript -// Parent: Root -public struct ApplePayPaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: ApplePayPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: ApplePayPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: ApplePayPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: ApplePayPaymentMethod -public let brands: [Swift.String]? { get } -``` -```javascript -// Parent: ApplePayPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: ApplePayPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: ApplePayPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.ApplePayPaymentMethod -``` -```javascript -// Parent: Root -public struct AtomePaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: AtomePaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: AtomePaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: AtomePaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: AtomePaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: AtomePaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: AtomePaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.AtomePaymentMethod -``` -```javascript -// Parent: Root -public struct BACSDirectDebitPaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: BACSDirectDebitPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: BACSDirectDebitPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: BACSDirectDebitPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: BACSDirectDebitPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: BACSDirectDebitPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: BACSDirectDebitPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.BACSDirectDebitPaymentMethod -``` -```javascript -// Parent: Root -public struct BCMCPaymentMethod : AnyCardPaymentMethod, Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: BCMCPaymentMethod -public var type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: BCMCPaymentMethod -public var name: Swift.String { get } -``` -```javascript -// Parent: BCMCPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: BCMCPaymentMethod -public var brands: [Adyen.CardType] { get } -``` -```javascript -// Parent: BCMCPaymentMethod -public var fundingSource: Adyen.CardFundingSource? { get } -``` -```javascript -// Parent: BCMCPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.BCMCPaymentMethod -``` -```javascript -// Parent: BCMCPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: BCMCPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: Root -public struct BLIKPaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: BLIKPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: BLIKPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: BLIKPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: BLIKPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: BLIKPaymentMethod -public func defaultDisplayInformation(using: Adyen.LocalizationParameters?) -> Adyen.DisplayInformation -``` -```javascript -// Parent: BLIKPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: BLIKPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.BLIKPaymentMethod -``` -```javascript -// Parent: Root -public struct BoletoPaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: BoletoPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: BoletoPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: BoletoPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: BoletoPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: BoletoPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: BoletoPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.BoletoPaymentMethod -``` -```javascript -// Parent: Root -public struct CardPaymentMethod : AnyCardPaymentMethod, Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: CardPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: CardPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: CardPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: CardPaymentMethod -public let fundingSource: Adyen.CardFundingSource? { get } -``` -```javascript -// Parent: CardPaymentMethod -public let brands: [Adyen.CardType] { get } -``` -```javascript -// Parent: CardPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.CardPaymentMethod -``` -```javascript -// Parent: CardPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: CardPaymentMethod -public func defaultDisplayInformation(using: Adyen.LocalizationParameters?) -> Adyen.DisplayInformation -``` -```javascript -// Parent: CardPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: Root -public struct StoredCardPaymentMethod : AnyCardPaymentMethod, Decodable, Encodable, PaymentMethod, StoredPaymentMethod -``` -```javascript -// Parent: StoredCardPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: StoredCardPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: StoredCardPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: StoredCardPaymentMethod -public let identifier: Swift.String { get } -``` -```javascript -// Parent: StoredCardPaymentMethod -public var brands: [Adyen.CardType] { get } -``` -```javascript -// Parent: StoredCardPaymentMethod -public var fundingSource: Adyen.CardFundingSource? { get set } -``` -```javascript -// Parent: StoredCardPaymentMethod -public func defaultDisplayInformation(using: Adyen.LocalizationParameters?) -> Adyen.DisplayInformation -``` -```javascript -// Parent: StoredCardPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: StoredCardPaymentMethod -public let supportedShopperInteractions: [Adyen.ShopperInteraction] { get } -``` -```javascript -// Parent: StoredCardPaymentMethod -public let brand: Adyen.CardType { get } -``` -```javascript -// Parent: StoredCardPaymentMethod -public let lastFour: Swift.String { get } -``` -```javascript -// Parent: StoredCardPaymentMethod -public let expiryMonth: Swift.String { get } -``` -```javascript -// Parent: StoredCardPaymentMethod -public let expiryYear: Swift.String { get } -``` -```javascript -// Parent: StoredCardPaymentMethod -public let holderName: Swift.String? { get } -``` -```javascript -// Parent: StoredCardPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: StoredCardPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.StoredCardPaymentMethod -``` -```javascript -// Parent: Root -public struct CashAppPayPaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: CashAppPayPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: CashAppPayPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: CashAppPayPaymentMethod -public let clientId: Swift.String { get } -``` -```javascript -// Parent: CashAppPayPaymentMethod -public let scopeId: Swift.String { get } -``` -```javascript -// Parent: CashAppPayPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: CashAppPayPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.CashAppPayPaymentMethod -``` -```javascript -// Parent: CashAppPayPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: CashAppPayPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: Root -public struct DokuPaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: DokuPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: DokuPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: DokuPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: DokuPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: DokuPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: DokuPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.DokuPaymentMethod -``` -```javascript -// Parent: Root -public typealias DokuWalletPaymentMethod = Adyen.DokuPaymentMethod -``` -```javascript -// Parent: Root -public typealias AlfamartPaymentMethod = Adyen.DokuPaymentMethod -``` -```javascript -// Parent: Root -public typealias IndomaretPaymentMethod = Adyen.DokuPaymentMethod -``` -```javascript -// Parent: Root -public struct EContextPaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: EContextPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: EContextPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: EContextPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: EContextPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: EContextPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: EContextPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.EContextPaymentMethod -``` -```javascript -// Parent: Root -public typealias SevenElevenPaymentMethod = Adyen.EContextPaymentMethod -``` -```javascript -// Parent: Root -public struct GiftCardPaymentMethod : Decodable, Encodable, PartialPaymentMethod, PaymentMethod -``` -```javascript -// Parent: GiftCardPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: GiftCardPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: GiftCardPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: GiftCardPaymentMethod -public let brand: Swift.String { get } -``` -```javascript -// Parent: GiftCardPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: GiftCardPaymentMethod -public func defaultDisplayInformation(using: Adyen.LocalizationParameters?) -> Adyen.DisplayInformation -``` -```javascript -// Parent: GiftCardPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: GiftCardPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.GiftCardPaymentMethod -``` -```javascript -// Parent: Root -public struct InstantPaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: InstantPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: InstantPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: InstantPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: InstantPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: InstantPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: InstantPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.InstantPaymentMethod -``` -```javascript -// Parent: Root -public struct IssuerListPaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: IssuerListPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: IssuerListPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: IssuerListPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: IssuerListPaymentMethod -public let issuers: [Adyen.Issuer] { get } -``` -```javascript -// Parent: IssuerListPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.IssuerListPaymentMethod -``` -```javascript -// Parent: IssuerListPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: IssuerListPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: Root -public struct MBWayPaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: MBWayPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: MBWayPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: MBWayPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: MBWayPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: MBWayPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: MBWayPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.MBWayPaymentMethod -``` -```javascript -// Parent: Root -public struct MealVoucherPaymentMethod : Decodable, Encodable, PartialPaymentMethod, PaymentMethod -``` -```javascript -// Parent: MealVoucherPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: MealVoucherPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: MealVoucherPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: MealVoucherPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: MealVoucherPaymentMethod -public func defaultDisplayInformation(using: Adyen.LocalizationParameters?) -> Adyen.DisplayInformation -``` -```javascript -// Parent: MealVoucherPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: MealVoucherPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.MealVoucherPaymentMethod -``` -```javascript -// Parent: Root -public struct Issuer : CustomStringConvertible, Decodable, Encodable, Equatable -``` -```javascript -// Parent: Issuer -public let identifier: Swift.String { get } -``` -```javascript -// Parent: Issuer -public let name: Swift.String { get } -``` -```javascript -// Parent: Issuer -public var description: Swift.String { get } -``` -```javascript -// Parent: Issuer -public static func __derived_struct_equals(_: Adyen.Issuer, _: Adyen.Issuer) -> Swift.Bool -``` -```javascript -// Parent: Issuer -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: Issuer -public init(from: any Swift.Decoder) throws -> Adyen.Issuer -``` -```javascript -// Parent: Root -public struct OnlineBankingPaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: OnlineBankingPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: OnlineBankingPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: OnlineBankingPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: OnlineBankingPaymentMethod -public let issuers: [Adyen.Issuer] { get } -``` -```javascript -// Parent: OnlineBankingPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: OnlineBankingPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: OnlineBankingPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.OnlineBankingPaymentMethod -``` -```javascript -// Parent: Root -public struct QiwiWalletPaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: QiwiWalletPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: QiwiWalletPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: QiwiWalletPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: QiwiWalletPaymentMethod -public let phoneExtensions: [Adyen.PhoneExtension] { get } -``` -```javascript -// Parent: QiwiWalletPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.QiwiWalletPaymentMethod -``` -```javascript -// Parent: QiwiWalletPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: QiwiWalletPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: Root -public struct PhoneExtension : Decodable, Encodable, Equatable, FormPickable -``` -```javascript -// Parent: PhoneExtension -public let value: Swift.String { get } -``` -```javascript -// Parent: PhoneExtension -public let countryCode: Swift.String { get } -``` -```javascript -// Parent: PhoneExtension -public var countryDisplayName: Swift.String { get } -``` -```javascript -// Parent: PhoneExtension -public init(value: Swift.String, countryCode: Swift.String) -> Adyen.PhoneExtension -``` -```javascript -// Parent: PhoneExtension -public static func __derived_struct_equals(_: Adyen.PhoneExtension, _: Adyen.PhoneExtension) -> Swift.Bool -``` -```javascript -// Parent: PhoneExtension -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: PhoneExtension -public init(from: any Swift.Decoder) throws -> Adyen.PhoneExtension -``` -```javascript -// Parent: PhoneExtension -@_spi(AdyenInternal) public var identifier: Swift.String { get } -``` -```javascript -// Parent: PhoneExtension -@_spi(AdyenInternal) public var icon: UIKit.UIImage? { get } -``` -```javascript -// Parent: PhoneExtension -@_spi(AdyenInternal) public var title: Swift.String { get } -``` -```javascript -// Parent: PhoneExtension -@_spi(AdyenInternal) public var subtitle: Swift.String? { get } -``` -```javascript -// Parent: PhoneExtension -@_spi(AdyenInternal) public var trailingText: Swift.String? { get } -``` -```javascript -// Parent: Root -public struct SEPADirectDebitPaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: SEPADirectDebitPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: SEPADirectDebitPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: SEPADirectDebitPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: SEPADirectDebitPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: SEPADirectDebitPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: SEPADirectDebitPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.SEPADirectDebitPaymentMethod -``` -```javascript -// Parent: Root -public struct StoredBCMCPaymentMethod : Decodable, Encodable, PaymentMethod, StoredPaymentMethod -``` -```javascript -// Parent: StoredBCMCPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: StoredBCMCPaymentMethod -public var name: Swift.String { get } -``` -```javascript -// Parent: StoredBCMCPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: StoredBCMCPaymentMethod -public var identifier: Swift.String { get } -``` -```javascript -// Parent: StoredBCMCPaymentMethod -public func defaultDisplayInformation(using: Adyen.LocalizationParameters?) -> Adyen.DisplayInformation -``` -```javascript -// Parent: StoredBCMCPaymentMethod -public var supportedShopperInteractions: [Adyen.ShopperInteraction] { get } -``` -```javascript -// Parent: StoredBCMCPaymentMethod -public let brand: Swift.String { get } -``` -```javascript -// Parent: StoredBCMCPaymentMethod -public var lastFour: Swift.String { get } -``` -```javascript -// Parent: StoredBCMCPaymentMethod -public var expiryMonth: Swift.String { get } -``` -```javascript -// Parent: StoredBCMCPaymentMethod -public var expiryYear: Swift.String { get } -``` -```javascript -// Parent: StoredBCMCPaymentMethod -public var holderName: Swift.String? { get } -``` -```javascript -// Parent: StoredBCMCPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: StoredBCMCPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.StoredBCMCPaymentMethod -``` -```javascript -// Parent: StoredBCMCPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: Root -public struct StoredBLIKPaymentMethod : Decodable, Encodable, PaymentMethod, StoredPaymentMethod -``` -```javascript -// Parent: StoredBLIKPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: StoredBLIKPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: StoredBLIKPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: StoredBLIKPaymentMethod -public let identifier: Swift.String { get } -``` -```javascript -// Parent: StoredBLIKPaymentMethod -public let supportedShopperInteractions: [Adyen.ShopperInteraction] { get } -``` -```javascript -// Parent: StoredBLIKPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: StoredBLIKPaymentMethod -@_spi(AdyenInternal) public func defaultDisplayInformation(using: Adyen.LocalizationParameters?) -> Adyen.DisplayInformation -``` -```javascript -// Parent: StoredBLIKPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: StoredBLIKPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.StoredBLIKPaymentMethod -``` -```javascript -// Parent: Root -public struct StoredCashAppPayPaymentMethod : Decodable, Encodable, PaymentMethod, StoredPaymentMethod -``` -```javascript -// Parent: StoredCashAppPayPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: StoredCashAppPayPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: StoredCashAppPayPaymentMethod -public let cashtag: Swift.String { get } -``` -```javascript -// Parent: StoredCashAppPayPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: StoredCashAppPayPaymentMethod -public let identifier: Swift.String { get } -``` -```javascript -// Parent: StoredCashAppPayPaymentMethod -public let supportedShopperInteractions: [Adyen.ShopperInteraction] { get } -``` -```javascript -// Parent: StoredCashAppPayPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: StoredCashAppPayPaymentMethod -@_spi(AdyenInternal) public func defaultDisplayInformation(using: Adyen.LocalizationParameters?) -> Adyen.DisplayInformation -``` -```javascript -// Parent: StoredCashAppPayPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: StoredCashAppPayPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.StoredCashAppPayPaymentMethod -``` -```javascript -// Parent: Root -public struct StoredInstantPaymentMethod : Decodable, Encodable, PaymentMethod, StoredPaymentMethod -``` -```javascript -// Parent: StoredInstantPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: StoredInstantPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: StoredInstantPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: StoredInstantPaymentMethod -public let identifier: Swift.String { get } -``` -```javascript -// Parent: StoredInstantPaymentMethod -public let supportedShopperInteractions: [Adyen.ShopperInteraction] { get } -``` -```javascript -// Parent: StoredInstantPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: StoredInstantPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: StoredInstantPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.StoredInstantPaymentMethod -``` -```javascript -// Parent: Root -public struct StoredPayPalPaymentMethod : Decodable, Encodable, PaymentMethod, StoredPaymentMethod -``` -```javascript -// Parent: StoredPayPalPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: StoredPayPalPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: StoredPayPalPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: StoredPayPalPaymentMethod -public let identifier: Swift.String { get } -``` -```javascript -// Parent: StoredPayPalPaymentMethod -public let supportedShopperInteractions: [Adyen.ShopperInteraction] { get } -``` -```javascript -// Parent: StoredPayPalPaymentMethod -public func defaultDisplayInformation(using: Adyen.LocalizationParameters?) -> Adyen.DisplayInformation -``` -```javascript -// Parent: StoredPayPalPaymentMethod -public let emailAddress: Swift.String { get } -``` -```javascript -// Parent: StoredPayPalPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: StoredPayPalPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: StoredPayPalPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.StoredPayPalPaymentMethod -``` -```javascript -// Parent: Root -public struct TwintPaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: TwintPaymentMethod -public var type: Adyen.PaymentMethodType { get set } -``` -```javascript -// Parent: TwintPaymentMethod -public var name: Swift.String { get set } -``` -```javascript -// Parent: TwintPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: TwintPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: TwintPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: TwintPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.TwintPaymentMethod -``` -```javascript -// Parent: Root -public struct UPIPaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: UPIPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: UPIPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: UPIPaymentMethod -public let apps: [Adyen.Issuer]? { get } -``` -```javascript -// Parent: UPIPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: UPIPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: UPIPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: UPIPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.UPIPaymentMethod -``` -```javascript -// Parent: Root -public struct WeChatPayPaymentMethod : Decodable, Encodable, PaymentMethod -``` -```javascript -// Parent: WeChatPayPaymentMethod -public let type: Adyen.PaymentMethodType { get } -``` -```javascript -// Parent: WeChatPayPaymentMethod -public let name: Swift.String { get } -``` -```javascript -// Parent: WeChatPayPaymentMethod -public var merchantProvidedDisplayInformation: Adyen.MerchantCustomDisplayInformation? { get set } -``` -```javascript -// Parent: WeChatPayPaymentMethod -@_spi(AdyenInternal) public func buildComponent(using: any Adyen.PaymentComponentBuilder) -> (any Adyen.PaymentComponent)? -``` -```javascript -// Parent: WeChatPayPaymentMethod -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: WeChatPayPaymentMethod -public init(from: any Swift.Decoder) throws -> Adyen.WeChatPayPaymentMethod -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) @objc public final class CancellingToolBar : AdyenCompatible, AnyNavigationBar, CALayerDelegate, CVarArg, CustomDebugStringConvertible, CustomStringConvertible, Equatable, Hashable, NSCoding, NSObjectProtocol, Sendable, UIAccessibilityIdentification, UIActivityItemsConfigurationProviding, UIAppearance, UIAppearanceContainer, UICoordinateSpace, UIDynamicItem, UIFocusEnvironment, UIFocusItem, UIFocusItemContainer, UILargeContentViewerItem, UIPasteConfigurationSupporting, UIPopoverPresentationControllerSourceItem, UIResponderStandardEditActions, UITraitChangeObservable, UITraitEnvironment, UIUserActivityRestoring -``` -```javascript -// Parent: CancellingToolBar -@_spi(AdyenInternal) override public init(title: Swift.String?, style: Adyen.NavigationStyle) -> Adyen.CancellingToolBar -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) @objc public class ModalToolbar : AdyenCompatible, AnyNavigationBar, CALayerDelegate, CVarArg, CustomDebugStringConvertible, CustomStringConvertible, Equatable, Hashable, NSCoding, NSObjectProtocol, Sendable, UIAccessibilityIdentification, UIActivityItemsConfigurationProviding, UIAppearance, UIAppearanceContainer, UICoordinateSpace, UIDynamicItem, UIFocusEnvironment, UIFocusItem, UIFocusItemContainer, UILargeContentViewerItem, UIPasteConfigurationSupporting, UIPopoverPresentationControllerSourceItem, UIResponderStandardEditActions, UITraitChangeObservable, UITraitEnvironment, UIUserActivityRestoring -``` -```javascript -// Parent: ModalToolbar -@_spi(AdyenInternal) public var onCancelHandler: (() -> Swift.Void)? { get set } -``` -```javascript -// Parent: ModalToolbar -@_spi(AdyenInternal) public init(title: Swift.String?, style: Adyen.NavigationStyle) -> Adyen.ModalToolbar -``` -```javascript -// Parent: ModalToolbar -@_spi(AdyenInternal) @objc override public dynamic init(frame: CoreFoundation.CGRect) -> Adyen.ModalToolbar -``` -```javascript -// Parent: Root -public final class AmountFormatter -``` -```javascript -// Parent: AmountFormatter -public static func formatted(amount: Swift.Int, currencyCode: Swift.String, localeIdentifier: Swift.String? = $DEFAULT_ARG) -> Swift.String? -``` -```javascript -// Parent: AmountFormatter -public static func minorUnitAmount(from: Swift.Double, currencyCode: Swift.String, localeIdentifier: Swift.String? = $DEFAULT_ARG) -> Swift.Int -``` -```javascript -// Parent: AmountFormatter -public static func minorUnitAmount(from: Foundation.Decimal, currencyCode: Swift.String, localeIdentifier: Swift.String? = $DEFAULT_ARG) -> Swift.Int -``` -```javascript -// Parent: AmountFormatter -public static func decimalAmount(_: Swift.Int, currencyCode: Swift.String, localeIdentifier: Swift.String? = $DEFAULT_ARG) -> Foundation.NSDecimalNumber -``` -```javascript -// Parent: Root -public final class BrazilSocialSecurityNumberFormatter : Formatter, Sanitizer -``` -```javascript -// Parent: BrazilSocialSecurityNumberFormatter -override public func formattedValue(for: Swift.String) -> Swift.String -``` -```javascript -// Parent: BrazilSocialSecurityNumberFormatter -override public init() -> Adyen.BrazilSocialSecurityNumberFormatter -``` -```javascript -// Parent: Root -public protocol Formatter : Sanitizer -``` -```javascript -// Parent: Formatter -public func formattedValue(for: Swift.String) -> Swift.String -``` -```javascript -// Parent: Root -public protocol Sanitizer -``` -```javascript -// Parent: Sanitizer -public func sanitizedValue(for: Swift.String) -> Swift.String -``` -```javascript -// Parent: Root -public final class IBANFormatter : Formatter, Sanitizer -``` -```javascript -// Parent: IBANFormatter -public init() -> Adyen.IBANFormatter -``` -```javascript -// Parent: IBANFormatter -public func formattedValue(for: Swift.String) -> Swift.String -``` -```javascript -// Parent: IBANFormatter -public func sanitizedValue(for: Swift.String) -> Swift.String -``` -```javascript -// Parent: Root -open class NumericFormatter : Formatter, Sanitizer -``` -```javascript -// Parent: NumericFormatter -public init() -> Adyen.NumericFormatter -``` -```javascript -// Parent: NumericFormatter -open func formattedValue(for: Swift.String) -> Swift.String -``` -```javascript -// Parent: NumericFormatter -open func sanitizedValue(for: Swift.String) -> Swift.String -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol AdyenCancellable -``` -```javascript -// Parent: AdyenCancellable -@_spi(AdyenInternal) public func cancel() -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public class AdyenTask : AdyenCancellable -``` -```javascript -// Parent: AdyenTask -@_spi(AdyenInternal) public var isCancelled: Swift.Bool { get } -``` -```javascript -// Parent: AdyenTask -@_spi(AdyenInternal) public func cancel() -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct AdyenDependencyValues -``` -```javascript -// Parent: AdyenDependencyValues -@_spi(AdyenInternal) public subscript(_: K.Type) -> K.Value { get set } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct AdyenDependency -``` -```javascript -// Parent: AdyenDependency -@_spi(AdyenInternal) public var wrappedValue: T { get } -``` -```javascript -// Parent: AdyenDependency -@_spi(AdyenInternal) public init(_: Swift.KeyPath) -> Adyen.AdyenDependency -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol AdyenDependencyKey -``` -```javascript -// Parent: AdyenDependencyKey -@_spi(AdyenInternal) public associatedtype Value -``` -```javascript -// Parent: AdyenDependencyKey -@_spi(AdyenInternal) public static var liveValue: Self.Value { get } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct AdyenScope -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public let base: Base { get } -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public init(base: Base) -> Adyen.AdyenScope -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public subscript(safeIndex: Swift.Int) -> T? { get } -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public func isSchemeConfigured(_: Swift.String) -> Swift.Bool -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public func with(priority: UIKit.UILayoutPriority) -> UIKit.NSLayoutConstraint -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public var caAlignmentMode: QuartzCore.CATextLayerAlignmentMode { get } -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public var isNullOrEmpty: Swift.Bool { get } -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public var nilIfEmpty: Swift.String? { get } -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public var nilIfEmpty: Swift.String? { get } -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public func truncate(to: Swift.Int) -> Swift.String -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public func components(withLengths: [Swift.Int]) -> [Swift.String] -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public func components(withLength: Swift.Int) -> [Swift.String] -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public subscript(_: Swift.Int) -> Swift.String { get } -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public subscript(_: Swift.Range) -> Swift.String { get } -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public subscript(_: Swift.ClosedRange) -> Swift.String { get } -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public var linkRanges: [Foundation.NSRange] { get } -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public func timeLeftString() -> Swift.String? -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public var mainKeyWindow: UIKit.UIWindow? { get } -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public func font(with: UIKit.UIFont.Weight) -> UIKit.UIFont -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public func cancelAnimations(with: Swift.String) -> Swift.Void -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public func animate(context: Adyen.AnimationContext) -> Swift.Void -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) @discardableResult public func anchor(inside: UIKit.UIView, with: UIKit.UIEdgeInsets = $DEFAULT_ARG) -> [UIKit.NSLayoutConstraint] -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) @discardableResult public func anchor(inside: UIKit.UILayoutGuide, with: UIKit.UIEdgeInsets = $DEFAULT_ARG) -> [UIKit.NSLayoutConstraint] -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) @discardableResult public func anchor(inside: Adyen.AdyenScope.LayoutAnchorSource, edgeInsets: Adyen.AdyenScope.EdgeInsets = $DEFAULT_ARG) -> [UIKit.NSLayoutConstraint] -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public func wrapped(with: UIKit.UIEdgeInsets = $DEFAULT_ARG) -> UIKit.UIView -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public enum LayoutAnchorSource -``` -```javascript -// Parent: AdyenScope.LayoutAnchorSource -@_spi(AdyenInternal) case view(UIKit.UIView) -``` -```javascript -// Parent: AdyenScope.LayoutAnchorSource -@_spi(AdyenInternal) case layoutGuide(UIKit.UILayoutGuide) -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public struct EdgeInsets -``` -```javascript -// Parent: AdyenScope.EdgeInsets -@_spi(AdyenInternal) public var top: CoreGraphics.CGFloat? { get set } -``` -```javascript -// Parent: AdyenScope.EdgeInsets -@_spi(AdyenInternal) public var left: CoreGraphics.CGFloat? { get set } -``` -```javascript -// Parent: AdyenScope.EdgeInsets -@_spi(AdyenInternal) public var bottom: CoreGraphics.CGFloat? { get set } -``` -```javascript -// Parent: AdyenScope.EdgeInsets -@_spi(AdyenInternal) public var right: CoreGraphics.CGFloat? { get set } -``` -```javascript -// Parent: AdyenScope.EdgeInsets -@_spi(AdyenInternal) public static var zero: Adyen.AdyenScope.EdgeInsets { get } -``` -```javascript -// Parent: AdyenScope.EdgeInsets -@_spi(AdyenInternal) public init(top: CoreGraphics.CGFloat? = $DEFAULT_ARG, left: CoreGraphics.CGFloat? = $DEFAULT_ARG, bottom: CoreGraphics.CGFloat? = $DEFAULT_ARG, right: CoreGraphics.CGFloat? = $DEFAULT_ARG) -> Adyen.AdyenScope.EdgeInsets -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public var topPresenter: UIKit.UIViewController { get } -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) @discardableResult public func snapShot(forceRedraw: Swift.Bool = $DEFAULT_ARG) -> UIKit.UIImage? -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public func hide(animationKey: Swift.String, hidden: Swift.Bool, animated: Swift.Bool) -> Swift.Void -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public var minimalSize: CoreFoundation.CGSize { get } -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public func round(corners: UIKit.UIRectCorner, radius: CoreGraphics.CGFloat) -> Swift.Void -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public func round(corners: UIKit.UIRectCorner, percentage: CoreGraphics.CGFloat) -> Swift.Void -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public func round(corners: UIKit.UIRectCorner, rounding: Adyen.CornerRounding) -> Swift.Void -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public func round(using: Adyen.CornerRounding) -> Swift.Void -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public var queryParameters: [Swift.String : Swift.String] { get } -``` -```javascript -// Parent: AdyenScope -@_spi(AdyenInternal) public var isHttp: Swift.Bool { get } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol AdyenCompatible -``` -```javascript -// Parent: AdyenCompatible -@_spi(AdyenInternal) public associatedtype AdyenBase -``` -```javascript -// Parent: AdyenCompatible -@_spi(AdyenInternal) public var adyen: Adyen.AdyenScope { get } -``` -```javascript -// Parent: AdyenCompatible -@_spi(AdyenInternal) public var adyen: Adyen.AdyenScope { get } -``` -```javascript -// Parent: Root -public let adyenSdkVersion: Swift.String -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol ImageLoading -``` -```javascript -// Parent: ImageLoading -@_spi(AdyenInternal) @discardableResult public func load(url: Foundation.URL, completion: ((UIKit.UIImage?) -> Swift.Void)) -> any Adyen.AdyenCancellable -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class ImageLoader : ImageLoading -``` -```javascript -// Parent: ImageLoader -@_spi(AdyenInternal) public init(urlSession: Foundation.URLSession = $DEFAULT_ARG) -> Adyen.ImageLoader -``` -```javascript -// Parent: ImageLoader -@_spi(AdyenInternal) @discardableResult public func load(url: Foundation.URL, completion: ((UIKit.UIImage?) -> Swift.Void)) -> any Adyen.AdyenCancellable -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class ImageLoaderProvider -``` -```javascript -// Parent: ImageLoaderProvider -@_spi(AdyenInternal) public static func imageLoader() -> any Adyen.ImageLoading -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) @objc public class AnimationContext : CVarArg, CustomDebugStringConvertible, CustomStringConvertible, Equatable, Hashable, NSObjectProtocol -``` -```javascript -// Parent: AnimationContext -@_spi(AdyenInternal) public init(animationKey: Swift.String, duration: Foundation.TimeInterval, delay: Foundation.TimeInterval = $DEFAULT_ARG, options: UIKit.UIView.AnimationOptions = $DEFAULT_ARG, animations: () -> Swift.Void, completion: ((Swift.Bool) -> Swift.Void)? = $DEFAULT_ARG) -> Adyen.AnimationContext -``` -```javascript -// Parent: AnimationContext -@_spi(AdyenInternal) @objc override public dynamic init() -> Adyen.AnimationContext -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) @objc public final class KeyFrameAnimationContext : CVarArg, CustomDebugStringConvertible, CustomStringConvertible, Equatable, Hashable, NSObjectProtocol -``` -```javascript -// Parent: KeyFrameAnimationContext -@_spi(AdyenInternal) public init(animationKey: Swift.String, duration: Foundation.TimeInterval, delay: Foundation.TimeInterval = $DEFAULT_ARG, options: UIKit.UIView.KeyframeAnimationOptions = $DEFAULT_ARG, animations: () -> Swift.Void, completion: ((Swift.Bool) -> Swift.Void)? = $DEFAULT_ARG) -> Adyen.KeyFrameAnimationContext -``` -```javascript -// Parent: KeyFrameAnimationContext -@_spi(AdyenInternal) override public init(animationKey: Swift.String, duration: Foundation.TimeInterval, delay: Foundation.TimeInterval = $DEFAULT_ARG, options: UIKit.UIView.AnimationOptions = $DEFAULT_ARG, animations: () -> Swift.Void, completion: ((Swift.Bool) -> Swift.Void)? = $DEFAULT_ARG) -> Adyen.KeyFrameAnimationContext -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) @objc public final class SpringAnimationContext : CVarArg, CustomDebugStringConvertible, CustomStringConvertible, Equatable, Hashable, NSObjectProtocol -``` -```javascript -// Parent: SpringAnimationContext -@_spi(AdyenInternal) public init(animationKey: Swift.String, duration: Foundation.TimeInterval, delay: Foundation.TimeInterval = $DEFAULT_ARG, dampingRatio: CoreGraphics.CGFloat, velocity: CoreGraphics.CGFloat, options: UIKit.UIView.AnimationOptions = $DEFAULT_ARG, animations: () -> Swift.Void, completion: ((Swift.Bool) -> Swift.Void)? = $DEFAULT_ARG) -> Adyen.SpringAnimationContext -``` -```javascript -// Parent: SpringAnimationContext -@_spi(AdyenInternal) override public init(animationKey: Swift.String, duration: Foundation.TimeInterval, delay: Foundation.TimeInterval = $DEFAULT_ARG, options: UIKit.UIView.AnimationOptions = $DEFAULT_ARG, animations: () -> Swift.Void, completion: ((Swift.Bool) -> Swift.Void)? = $DEFAULT_ARG) -> Adyen.SpringAnimationContext -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol PreferredContentSizeConsumer -``` -```javascript -// Parent: PreferredContentSizeConsumer -@_spi(AdyenInternal) public func didUpdatePreferredContentSize() -> Swift.Void -``` -```javascript -// Parent: PreferredContentSizeConsumer -@_spi(AdyenInternal) public func willUpdatePreferredContentSize() -> Swift.Void -``` -```javascript -// Parent: Root -public struct Amount : Comparable, Decodable, Encodable, Equatable -``` -```javascript -// Parent: Amount -public let value: Swift.Int { get } -``` -```javascript -// Parent: Amount -public let currencyCode: Swift.String { get } -``` -```javascript -// Parent: Amount -public var localeIdentifier: Swift.String? { get set } -``` -```javascript -// Parent: Amount -public init(value: Swift.Int, currencyCode: Swift.String, localeIdentifier: Swift.String? = $DEFAULT_ARG) -> Adyen.Amount -``` -```javascript -// Parent: Amount -public init(value: Foundation.Decimal, currencyCode: Swift.String, localeIdentifier: Swift.String? = $DEFAULT_ARG) -> Adyen.Amount -``` -```javascript -// Parent: Amount -public static func __derived_struct_equals(_: Adyen.Amount, _: Adyen.Amount) -> Swift.Bool -``` -```javascript -// Parent: Amount -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: Amount -public init(from: any Swift.Decoder) throws -> Adyen.Amount -``` -```javascript -// Parent: Amount -public var formatted: Swift.String { get } -``` -```javascript -// Parent: Amount -@_spi(AdyenInternal) public var formattedComponents: Adyen.AmountComponents { get } -``` -```javascript -// Parent: Amount -@_spi(AdyenInternal) public static func <(_: Adyen.Amount, _: Adyen.Amount) -> Swift.Bool -``` -```javascript -// Parent: Amount -@_spi(AdyenInternal) public static func <=(_: Adyen.Amount, _: Adyen.Amount) -> Swift.Bool -``` -```javascript -// Parent: Amount -@_spi(AdyenInternal) public static func >=(_: Adyen.Amount, _: Adyen.Amount) -> Swift.Bool -``` -```javascript -// Parent: Amount -@_spi(AdyenInternal) public static func >(_: Adyen.Amount, _: Adyen.Amount) -> Swift.Bool -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct AmountComponents -``` -```javascript -// Parent: AmountComponents -@_spi(AdyenInternal) public let formattedValue: Swift.String { get } -``` -```javascript -// Parent: AmountComponents -@_spi(AdyenInternal) public let formattedCurrencySymbol: Swift.String { get } -``` -```javascript -// Parent: Root -public protocol OpaqueEncodable : Encodable -``` -```javascript -// Parent: OpaqueEncodable -public var encodable: Adyen.AnyEncodable { get } -``` -```javascript -// Parent: OpaqueEncodable -public var encodable: Adyen.AnyEncodable { get } -``` -```javascript -// Parent: Root -public struct AnyEncodable : Encodable -``` -```javascript -// Parent: AnyEncodable -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: Root -public struct Balance -``` -```javascript -// Parent: Balance -public let availableAmount: Adyen.Amount { get } -``` -```javascript -// Parent: Balance -public let transactionLimit: Adyen.Amount? { get } -``` -```javascript -// Parent: Balance -public init(availableAmount: Adyen.Amount, transactionLimit: Adyen.Amount?) -> Adyen.Balance -``` -```javascript -// Parent: Root -public struct BrowserInfo : Encodable -``` -```javascript -// Parent: BrowserInfo -public var userAgent: Swift.String? { get set } -``` -```javascript -// Parent: BrowserInfo -public static func initialize(completion: ((Adyen.BrowserInfo?) -> Swift.Void)) -> Swift.Void -``` -```javascript -// Parent: BrowserInfo -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol DelegatedAuthenticationAware -``` -```javascript -// Parent: DelegatedAuthenticationAware -@_spi(AdyenInternal) public var delegatedAuthenticationData: Adyen.DelegatedAuthenticationData? { get } -``` -```javascript -// Parent: Root -public enum DelegatedAuthenticationData : Decodable, Encodable -``` -```javascript -// Parent: DelegatedAuthenticationData -public enum DecodingError : Equatable, Error, Hashable, LocalizedError, Sendable -``` -```javascript -// Parent: DelegatedAuthenticationData.DecodingError -case invalidDelegatedAuthenticationData -``` -```javascript -// Parent: DelegatedAuthenticationData.DecodingError -public var errorDescription: Swift.String? { get } -``` -```javascript -// Parent: DelegatedAuthenticationData.DecodingError -public static func __derived_enum_equals(_: Adyen.DelegatedAuthenticationData.DecodingError, _: Adyen.DelegatedAuthenticationData.DecodingError) -> Swift.Bool -``` -```javascript -// Parent: DelegatedAuthenticationData.DecodingError -public func hash(into: inout Swift.Hasher) -> Swift.Void -``` -```javascript -// Parent: DelegatedAuthenticationData.DecodingError -public var hashValue: Swift.Int { get } -``` -```javascript -// Parent: DelegatedAuthenticationData -case sdkOutput(Swift.String) -``` -```javascript -// Parent: DelegatedAuthenticationData -case sdkInput(Swift.String) -``` -```javascript -// Parent: DelegatedAuthenticationData -public init(from: any Swift.Decoder) throws -> Adyen.DelegatedAuthenticationData -``` -```javascript -// Parent: DelegatedAuthenticationData -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: Root -public struct Installments : Encodable, Equatable -``` -```javascript -// Parent: Installments -public enum Plan : Equatable, Hashable, RawRepresentable -``` -```javascript -// Parent: Installments.Plan -case regular -``` -```javascript -// Parent: Installments.Plan -case revolving -``` -```javascript -// Parent: Installments.Plan -@inlinable public init(rawValue: Swift.String) -> Adyen.Installments.Plan? -``` -```javascript -// Parent: Installments.Plan -public typealias RawValue = Swift.String -``` -```javascript -// Parent: Installments.Plan -public var rawValue: Swift.String { get } -``` -```javascript -// Parent: Installments -public let totalMonths: Swift.Int { get } -``` -```javascript -// Parent: Installments -public let plan: Adyen.Installments.Plan { get } -``` -```javascript -// Parent: Installments -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: Installments -public init(totalMonths: Swift.Int, plan: Adyen.Installments.Plan) -> Adyen.Installments -``` -```javascript -// Parent: Installments -public static func __derived_struct_equals(_: Adyen.Installments, _: Adyen.Installments) -> Swift.Bool -``` -```javascript -// Parent: Root -public struct PartialPaymentOrder : Decodable, Encodable, Equatable -``` -```javascript -// Parent: PartialPaymentOrder -public struct CompactOrder : Encodable, Equatable -``` -```javascript -// Parent: PartialPaymentOrder.CompactOrder -public let pspReference: Swift.String { get } -``` -```javascript -// Parent: PartialPaymentOrder.CompactOrder -public let orderData: Swift.String? { get } -``` -```javascript -// Parent: PartialPaymentOrder.CompactOrder -public static func __derived_struct_equals(_: Adyen.PartialPaymentOrder.CompactOrder, _: Adyen.PartialPaymentOrder.CompactOrder) -> Swift.Bool -``` -```javascript -// Parent: PartialPaymentOrder.CompactOrder -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: PartialPaymentOrder -public let compactOrder: Adyen.PartialPaymentOrder.CompactOrder { get } -``` -```javascript -// Parent: PartialPaymentOrder -public let pspReference: Swift.String { get } -``` -```javascript -// Parent: PartialPaymentOrder -public let orderData: Swift.String? { get } -``` -```javascript -// Parent: PartialPaymentOrder -public let reference: Swift.String? { get } -``` -```javascript -// Parent: PartialPaymentOrder -public let amount: Adyen.Amount? { get } -``` -```javascript -// Parent: PartialPaymentOrder -public let remainingAmount: Adyen.Amount? { get } -``` -```javascript -// Parent: PartialPaymentOrder -public let expiresAt: Foundation.Date? { get } -``` -```javascript -// Parent: PartialPaymentOrder -public init(pspReference: Swift.String, orderData: Swift.String?, reference: Swift.String? = $DEFAULT_ARG, amount: Adyen.Amount? = $DEFAULT_ARG, remainingAmount: Adyen.Amount? = $DEFAULT_ARG, expiresAt: Foundation.Date? = $DEFAULT_ARG) -> Adyen.PartialPaymentOrder -``` -```javascript -// Parent: PartialPaymentOrder -public init(from: any Swift.Decoder) throws -> Adyen.PartialPaymentOrder -``` -```javascript -// Parent: PartialPaymentOrder -public static func __derived_struct_equals(_: Adyen.PartialPaymentOrder, _: Adyen.PartialPaymentOrder) -> Swift.Bool -``` -```javascript -// Parent: PartialPaymentOrder -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: Root -public struct Payment : Decodable, Encodable -``` -```javascript -// Parent: Payment -public let amount: Adyen.Amount { get } -``` -```javascript -// Parent: Payment -public let countryCode: Swift.String { get } -``` -```javascript -// Parent: Payment -public init(amount: Adyen.Amount, countryCode: Swift.String) -> Adyen.Payment -``` -```javascript -// Parent: Payment -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: Payment -public init(from: any Swift.Decoder) throws -> Adyen.Payment -``` -```javascript -// Parent: Root -public struct PaymentComponentData -``` -```javascript -// Parent: PaymentComponentData -public let amount: Adyen.Amount? { get } -``` -```javascript -// Parent: PaymentComponentData -public let paymentMethod: any Adyen.PaymentMethodDetails { get } -``` -```javascript -// Parent: PaymentComponentData -public let storePaymentMethod: Swift.Bool? { get } -``` -```javascript -// Parent: PaymentComponentData -public let order: Adyen.PartialPaymentOrder? { get } -``` -```javascript -// Parent: PaymentComponentData -public var amountToPay: Adyen.Amount? { get } -``` -```javascript -// Parent: PaymentComponentData -public let installments: Adyen.Installments? { get } -``` -```javascript -// Parent: PaymentComponentData -public let supportNativeRedirect: Swift.Bool { get } -``` -```javascript -// Parent: PaymentComponentData -public var shopperName: Adyen.ShopperName? { get } -``` -```javascript -// Parent: PaymentComponentData -public var emailAddress: Swift.String? { get } -``` -```javascript -// Parent: PaymentComponentData -public var telephoneNumber: Swift.String? { get } -``` -```javascript -// Parent: PaymentComponentData -public let browserInfo: Adyen.BrowserInfo? { get } -``` -```javascript -// Parent: PaymentComponentData -public var checkoutAttemptId: Swift.String? { get } -``` -```javascript -// Parent: PaymentComponentData -public var billingAddress: Adyen.PostalAddress? { get } -``` -```javascript -// Parent: PaymentComponentData -public var deliveryAddress: Adyen.PostalAddress? { get } -``` -```javascript -// Parent: PaymentComponentData -public var socialSecurityNumber: Swift.String? { get } -``` -```javascript -// Parent: PaymentComponentData -public var delegatedAuthenticationData: Adyen.DelegatedAuthenticationData? { get } -``` -```javascript -// Parent: PaymentComponentData -@_spi(AdyenInternal) public init(paymentMethodDetails: some Adyen.PaymentMethodDetails, amount: Adyen.Amount?, order: Adyen.PartialPaymentOrder?, storePaymentMethod: Swift.Bool? = $DEFAULT_ARG, browserInfo: Adyen.BrowserInfo? = $DEFAULT_ARG, installments: Adyen.Installments? = $DEFAULT_ARG) -> Adyen.PaymentComponentData -``` -```javascript -// Parent: PaymentComponentData -@_spi(AdyenInternal) public func replacing(order: Adyen.PartialPaymentOrder) -> Adyen.PaymentComponentData -``` -```javascript -// Parent: PaymentComponentData -@_spi(AdyenInternal) public func replacing(amount: Adyen.Amount) -> Adyen.PaymentComponentData -``` -```javascript -// Parent: PaymentComponentData -@_spi(AdyenInternal) public func replacing(checkoutAttemptId: Swift.String?) -> Adyen.PaymentComponentData -``` -```javascript -// Parent: PaymentComponentData -@_spi(AdyenInternal) public func dataByAddingBrowserInfo(completion: ((Adyen.PaymentComponentData) -> Swift.Void)) -> Swift.Void -``` -```javascript -// Parent: Root -public struct PostalAddress : Encodable, Equatable -``` -```javascript -// Parent: PostalAddress -public init(city: Swift.String? = $DEFAULT_ARG, country: Swift.String? = $DEFAULT_ARG, houseNumberOrName: Swift.String? = $DEFAULT_ARG, postalCode: Swift.String? = $DEFAULT_ARG, stateOrProvince: Swift.String? = $DEFAULT_ARG, street: Swift.String? = $DEFAULT_ARG, apartment: Swift.String? = $DEFAULT_ARG) -> Adyen.PostalAddress -``` -```javascript -// Parent: PostalAddress -public var city: Swift.String? { get set } -``` -```javascript -// Parent: PostalAddress -public var country: Swift.String? { get set } -``` -```javascript -// Parent: PostalAddress -public var houseNumberOrName: Swift.String? { get set } -``` -```javascript -// Parent: PostalAddress -public var postalCode: Swift.String? { get set } -``` -```javascript -// Parent: PostalAddress -public var stateOrProvince: Swift.String? { get set } -``` -```javascript -// Parent: PostalAddress -public var street: Swift.String? { get set } -``` -```javascript -// Parent: PostalAddress -public var apartment: Swift.String? { get set } -``` -```javascript -// Parent: PostalAddress -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: PostalAddress -public static func ==(_: Adyen.PostalAddress, _: Adyen.PostalAddress) -> Swift.Bool -``` -```javascript -// Parent: PostalAddress -public var isEmpty: Swift.Bool { get } -``` -```javascript -// Parent: PostalAddress -@_spi(AdyenInternal) public func formatted(using: Adyen.LocalizationParameters?) -> Swift.String -``` -```javascript -// Parent: PostalAddress -@_spi(AdyenInternal) public var formattedStreet: Swift.String { get } -``` -```javascript -// Parent: PostalAddress -@_spi(AdyenInternal) public func formattedLocation(using: Adyen.LocalizationParameters?) -> Swift.String -``` -```javascript -// Parent: PostalAddress -@_spi(AdyenInternal) public func satisfies(requiredFields: Swift.Set) -> Swift.Bool -``` -```javascript -// Parent: Root -public struct PhoneNumber -``` -```javascript -// Parent: PhoneNumber -public let value: Swift.String { get } -``` -```javascript -// Parent: PhoneNumber -public let callingCode: Swift.String? { get } -``` -```javascript -// Parent: PhoneNumber -public init(value: Swift.String, callingCode: Swift.String?) -> Adyen.PhoneNumber -``` -```javascript -// Parent: Root -public struct PrefilledShopperInformation : ShopperInformation -``` -```javascript -// Parent: PrefilledShopperInformation -public var shopperName: Adyen.ShopperName? { get set } -``` -```javascript -// Parent: PrefilledShopperInformation -public var emailAddress: Swift.String? { get set } -``` -```javascript -// Parent: PrefilledShopperInformation -public var telephoneNumber: Swift.String? { get set } -``` -```javascript -// Parent: PrefilledShopperInformation -public var phoneNumber: Adyen.PhoneNumber? { get set } -``` -```javascript -// Parent: PrefilledShopperInformation -public var billingAddress: Adyen.PostalAddress? { get set } -``` -```javascript -// Parent: PrefilledShopperInformation -public var deliveryAddress: Adyen.PostalAddress? { get set } -``` -```javascript -// Parent: PrefilledShopperInformation -public var socialSecurityNumber: Swift.String? { get set } -``` -```javascript -// Parent: PrefilledShopperInformation -public var card: Adyen.PrefilledShopperInformation.CardInformation? { get set } -``` -```javascript -// Parent: PrefilledShopperInformation -public init(shopperName: Adyen.ShopperName? = $DEFAULT_ARG, emailAddress: Swift.String? = $DEFAULT_ARG, telephoneNumber: Swift.String? = $DEFAULT_ARG, billingAddress: Adyen.PostalAddress? = $DEFAULT_ARG, deliveryAddress: Adyen.PostalAddress? = $DEFAULT_ARG, socialSecurityNumber: Swift.String? = $DEFAULT_ARG, card: Adyen.PrefilledShopperInformation.CardInformation? = $DEFAULT_ARG) -> Adyen.PrefilledShopperInformation -``` -```javascript -// Parent: PrefilledShopperInformation -public init(shopperName: Adyen.ShopperName? = $DEFAULT_ARG, emailAddress: Swift.String? = $DEFAULT_ARG, phoneNumber: Adyen.PhoneNumber? = $DEFAULT_ARG, billingAddress: Adyen.PostalAddress? = $DEFAULT_ARG, deliveryAddress: Adyen.PostalAddress? = $DEFAULT_ARG, socialSecurityNumber: Swift.String? = $DEFAULT_ARG, card: Adyen.PrefilledShopperInformation.CardInformation? = $DEFAULT_ARG) -> Adyen.PrefilledShopperInformation -``` -```javascript -// Parent: PrefilledShopperInformation -public struct CardInformation -``` -```javascript -// Parent: PrefilledShopperInformation.CardInformation -public let holderName: Swift.String { get } -``` -```javascript -// Parent: PrefilledShopperInformation.CardInformation -public init(holderName: Swift.String) -> Adyen.PrefilledShopperInformation.CardInformation -``` -```javascript -// Parent: Root -public protocol ShopperInformation -``` -```javascript -// Parent: ShopperInformation -public var shopperName: Adyen.ShopperName? { get } -``` -```javascript -// Parent: ShopperInformation -public var emailAddress: Swift.String? { get } -``` -```javascript -// Parent: ShopperInformation -public var telephoneNumber: Swift.String? { get } -``` -```javascript -// Parent: ShopperInformation -public var billingAddress: Adyen.PostalAddress? { get } -``` -```javascript -// Parent: ShopperInformation -public var deliveryAddress: Adyen.PostalAddress? { get } -``` -```javascript -// Parent: ShopperInformation -public var socialSecurityNumber: Swift.String? { get } -``` -```javascript -// Parent: ShopperInformation -@_spi(AdyenInternal) public var shopperName: Adyen.ShopperName? { get } -``` -```javascript -// Parent: ShopperInformation -@_spi(AdyenInternal) public var emailAddress: Swift.String? { get } -``` -```javascript -// Parent: ShopperInformation -@_spi(AdyenInternal) public var telephoneNumber: Swift.String? { get } -``` -```javascript -// Parent: ShopperInformation -@_spi(AdyenInternal) public var billingAddress: Adyen.PostalAddress? { get } -``` -```javascript -// Parent: ShopperInformation -@_spi(AdyenInternal) public var deliveryAddress: Adyen.PostalAddress? { get } -``` -```javascript -// Parent: ShopperInformation -@_spi(AdyenInternal) public var socialSecurityNumber: Swift.String? { get } -``` -```javascript -// Parent: Root -public struct ShopperName : Decodable, Encodable, Equatable -``` -```javascript -// Parent: ShopperName -public let firstName: Swift.String { get } -``` -```javascript -// Parent: ShopperName -public let lastName: Swift.String { get } -``` -```javascript -// Parent: ShopperName -public init(firstName: Swift.String, lastName: Swift.String) -> Adyen.ShopperName -``` -```javascript -// Parent: ShopperName -public static func __derived_struct_equals(_: Adyen.ShopperName, _: Adyen.ShopperName) -> Swift.Bool -``` -```javascript -// Parent: ShopperName -public func encode(to: any Swift.Encoder) throws -> Swift.Void -``` -```javascript -// Parent: ShopperName -public init(from: any Swift.Decoder) throws -> Adyen.ShopperName -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public enum Dimensions -``` -```javascript -// Parent: Dimensions -@_spi(AdyenInternal) public static var leastPresentableScale: CoreGraphics.CGFloat { get set } -``` -```javascript -// Parent: Dimensions -@_spi(AdyenInternal) public static var greatestPresentableHeightScale: CoreGraphics.CGFloat { get set } -``` -```javascript -// Parent: Dimensions -@_spi(AdyenInternal) public static var maxAdaptiveWidth: CoreGraphics.CGFloat { get set } -``` -```javascript -// Parent: Dimensions -@_spi(AdyenInternal) public static var greatestPresentableScale: CoreGraphics.CGFloat { get } -``` -```javascript -// Parent: Dimensions -@_spi(AdyenInternal) public static func expectedWidth(for: UIKit.UIWindow? = $DEFAULT_ARG) -> CoreGraphics.CGFloat -``` -```javascript -// Parent: Dimensions -@_spi(AdyenInternal) public static func keyWindowSize(for: UIKit.UIWindow? = $DEFAULT_ARG) -> CoreFoundation.CGRect -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct FormItemViewBuilder -``` -```javascript -// Parent: FormItemViewBuilder -@_spi(AdyenInternal) public func build(with: Adyen.FormToggleItem) -> Adyen.FormItemView -``` -```javascript -// Parent: FormItemViewBuilder -@_spi(AdyenInternal) public func build(with: Adyen.FormSplitItem) -> Adyen.FormItemView -``` -```javascript -// Parent: FormItemViewBuilder -@_spi(AdyenInternal) public func build(with: Adyen.FormPhoneNumberItem) -> Adyen.FormItemView -``` -```javascript -// Parent: FormItemViewBuilder -@_spi(AdyenInternal) public func build(with: Adyen.FormIssuersPickerItem) -> Adyen.BaseFormPickerItemView -``` -```javascript -// Parent: FormItemViewBuilder -@_spi(AdyenInternal) public func build(with: Adyen.FormTextInputItem) -> Adyen.FormItemView -``` -```javascript -// Parent: FormItemViewBuilder -@_spi(AdyenInternal) public func build(with: Adyen.ListItem) -> Adyen.ListItemView -``` -```javascript -// Parent: FormItemViewBuilder -@_spi(AdyenInternal) public func build(with: Adyen.SelectableFormItem) -> Adyen.FormItemView -``` -```javascript -// Parent: FormItemViewBuilder -@_spi(AdyenInternal) public func build(with: Adyen.FormButtonItem) -> Adyen.FormItemView -``` -```javascript -// Parent: FormItemViewBuilder -@_spi(AdyenInternal) public func build(with: Adyen.FormImageItem) -> Adyen.FormItemView -``` -```javascript -// Parent: FormItemViewBuilder -@_spi(AdyenInternal) public func build(with: Adyen.FormSeparatorItem) -> Adyen.FormItemView -``` -```javascript -// Parent: FormItemViewBuilder -@_spi(AdyenInternal) public func build(with: Adyen.FormErrorItem) -> Adyen.FormItemView -``` -```javascript -// Parent: FormItemViewBuilder -@_spi(AdyenInternal) public func build(with: Adyen.FormAddressItem) -> Adyen.FormItemView -``` -```javascript -// Parent: FormItemViewBuilder -@_spi(AdyenInternal) public func build(with: Adyen.FormSpacerItem) -> Adyen.FormItemView -``` -```javascript -// Parent: FormItemViewBuilder -@_spi(AdyenInternal) public func build(with: Adyen.FormPostalCodeItem) -> Adyen.FormItemView -``` -```javascript -// Parent: FormItemViewBuilder -@_spi(AdyenInternal) public func build(with: Adyen.FormSearchButtonItem) -> Adyen.FormItemView -``` -```javascript -// Parent: FormItemViewBuilder -@_spi(AdyenInternal) public func build(with: Adyen.FormAddressPickerItem) -> Adyen.FormItemView -``` -```javascript -// Parent: FormItemViewBuilder -@_spi(AdyenInternal) public func build(with: Adyen.FormPickerItem) -> Adyen.FormItemView> -``` -```javascript -// Parent: FormItemViewBuilder -@_spi(AdyenInternal) public func build(with: Adyen.FormPhoneExtensionPickerItem) -> Adyen.FormPhoneExtensionPickerItemView -``` -```javascript -// Parent: FormItemViewBuilder -@_spi(AdyenInternal) public static func build(_: any Adyen.FormItem) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol FormViewProtocol -``` -```javascript -// Parent: FormViewProtocol -@_spi(AdyenInternal) public func add(item: T?) -> Swift.Void -``` -```javascript -// Parent: FormViewProtocol -@_spi(AdyenInternal) public func displayValidation() -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) @objc open class FormViewController : AdyenCompatible, AdyenObserver, CVarArg, CustomDebugStringConvertible, CustomStringConvertible, Equatable, FormTextItemViewDelegate, FormViewProtocol, Hashable, NSCoding, NSExtensionRequestHandling, NSObjectProtocol, PreferredContentSizeConsumer, Sendable, UIActivityItemsConfigurationProviding, UIAppearanceContainer, UIContentContainer, UIFocusEnvironment, UIPasteConfigurationSupporting, UIResponderStandardEditActions, UIStateRestoring, UITraitChangeObservable, UITraitEnvironment, UIUserActivityRestoring, ViewControllerPresenter -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) public var requiresKeyboardInput: Swift.Bool { get } -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) public let style: any Adyen.ViewStyle { get } -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) public weak var delegate: (any Adyen.ViewControllerDelegate)? { get set } -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) public init(style: any Adyen.ViewStyle, localizationParameters: Adyen.LocalizationParameters?) -> Adyen.FormViewController -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) @objc override open dynamic func viewDidLoad() -> Swift.Void -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) @objc override open dynamic func viewWillAppear(_: Swift.Bool) -> Swift.Void -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) @objc override open dynamic func viewDidAppear(_: Swift.Bool) -> Swift.Void -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) @objc override open dynamic func viewWillDisappear(_: Swift.Bool) -> Swift.Void -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) @objc override open dynamic func viewDidDisappear(_: Swift.Bool) -> Swift.Void -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) @objc override public dynamic var preferredContentSize: CoreFoundation.CGSize { get set } -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) public func willUpdatePreferredContentSize() -> Swift.Void -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) public func didUpdatePreferredContentSize() -> Swift.Void -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) public func append(_: some Adyen.FormItem) -> Swift.Void -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) public let localizationParameters: Adyen.LocalizationParameters? { get } -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) public func validate() -> Swift.Bool -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) public func showValidation() -> Swift.Void -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) public func resetForm() -> Swift.Void -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) @discardableResult @objc override public dynamic func resignFirstResponder() -> Swift.Bool -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) @objc override public dynamic init(nibName: Swift.String?, bundle: Foundation.Bundle?) -> Adyen.FormViewController -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) public func add(item: (some Adyen.FormItem)?) -> Swift.Void -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) public func displayValidation() -> Swift.Void -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) public func didReachMaximumLength(in: Adyen.FormTextItemView) -> Swift.Void -``` -```javascript -// Parent: FormViewController -@_spi(AdyenInternal) public func didSelectReturnKey(in: Adyen.FormTextItemView) -> Swift.Void -``` -```javascript -// Parent: Root -public struct AddressStyle : FormValueItemStyle, TintableStyle, ViewStyle -``` -```javascript -// Parent: AddressStyle -public var title: Adyen.TextStyle { get set } -``` -```javascript -// Parent: AddressStyle -public var textField: Adyen.FormTextItemStyle { get set } -``` -```javascript -// Parent: AddressStyle -public var tintColor: UIKit.UIColor? { get set } -``` -```javascript -// Parent: AddressStyle -public var backgroundColor: UIKit.UIColor { get set } -``` -```javascript -// Parent: AddressStyle -public var separatorColor: UIKit.UIColor? { get } -``` -```javascript -// Parent: AddressStyle -public init(title: Adyen.TextStyle, textField: Adyen.FormTextItemStyle, tintColor: UIKit.UIColor? = $DEFAULT_ARG, backgroundColor: UIKit.UIColor = $DEFAULT_ARG) -> Adyen.AddressStyle -``` -```javascript -// Parent: AddressStyle -public init() -> Adyen.AddressStyle -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public enum AddressField : CaseIterable, Equatable, Hashable, RawRepresentable -``` -```javascript -// Parent: AddressField -@_spi(AdyenInternal) case street -``` -```javascript -// Parent: AddressField -@_spi(AdyenInternal) case houseNumberOrName -``` -```javascript -// Parent: AddressField -@_spi(AdyenInternal) case apartment -``` -```javascript -// Parent: AddressField -@_spi(AdyenInternal) case postalCode -``` -```javascript -// Parent: AddressField -@_spi(AdyenInternal) case city -``` -```javascript -// Parent: AddressField -@_spi(AdyenInternal) case stateOrProvince -``` -```javascript -// Parent: AddressField -@_spi(AdyenInternal) case country -``` -```javascript -// Parent: AddressField -@_spi(AdyenInternal) @inlinable public init(rawValue: Swift.String) -> Adyen.AddressField? -``` -```javascript -// Parent: AddressField -@_spi(AdyenInternal) public typealias AllCases = [Adyen.AddressField] -``` -```javascript -// Parent: AddressField -@_spi(AdyenInternal) public typealias RawValue = Swift.String -``` -```javascript -// Parent: AddressField -@_spi(AdyenInternal) public static var allCases: [Adyen.AddressField] { get } -``` -```javascript -// Parent: AddressField -@_spi(AdyenInternal) public var rawValue: Swift.String { get } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public enum AddressFormScheme -``` -```javascript -// Parent: AddressFormScheme -@_spi(AdyenInternal) public var children: [Adyen.AddressField] { get } -``` -```javascript -// Parent: AddressFormScheme -@_spi(AdyenInternal) case item(Adyen.AddressField) -``` -```javascript -// Parent: AddressFormScheme -@_spi(AdyenInternal) case split(Adyen.AddressField, Adyen.AddressField) -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct AddressViewModel -``` -```javascript -// Parent: AddressViewModel -@_spi(AdyenInternal) public var optionalFields: [Adyen.AddressField] { get set } -``` -```javascript -// Parent: AddressViewModel -@_spi(AdyenInternal) public var scheme: [Adyen.AddressFormScheme] { get set } -``` -```javascript -// Parent: AddressViewModel -@_spi(AdyenInternal) public init(labels: [Adyen.AddressField : Adyen.LocalizationKey], placeholder: [Adyen.AddressField : Adyen.LocalizationKey], optionalFields: [Adyen.AddressField], scheme: [Adyen.AddressFormScheme]) -> Adyen.AddressViewModel -``` -```javascript -// Parent: AddressViewModel -@_spi(AdyenInternal) public var requiredFields: Swift.Set { get } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct AddressViewModelBuilderContext -``` -```javascript -// Parent: AddressViewModelBuilderContext -@_spi(AdyenInternal) public var countryCode: Swift.String { get set } -``` -```javascript -// Parent: AddressViewModelBuilderContext -@_spi(AdyenInternal) public var isOptional: Swift.Bool { get set } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol AddressViewModelBuilder -``` -```javascript -// Parent: AddressViewModelBuilder -@_spi(AdyenInternal) public func build(context: Adyen.AddressViewModelBuilderContext) -> Adyen.AddressViewModel -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct DefaultAddressViewModelBuilder : AddressViewModelBuilder -``` -```javascript -// Parent: DefaultAddressViewModelBuilder -@_spi(AdyenInternal) public init() -> Adyen.DefaultAddressViewModelBuilder -``` -```javascript -// Parent: DefaultAddressViewModelBuilder -@_spi(AdyenInternal) public func build(context: Adyen.AddressViewModelBuilderContext) -> Adyen.AddressViewModel -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class FormAddressItem : AdyenObserver, FormItem, Hidable -``` -```javascript -// Parent: FormAddressItem -@_spi(AdyenInternal) public var isHidden: Adyen.AdyenObservable { get set } -``` -```javascript -// Parent: FormAddressItem -@_spi(AdyenInternal) override public var value: Adyen.PostalAddress { get set } -``` -```javascript -// Parent: FormAddressItem -@_spi(AdyenInternal) override public var subitems: [any Adyen.FormItem] { get } -``` -```javascript -// Parent: FormAddressItem -@_spi(AdyenInternal) public var addressViewModel: Adyen.AddressViewModel { get } -``` -```javascript -// Parent: FormAddressItem -@_spi(AdyenInternal) override public var title: Swift.String? { get set } -``` -```javascript -// Parent: FormAddressItem -@_spi(AdyenInternal) public init(initialCountry: Swift.String, configuration: Adyen.FormAddressItem.Configuration, identifier: Swift.String? = $DEFAULT_ARG, presenter: (any Adyen.ViewControllerPresenter)?, addressViewModelBuilder: any Adyen.AddressViewModelBuilder) -> Adyen.FormAddressItem -``` -```javascript -// Parent: FormAddressItem -@_spi(AdyenInternal) public func updateOptionalStatus(isOptional: Swift.Bool) -> Swift.Void -``` -```javascript -// Parent: FormAddressItem -@_spi(AdyenInternal) override public func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: FormAddressItem -@_spi(AdyenInternal) public func reset() -> Swift.Void -``` -```javascript -// Parent: FormAddressItem -@_spi(AdyenInternal) public struct Configuration -``` -```javascript -// Parent: FormAddressItem.Configuration -@_spi(AdyenInternal) public init(style: Adyen.AddressStyle = $DEFAULT_ARG, localizationParameters: Adyen.LocalizationParameters? = $DEFAULT_ARG, supportedCountryCodes: [Swift.String]? = $DEFAULT_ARG, showsHeader: Swift.Bool = $DEFAULT_ARG) -> Adyen.FormAddressItem.Configuration -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class FormPostalCodeItem : FormItem, InputViewRequiringFormItem, ValidatableFormItem -``` -```javascript -// Parent: FormPostalCodeItem -@_spi(AdyenInternal) public init(style: Adyen.FormTextItemStyle = $DEFAULT_ARG, localizationParameters: Adyen.LocalizationParameters? = $DEFAULT_ARG) -> Adyen.FormPostalCodeItem -``` -```javascript -// Parent: FormPostalCodeItem -@_spi(AdyenInternal) public func updateOptionalStatus(isOptional: Swift.Bool) -> Swift.Void -``` -```javascript -// Parent: FormPostalCodeItem -@_spi(AdyenInternal) override public func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: FormPostalCodeItem -@_spi(AdyenInternal) override public init(style: Adyen.FormTextItemStyle) -> Adyen.FormPostalCodeItem -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class FormRegionPickerItem : FormItem, ValidatableFormItem -``` -```javascript -// Parent: FormRegionPickerItem -@_spi(AdyenInternal) public required init(preselectedRegion: Adyen.Region?, selectableRegions: [Adyen.Region], validationFailureMessage: Swift.String?, title: Swift.String, placeholder: Swift.String, style: Adyen.FormTextItemStyle, presenter: (any Adyen.ViewControllerPresenter)?, localizationParameters: Adyen.LocalizationParameters? = $DEFAULT_ARG, identifier: Swift.String? = $DEFAULT_ARG) -> Adyen.FormRegionPickerItem -``` -```javascript -// Parent: FormRegionPickerItem -@_spi(AdyenInternal) public func updateValue(with: Adyen.Region?) -> Swift.Void -``` -```javascript -// Parent: FormRegionPickerItem -@_spi(AdyenInternal) override public func resetValue() -> Swift.Void -``` -```javascript -// Parent: FormRegionPickerItem -@_spi(AdyenInternal) override public func updateValidationFailureMessage() -> Swift.Void -``` -```javascript -// Parent: FormRegionPickerItem -@_spi(AdyenInternal) override public func updateFormattedValue() -> Swift.Void -``` -```javascript -// Parent: FormRegionPickerItem -@_spi(AdyenInternal) override public init(preselectedValue: Adyen.FormPickerElement?, selectableValues: [Adyen.FormPickerElement], title: Swift.String, placeholder: Swift.String, style: Adyen.FormTextItemStyle, presenter: (any Adyen.ViewControllerPresenter)?, localizationParameters: Adyen.LocalizationParameters? = $DEFAULT_ARG, identifier: Swift.String? = $DEFAULT_ARG) -> Adyen.FormRegionPickerItem -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class FormAddressPickerItem : FormItem, Hidable, ValidatableFormItem -``` -```javascript -// Parent: FormAddressPickerItem -@_spi(AdyenInternal) public var isHidden: Adyen.AdyenObservable { get set } -``` -```javascript -// Parent: FormAddressPickerItem -@_spi(AdyenInternal) public enum AddressType : Equatable, Hashable -``` -```javascript -// Parent: FormAddressPickerItem.AddressType -@_spi(AdyenInternal) case billing -``` -```javascript -// Parent: FormAddressPickerItem.AddressType -@_spi(AdyenInternal) case delivery -``` -```javascript -// Parent: FormAddressPickerItem.AddressType -@_spi(AdyenInternal) public static func __derived_enum_equals(_: Adyen.FormAddressPickerItem.AddressType, _: Adyen.FormAddressPickerItem.AddressType) -> Swift.Bool -``` -```javascript -// Parent: FormAddressPickerItem.AddressType -@_spi(AdyenInternal) public func hash(into: inout Swift.Hasher) -> Swift.Void -``` -```javascript -// Parent: FormAddressPickerItem.AddressType -@_spi(AdyenInternal) public var hashValue: Swift.Int { get } -``` -```javascript -// Parent: FormAddressPickerItem.AddressType -@_spi(AdyenInternal) public func placeholder(with: Adyen.LocalizationParameters?) -> Swift.String -``` -```javascript -// Parent: FormAddressPickerItem.AddressType -@_spi(AdyenInternal) public func title(with: Adyen.LocalizationParameters?) -> Swift.String -``` -```javascript -// Parent: FormAddressPickerItem -@_spi(AdyenInternal) public var addressViewModel: Adyen.AddressViewModel { get } -``` -```javascript -// Parent: FormAddressPickerItem -@_spi(AdyenInternal) override public var value: Adyen.PostalAddress? { get set } -``` -```javascript -// Parent: FormAddressPickerItem -@_spi(AdyenInternal) public init(for: Adyen.FormAddressPickerItem.AddressType, initialCountry: Swift.String, supportedCountryCodes: [Swift.String]?, prefillAddress: Adyen.PostalAddress?, style: Adyen.FormComponentStyle, localizationParameters: Adyen.LocalizationParameters? = $DEFAULT_ARG, identifier: Swift.String? = $DEFAULT_ARG, addressViewModelBuilder: any Adyen.AddressViewModelBuilder = $DEFAULT_ARG, presenter: any Adyen.ViewControllerPresenter, lookupProvider: (any Adyen.AddressLookupProvider)? = $DEFAULT_ARG) -> Adyen.FormAddressPickerItem -``` -```javascript -// Parent: FormAddressPickerItem -@_spi(AdyenInternal) public func updateOptionalStatus(isOptional: Swift.Bool) -> Swift.Void -``` -```javascript -// Parent: FormAddressPickerItem -@_spi(AdyenInternal) override public func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: FormAddressPickerItem -@_spi(AdyenInternal) override public func isValid() -> Swift.Bool -``` -```javascript -// Parent: FormAddressPickerItem -@_spi(AdyenInternal) override public func validationStatus() -> Adyen.ValidationStatus? -``` -```javascript -// Parent: FormAddressPickerItem -@_spi(AdyenInternal) override public init(value: Adyen.PostalAddress?, style: Adyen.FormTextItemStyle, placeholder: Swift.String) -> Adyen.FormAddressPickerItem -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public class FormAttributedLabelItem : FormItem -``` -```javascript -// Parent: FormAttributedLabelItem -@_spi(AdyenInternal) public var subitems: [any Adyen.FormItem] { get set } -``` -```javascript -// Parent: FormAttributedLabelItem -@_spi(AdyenInternal) public init(originalText: Swift.String, links: [Swift.String], style: Adyen.TextStyle, linkTextStyle: Adyen.TextStyle, identifier: Swift.String? = $DEFAULT_ARG) -> Adyen.FormAttributedLabelItem -``` -```javascript -// Parent: FormAttributedLabelItem -@_spi(AdyenInternal) public var identifier: Swift.String? { get set } -``` -```javascript -// Parent: FormAttributedLabelItem -@_spi(AdyenInternal) public func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public class FormContainerItem : FormItem, Hidable -``` -```javascript -// Parent: FormContainerItem -@_spi(AdyenInternal) public var isHidden: Adyen.AdyenObservable { get set } -``` -```javascript -// Parent: FormContainerItem -@_spi(AdyenInternal) public var subitems: [any Adyen.FormItem] { get set } -``` -```javascript -// Parent: FormContainerItem -@_spi(AdyenInternal) public init(content: any Adyen.FormItem, padding: UIKit.UIEdgeInsets = $DEFAULT_ARG, identifier: Swift.String? = $DEFAULT_ARG) -> Adyen.FormContainerItem -``` -```javascript -// Parent: FormContainerItem -@_spi(AdyenInternal) public var identifier: Swift.String? { get set } -``` -```javascript -// Parent: FormContainerItem -@_spi(AdyenInternal) public var content: any Adyen.FormItem { get } -``` -```javascript -// Parent: FormContainerItem -@_spi(AdyenInternal) public var padding: UIKit.UIEdgeInsets { get set } -``` -```javascript -// Parent: FormContainerItem -@_spi(AdyenInternal) public func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public class FormLabelItem : FormItem -``` -```javascript -// Parent: FormLabelItem -@_spi(AdyenInternal) public var subitems: [any Adyen.FormItem] { get set } -``` -```javascript -// Parent: FormLabelItem -@_spi(AdyenInternal) public init(text: Swift.String, style: Adyen.TextStyle, identifier: Swift.String? = $DEFAULT_ARG) -> Adyen.FormLabelItem -``` -```javascript -// Parent: FormLabelItem -@_spi(AdyenInternal) public var identifier: Swift.String? { get set } -``` -```javascript -// Parent: FormLabelItem -@_spi(AdyenInternal) public var style: Adyen.TextStyle { get set } -``` -```javascript -// Parent: FormLabelItem -@_spi(AdyenInternal) public var text: Swift.String { get set } -``` -```javascript -// Parent: FormLabelItem -@_spi(AdyenInternal) public func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) open class FormVerticalStackItemView : AdyenCompatible, AdyenObserver, AnyFormItemView, CALayerDelegate, CVarArg, CustomDebugStringConvertible, CustomStringConvertible, Equatable, Hashable, NSCoding, NSObjectProtocol, Sendable, UIAccessibilityIdentification, UIActivityItemsConfigurationProviding, UIAppearance, UIAppearanceContainer, UICoordinateSpace, UIDynamicItem, UIFocusEnvironment, UIFocusItem, UIFocusItemContainer, UILargeContentViewerItem, UIPasteConfigurationSupporting, UIPopoverPresentationControllerSourceItem, UIResponderStandardEditActions, UITraitChangeObservable, UITraitEnvironment, UIUserActivityRestoring -``` -```javascript -// Parent: FormVerticalStackItemView -@_spi(AdyenInternal) public var views: [any Adyen.AnyFormItemView] { get } -``` -```javascript -// Parent: FormVerticalStackItemView -@_spi(AdyenInternal) public required init(item: FormItemType) -> Adyen.FormVerticalStackItemView -``` -```javascript -// Parent: FormVerticalStackItemView -@_spi(AdyenInternal) public convenience init(item: FormItemType, itemSpacing: CoreGraphics.CGFloat) -> Adyen.FormVerticalStackItemView -``` -```javascript -// Parent: FormVerticalStackItemView -@_spi(AdyenInternal) override public var childItemViews: [any Adyen.AnyFormItemView] { get } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class FormButtonItem : FormItem -``` -```javascript -// Parent: FormButtonItem -@_spi(AdyenInternal) public var subitems: [any Adyen.FormItem] { get set } -``` -```javascript -// Parent: FormButtonItem -@_spi(AdyenInternal) public let style: Adyen.FormButtonItemStyle { get } -``` -```javascript -// Parent: FormButtonItem -@_spi(AdyenInternal) public var identifier: Swift.String? { get set } -``` -```javascript -// Parent: FormButtonItem -@_spi(AdyenInternal) public var title: Swift.String? { get set } -``` -```javascript -// Parent: FormButtonItem -@_spi(AdyenInternal) public var $title: Adyen.AdyenObservable { get } -``` -```javascript -// Parent: FormButtonItem -@_spi(AdyenInternal) public var showsActivityIndicator: Swift.Bool { get set } -``` -```javascript -// Parent: FormButtonItem -@_spi(AdyenInternal) public var $showsActivityIndicator: Adyen.AdyenObservable { get } -``` -```javascript -// Parent: FormButtonItem -@_spi(AdyenInternal) public var enabled: Swift.Bool { get set } -``` -```javascript -// Parent: FormButtonItem -@_spi(AdyenInternal) public var $enabled: Adyen.AdyenObservable { get } -``` -```javascript -// Parent: FormButtonItem -@_spi(AdyenInternal) public var buttonSelectionHandler: (() -> Swift.Void)? { get set } -``` -```javascript -// Parent: FormButtonItem -@_spi(AdyenInternal) public init(style: Adyen.FormButtonItemStyle) -> Adyen.FormButtonItem -``` -```javascript -// Parent: FormButtonItem -@_spi(AdyenInternal) public func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: Root -public struct FormButtonItemStyle : ViewStyle -``` -```javascript -// Parent: FormButtonItemStyle -public var button: Adyen.ButtonStyle { get set } -``` -```javascript -// Parent: FormButtonItemStyle -public var backgroundColor: UIKit.UIColor { get set } -``` -```javascript -// Parent: FormButtonItemStyle -public init(button: Adyen.ButtonStyle) -> Adyen.FormButtonItemStyle -``` -```javascript -// Parent: FormButtonItemStyle -public init(button: Adyen.ButtonStyle, background: UIKit.UIColor) -> Adyen.FormButtonItemStyle -``` -```javascript -// Parent: FormButtonItemStyle -public static func main(font: UIKit.UIFont, textColor: UIKit.UIColor, mainColor: UIKit.UIColor, cornerRadius: CoreGraphics.CGFloat) -> Adyen.FormButtonItemStyle -``` -```javascript -// Parent: FormButtonItemStyle -public static func main(font: UIKit.UIFont, textColor: UIKit.UIColor, mainColor: UIKit.UIColor) -> Adyen.FormButtonItemStyle -``` -```javascript -// Parent: FormButtonItemStyle -public static func main(font: UIKit.UIFont, textColor: UIKit.UIColor, mainColor: UIKit.UIColor, cornerRounding: Adyen.CornerRounding) -> Adyen.FormButtonItemStyle -``` -```javascript -// Parent: FormButtonItemStyle -public static func secondary(font: UIKit.UIFont, textColor: UIKit.UIColor) -> Adyen.FormButtonItemStyle -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class FormSearchButtonItem : FormItem -``` -```javascript -// Parent: FormSearchButtonItem -@_spi(AdyenInternal) public var subitems: [any Adyen.FormItem] { get set } -``` -```javascript -// Parent: FormSearchButtonItem -@_spi(AdyenInternal) public let style: any Adyen.ViewStyle { get } -``` -```javascript -// Parent: FormSearchButtonItem -@_spi(AdyenInternal) public var identifier: Swift.String? { get set } -``` -```javascript -// Parent: FormSearchButtonItem -@_spi(AdyenInternal) public var placeholder: Swift.String? { get set } -``` -```javascript -// Parent: FormSearchButtonItem -@_spi(AdyenInternal) public var $placeholder: Adyen.AdyenObservable { get } -``` -```javascript -// Parent: FormSearchButtonItem -@_spi(AdyenInternal) public let selectionHandler: () -> Swift.Void { get } -``` -```javascript -// Parent: FormSearchButtonItem -@_spi(AdyenInternal) public init(placeholder: Swift.String, style: any Adyen.ViewStyle, identifier: Swift.String, selectionHandler: () -> Swift.Void) -> Adyen.FormSearchButtonItem -``` -```javascript -// Parent: FormSearchButtonItem -@_spi(AdyenInternal) public func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class FormErrorItem : FormItem, Hidable -``` -```javascript -// Parent: FormErrorItem -@_spi(AdyenInternal) public var message: Swift.String? { get set } -``` -```javascript -// Parent: FormErrorItem -@_spi(AdyenInternal) public var $message: Adyen.AdyenObservable { get } -``` -```javascript -// Parent: FormErrorItem -@_spi(AdyenInternal) public let iconName: Swift.String { get } -``` -```javascript -// Parent: FormErrorItem -@_spi(AdyenInternal) public let style: Adyen.FormErrorItemStyle { get } -``` -```javascript -// Parent: FormErrorItem -@_spi(AdyenInternal) public var identifier: Swift.String? { get set } -``` -```javascript -// Parent: FormErrorItem -@_spi(AdyenInternal) public var isHidden: Adyen.AdyenObservable { get set } -``` -```javascript -// Parent: FormErrorItem -@_spi(AdyenInternal) public var subitems: [any Adyen.FormItem] { get set } -``` -```javascript -// Parent: FormErrorItem -@_spi(AdyenInternal) public init(message: Swift.String? = $DEFAULT_ARG, iconName: Swift.String = $DEFAULT_ARG, style: Adyen.FormErrorItemStyle = $DEFAULT_ARG) -> Adyen.FormErrorItem -``` -```javascript -// Parent: FormErrorItem -@_spi(AdyenInternal) public func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: Root -public struct FormErrorItemStyle : ViewStyle -``` -```javascript -// Parent: FormErrorItemStyle -public var message: Adyen.TextStyle { get set } -``` -```javascript -// Parent: FormErrorItemStyle -public var cornerRounding: Adyen.CornerRounding { get set } -``` -```javascript -// Parent: FormErrorItemStyle -public var backgroundColor: UIKit.UIColor { get set } -``` -```javascript -// Parent: FormErrorItemStyle -public init(message: Adyen.TextStyle) -> Adyen.FormErrorItemStyle -``` -```javascript -// Parent: FormErrorItemStyle -public init() -> Adyen.FormErrorItemStyle -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public class FormImageItem : FormItem, Hidable -``` -```javascript -// Parent: FormImageItem -@_spi(AdyenInternal) public var isHidden: Adyen.AdyenObservable { get set } -``` -```javascript -// Parent: FormImageItem -@_spi(AdyenInternal) public var subitems: [any Adyen.FormItem] { get set } -``` -```javascript -// Parent: FormImageItem -@_spi(AdyenInternal) public var name: Swift.String { get set } -``` -```javascript -// Parent: FormImageItem -@_spi(AdyenInternal) public var identifier: Swift.String? { get set } -``` -```javascript -// Parent: FormImageItem -@_spi(AdyenInternal) public var size: CoreFoundation.CGSize { get set } -``` -```javascript -// Parent: FormImageItem -@_spi(AdyenInternal) public var style: Adyen.ImageStyle? { get set } -``` -```javascript -// Parent: FormImageItem -@_spi(AdyenInternal) public init(name: Swift.String, size: CoreFoundation.CGSize? = $DEFAULT_ARG, style: Adyen.ImageStyle? = $DEFAULT_ARG, identifier: Swift.String? = $DEFAULT_ARG) -> Adyen.FormImageItem -``` -```javascript -// Parent: FormImageItem -@_spi(AdyenInternal) public func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol Hidable -``` -```javascript -// Parent: Hidable -@_spi(AdyenInternal) public var isHidden: Adyen.AdyenObservable { get } -``` -```javascript -// Parent: Hidable -@_spi(AdyenInternal) public var isVisible: Swift.Bool { get set } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol FormItem -``` -```javascript -// Parent: FormItem -@_spi(AdyenInternal) public var identifier: Swift.String? { get set } -``` -```javascript -// Parent: FormItem -@_spi(AdyenInternal) public var subitems: [any Adyen.FormItem] { get } -``` -```javascript -// Parent: FormItem -@_spi(AdyenInternal) public func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: FormItem -@_spi(AdyenInternal) public func addingDefaultMargins() -> Adyen.FormContainerItem -``` -```javascript -// Parent: FormItem -@_spi(AdyenInternal) public var flatSubitems: [any Adyen.FormItem] { get } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol ValidatableFormItem : FormItem -``` -```javascript -// Parent: ValidatableFormItem -@_spi(AdyenInternal) public var validationFailureMessage: Swift.String? { get set } -``` -```javascript -// Parent: ValidatableFormItem -@_spi(AdyenInternal) public func isValid() -> Swift.Bool -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol InputViewRequiringFormItem : FormItem -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) open class FormItemView : AdyenCompatible, AdyenObserver, AnyFormItemView, CALayerDelegate, CVarArg, CustomDebugStringConvertible, CustomStringConvertible, Equatable, Hashable, NSCoding, NSObjectProtocol, Sendable, UIAccessibilityIdentification, UIActivityItemsConfigurationProviding, UIAppearance, UIAppearanceContainer, UICoordinateSpace, UIDynamicItem, UIFocusEnvironment, UIFocusItem, UIFocusItemContainer, UILargeContentViewerItem, UIPasteConfigurationSupporting, UIPopoverPresentationControllerSourceItem, UIResponderStandardEditActions, UITraitChangeObservable, UITraitEnvironment, UIUserActivityRestoring -``` -```javascript -// Parent: FormItemView -@_spi(AdyenInternal) public let item: ItemType { get } -``` -```javascript -// Parent: FormItemView -@_spi(AdyenInternal) public required init(item: ItemType) -> Adyen.FormItemView -``` -```javascript -// Parent: FormItemView -@_spi(AdyenInternal) open var childItemViews: [any Adyen.AnyFormItemView] { get } -``` -```javascript -// Parent: FormItemView -@_spi(AdyenInternal) public func reset() -> Swift.Void -``` -```javascript -// Parent: FormItemView -@_spi(AdyenInternal) @objc override public dynamic init(frame: CoreFoundation.CGRect) -> Adyen.FormItemView -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol AnyFormItemView -``` -```javascript -// Parent: AnyFormItemView -@_spi(AdyenInternal) public var parentItemView: (any Adyen.AnyFormItemView)? { get } -``` -```javascript -// Parent: AnyFormItemView -@_spi(AdyenInternal) public var childItemViews: [any Adyen.AnyFormItemView] { get } -``` -```javascript -// Parent: AnyFormItemView -@_spi(AdyenInternal) public func reset() -> Swift.Void -``` -```javascript -// Parent: AnyFormItemView -@_spi(AdyenInternal) public var parentItemView: (any Adyen.AnyFormItemView)? { get } -``` -```javascript -// Parent: AnyFormItemView -@_spi(AdyenInternal) public var flatSubitemViews: [any Adyen.AnyFormItemView] { get } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class FormPhoneNumberItem : FormItem, InputViewRequiringFormItem, ValidatableFormItem -``` -```javascript -// Parent: FormPhoneNumberItem -@_spi(AdyenInternal) public var prefix: Swift.String { get } -``` -```javascript -// Parent: FormPhoneNumberItem -@_spi(AdyenInternal) public var phoneNumber: Swift.String { get } -``` -```javascript -// Parent: FormPhoneNumberItem -@_spi(AdyenInternal) public init(phoneNumber: Adyen.PhoneNumber?, selectableValues: [Adyen.PhoneExtension], style: Adyen.FormTextItemStyle, localizationParameters: Adyen.LocalizationParameters? = $DEFAULT_ARG, presenter: Adyen.WeakReferenceViewControllerPresenter) -> Adyen.FormPhoneNumberItem -``` -```javascript -// Parent: FormPhoneNumberItem -@_spi(AdyenInternal) override public func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: FormPhoneNumberItem -@_spi(AdyenInternal) override public init(style: Adyen.FormTextItemStyle) -> Adyen.FormPhoneNumberItem -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class FormPhoneExtensionPickerItem : FormItem, ValidatableFormItem -``` -```javascript -// Parent: FormPhoneExtensionPickerItem -@_spi(AdyenInternal) public required init(preselectedExtension: Adyen.PhoneExtension?, selectableExtensions: [Adyen.PhoneExtension], validationFailureMessage: Swift.String?, style: Adyen.FormTextItemStyle, presenter: Adyen.WeakReferenceViewControllerPresenter, localizationParameters: Adyen.LocalizationParameters? = $DEFAULT_ARG, identifier: Swift.String? = $DEFAULT_ARG) -> Adyen.FormPhoneExtensionPickerItem -``` -```javascript -// Parent: FormPhoneExtensionPickerItem -@_spi(AdyenInternal) override public func resetValue() -> Swift.Void -``` -```javascript -// Parent: FormPhoneExtensionPickerItem -@_spi(AdyenInternal) override public func updateValidationFailureMessage() -> Swift.Void -``` -```javascript -// Parent: FormPhoneExtensionPickerItem -@_spi(AdyenInternal) override public func updateFormattedValue() -> Swift.Void -``` -```javascript -// Parent: FormPhoneExtensionPickerItem -@_spi(AdyenInternal) override public func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: FormPhoneExtensionPickerItem -@_spi(AdyenInternal) override public init(preselectedValue: Adyen.PhoneExtension?, selectableValues: [Adyen.PhoneExtension], title: Swift.String, placeholder: Swift.String, style: Adyen.FormTextItemStyle, presenter: (any Adyen.ViewControllerPresenter)?, localizationParameters: Adyen.LocalizationParameters? = $DEFAULT_ARG, identifier: Swift.String? = $DEFAULT_ARG) -> Adyen.FormPhoneExtensionPickerItem -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class FormPhoneExtensionPickerItemView : AdyenCompatible, AdyenObserver, AnyFormItemView, CALayerDelegate, CVarArg, CustomDebugStringConvertible, CustomStringConvertible, Equatable, Hashable, NSCoding, NSObjectProtocol, Sendable, UIAccessibilityIdentification, UIActivityItemsConfigurationProviding, UIAppearance, UIAppearanceContainer, UICoordinateSpace, UIDynamicItem, UIFocusEnvironment, UIFocusItem, UIFocusItemContainer, UILargeContentViewerItem, UIPasteConfigurationSupporting, UIPopoverPresentationControllerSourceItem, UIResponderStandardEditActions, UITraitChangeObservable, UITraitEnvironment, UIUserActivityRestoring -``` -```javascript -// Parent: FormPhoneExtensionPickerItemView -@_spi(AdyenInternal) @objc override public var accessibilityIdentifier: Swift.String? { get set } -``` -```javascript -// Parent: FormPhoneExtensionPickerItemView -@_spi(AdyenInternal) public required init(item: Adyen.FormPhoneExtensionPickerItem) -> Adyen.FormPhoneExtensionPickerItemView -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class FormSegmentedControlItem : FormItem -``` -```javascript -// Parent: FormSegmentedControlItem -@_spi(AdyenInternal) public var subitems: [any Adyen.FormItem] { get set } -``` -```javascript -// Parent: FormSegmentedControlItem -@_spi(AdyenInternal) public var identifier: Swift.String? { get set } -``` -```javascript -// Parent: FormSegmentedControlItem -@_spi(AdyenInternal) public var style: Adyen.SegmentedControlStyle { get set } -``` -```javascript -// Parent: FormSegmentedControlItem -@_spi(AdyenInternal) public var selectionHandler: ((Swift.Int) -> Swift.Void)? { get set } -``` -```javascript -// Parent: FormSegmentedControlItem -@_spi(AdyenInternal) public init(items: [Swift.String], style: Adyen.SegmentedControlStyle, identifier: Swift.String? = $DEFAULT_ARG) -> Adyen.FormSegmentedControlItem -``` -```javascript -// Parent: FormSegmentedControlItem -@_spi(AdyenInternal) public func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public class SelectableFormItem : FormItem, Hidable -``` -```javascript -// Parent: SelectableFormItem -@_spi(AdyenInternal) public var subitems: [any Adyen.FormItem] { get set } -``` -```javascript -// Parent: SelectableFormItem -@_spi(AdyenInternal) public var title: Swift.String { get set } -``` -```javascript -// Parent: SelectableFormItem -@_spi(AdyenInternal) public var imageUrl: Foundation.URL? { get set } -``` -```javascript -// Parent: SelectableFormItem -@_spi(AdyenInternal) public var isSelected: Swift.Bool { get set } -``` -```javascript -// Parent: SelectableFormItem -@_spi(AdyenInternal) public var $isSelected: Adyen.AdyenObservable { get } -``` -```javascript -// Parent: SelectableFormItem -@_spi(AdyenInternal) public var selectionHandler: (() -> Swift.Void)? { get set } -``` -```javascript -// Parent: SelectableFormItem -@_spi(AdyenInternal) public var identifier: Swift.String? { get set } -``` -```javascript -// Parent: SelectableFormItem -@_spi(AdyenInternal) public let accessibilityLabel: Swift.String { get } -``` -```javascript -// Parent: SelectableFormItem -@_spi(AdyenInternal) public let style: Adyen.SelectableFormItemStyle { get } -``` -```javascript -// Parent: SelectableFormItem -@_spi(AdyenInternal) public var isHidden: Adyen.AdyenObservable { get set } -``` -```javascript -// Parent: SelectableFormItem -@_spi(AdyenInternal) public init(title: Swift.String, imageUrl: Foundation.URL? = $DEFAULT_ARG, isSelected: Swift.Bool = $DEFAULT_ARG, style: Adyen.SelectableFormItemStyle, identifier: Swift.String? = $DEFAULT_ARG, accessibilityLabel: Swift.String? = $DEFAULT_ARG, selectionHandler: (() -> Swift.Void)? = $DEFAULT_ARG) -> Adyen.SelectableFormItem -``` -```javascript -// Parent: SelectableFormItem -@_spi(AdyenInternal) public func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct SelectableFormItemStyle : Equatable, ViewStyle -``` -```javascript -// Parent: SelectableFormItemStyle -@_spi(AdyenInternal) public var title: Adyen.TextStyle { get set } -``` -```javascript -// Parent: SelectableFormItemStyle -@_spi(AdyenInternal) public var imageStyle: Adyen.ImageStyle { get set } -``` -```javascript -// Parent: SelectableFormItemStyle -@_spi(AdyenInternal) public var backgroundColor: UIKit.UIColor { get set } -``` -```javascript -// Parent: SelectableFormItemStyle -@_spi(AdyenInternal) public init(title: Adyen.TextStyle) -> Adyen.SelectableFormItemStyle -``` -```javascript -// Parent: SelectableFormItemStyle -@_spi(AdyenInternal) public static func ==(_: Adyen.SelectableFormItemStyle, _: Adyen.SelectableFormItemStyle) -> Swift.Bool -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class SelectableFormItemView : AdyenCompatible, AdyenObserver, AnyFormItemView, CALayerDelegate, CVarArg, CustomDebugStringConvertible, CustomStringConvertible, Equatable, Hashable, NSCoding, NSObjectProtocol, Sendable, UIAccessibilityIdentification, UIActivityItemsConfigurationProviding, UIAppearance, UIAppearanceContainer, UICoordinateSpace, UIDynamicItem, UIFocusEnvironment, UIFocusItem, UIFocusItemContainer, UILargeContentViewerItem, UIPasteConfigurationSupporting, UIPopoverPresentationControllerSourceItem, UIResponderStandardEditActions, UITraitChangeObservable, UITraitEnvironment, UIUserActivityRestoring -``` -```javascript -// Parent: SelectableFormItemView -@_spi(AdyenInternal) public required init(item: Adyen.SelectableFormItem) -> Adyen.SelectableFormItemView -``` -```javascript -// Parent: SelectableFormItemView -@_spi(AdyenInternal) @objc override public func didMoveToWindow() -> Swift.Void -``` -```javascript -// Parent: SelectableFormItemView -@_spi(AdyenInternal) @objc override public func layoutSubviews() -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class FormSeparatorItem : FormItem -``` -```javascript -// Parent: FormSeparatorItem -@_spi(AdyenInternal) public var subitems: [any Adyen.FormItem] { get set } -``` -```javascript -// Parent: FormSeparatorItem -@_spi(AdyenInternal) public let color: UIKit.UIColor { get } -``` -```javascript -// Parent: FormSeparatorItem -@_spi(AdyenInternal) public var identifier: Swift.String? { get set } -``` -```javascript -// Parent: FormSeparatorItem -@_spi(AdyenInternal) public init(color: UIKit.UIColor) -> Adyen.FormSeparatorItem -``` -```javascript -// Parent: FormSeparatorItem -@_spi(AdyenInternal) public func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class FormSpacerItem : FormItem -``` -```javascript -// Parent: FormSpacerItem -@_spi(AdyenInternal) public var identifier: Swift.String? { get set } -``` -```javascript -// Parent: FormSpacerItem -@_spi(AdyenInternal) public let subitems: [any Adyen.FormItem] { get } -``` -```javascript -// Parent: FormSpacerItem -@_spi(AdyenInternal) public let standardSpaceMultiplier: Swift.Int { get } -``` -```javascript -// Parent: FormSpacerItem -@_spi(AdyenInternal) public init(numberOfSpaces: Swift.Int = $DEFAULT_ARG) -> Adyen.FormSpacerItem -``` -```javascript -// Parent: FormSpacerItem -@_spi(AdyenInternal) public func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class FormSpacerItemView : AdyenCompatible, AdyenObserver, AnyFormItemView, CALayerDelegate, CVarArg, CustomDebugStringConvertible, CustomStringConvertible, Equatable, Hashable, NSCoding, NSObjectProtocol, Sendable, UIAccessibilityIdentification, UIActivityItemsConfigurationProviding, UIAppearance, UIAppearanceContainer, UICoordinateSpace, UIDynamicItem, UIFocusEnvironment, UIFocusItem, UIFocusItemContainer, UILargeContentViewerItem, UIPasteConfigurationSupporting, UIPopoverPresentationControllerSourceItem, UIResponderStandardEditActions, UITraitChangeObservable, UITraitEnvironment, UIUserActivityRestoring -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class FormSplitItem : FormItem -``` -```javascript -// Parent: FormSplitItem -@_spi(AdyenInternal) public let style: any Adyen.ViewStyle { get } -``` -```javascript -// Parent: FormSplitItem -@_spi(AdyenInternal) public var identifier: Swift.String? { get set } -``` -```javascript -// Parent: FormSplitItem -@_spi(AdyenInternal) public var subitems: [any Adyen.FormItem] { get } -``` -```javascript -// Parent: FormSplitItem -@_spi(AdyenInternal) public init(items: any Adyen.FormItem..., style: any Adyen.ViewStyle) -> Adyen.FormSplitItem -``` -```javascript -// Parent: FormSplitItem -@_spi(AdyenInternal) public func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class FormTextInputItem : FormItem, Hidable, InputViewRequiringFormItem, ValidatableFormItem -``` -```javascript -// Parent: FormTextInputItem -@_spi(AdyenInternal) public var isHidden: Adyen.AdyenObservable { get set } -``` -```javascript -// Parent: FormTextInputItem -@_spi(AdyenInternal) public var isEnabled: Swift.Bool { get set } -``` -```javascript -// Parent: FormTextInputItem -@_spi(AdyenInternal) public var $isEnabled: Adyen.AdyenObservable { get } -``` -```javascript -// Parent: FormTextInputItem -@_spi(AdyenInternal) override public func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: FormTextInputItem -@_spi(AdyenInternal) override public init(style: Adyen.FormTextItemStyle = $DEFAULT_ARG) -> Adyen.FormTextInputItem -``` -```javascript -// Parent: FormTextInputItem -@_spi(AdyenInternal) override public func isValid() -> Swift.Bool -``` -```javascript -// Parent: FormTextInputItem -@_spi(AdyenInternal) public func focus() -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class FormTextInputItemView : AdyenCompatible, AdyenObserver, AnyFormItemView, AnyFormTextItemView, AnyFormValidatableValueItemView, AnyFormValueItemView, CALayerDelegate, CVarArg, CustomDebugStringConvertible, CustomStringConvertible, Equatable, Hashable, NSCoding, NSObjectProtocol, Sendable, UIAccessibilityIdentification, UIActivityItemsConfigurationProviding, UIAppearance, UIAppearanceContainer, UICoordinateSpace, UIDynamicItem, UIFocusEnvironment, UIFocusItem, UIFocusItemContainer, UILargeContentViewerItem, UIPasteConfigurationSupporting, UIPopoverPresentationControllerSourceItem, UIResponderStandardEditActions, UITextFieldDelegate, UITraitChangeObservable, UITraitEnvironment, UIUserActivityRestoring -``` -```javascript -// Parent: FormTextInputItemView -@_spi(AdyenInternal) public required init(item: Adyen.FormTextInputItem) -> Adyen.FormTextInputItemView -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) open class FormTextItem : FormItem, InputViewRequiringFormItem, ValidatableFormItem -``` -```javascript -// Parent: FormTextItem -@_spi(AdyenInternal) public var placeholder: Swift.String? { get set } -``` -```javascript -// Parent: FormTextItem -@_spi(AdyenInternal) public var $placeholder: Adyen.AdyenObservable { get } -``` -```javascript -// Parent: FormTextItem -@_spi(AdyenInternal) override public var value: Swift.String { get set } -``` -```javascript -// Parent: FormTextItem -@_spi(AdyenInternal) public var formatter: (any Adyen.Formatter)? { get set } -``` -```javascript -// Parent: FormTextItem -@_spi(AdyenInternal) public var validator: (any Adyen.Validator)? { get set } -``` -```javascript -// Parent: FormTextItem -@_spi(AdyenInternal) public var autocapitalizationType: UIKit.UITextAutocapitalizationType { get set } -``` -```javascript -// Parent: FormTextItem -@_spi(AdyenInternal) public var autocorrectionType: UIKit.UITextAutocorrectionType { get set } -``` -```javascript -// Parent: FormTextItem -@_spi(AdyenInternal) public var keyboardType: UIKit.UIKeyboardType { get set } -``` -```javascript -// Parent: FormTextItem -@_spi(AdyenInternal) public var contentType: UIKit.UITextContentType? { get set } -``` -```javascript -// Parent: FormTextItem -@_spi(AdyenInternal) public var allowsValidationWhileEditing: Swift.Bool { get set } -``` -```javascript -// Parent: FormTextItem -@_spi(AdyenInternal) public var onDidBeginEditing: (() -> Swift.Void)? { get set } -``` -```javascript -// Parent: FormTextItem -@_spi(AdyenInternal) public var onDidEndEditing: (() -> Swift.Void)? { get set } -``` -```javascript -// Parent: FormTextItem -@_spi(AdyenInternal) public init(style: Adyen.FormTextItemStyle) -> Adyen.FormTextItem -``` -```javascript -// Parent: FormTextItem -@_spi(AdyenInternal) override public func isValid() -> Swift.Bool -``` -```javascript -// Parent: FormTextItem -@_spi(AdyenInternal) override public func validationStatus() -> Adyen.ValidationStatus? -``` -```javascript -// Parent: Root -public struct FormTextItemStyle : FormValueItemStyle, TintableStyle, ViewStyle -``` -```javascript -// Parent: FormTextItemStyle -public var title: Adyen.TextStyle { get set } -``` -```javascript -// Parent: FormTextItemStyle -public var text: Adyen.TextStyle { get set } -``` -```javascript -// Parent: FormTextItemStyle -public var placeholderText: Adyen.TextStyle? { get set } -``` -```javascript -// Parent: FormTextItemStyle -public var icon: Adyen.ImageStyle { get set } -``` -```javascript -// Parent: FormTextItemStyle -public var tintColor: UIKit.UIColor? { get set } -``` -```javascript -// Parent: FormTextItemStyle -public var backgroundColor: UIKit.UIColor { get set } -``` -```javascript -// Parent: FormTextItemStyle -public var errorColor: UIKit.UIColor { get set } -``` -```javascript -// Parent: FormTextItemStyle -public var separatorColor: UIKit.UIColor? { get set } -``` -```javascript -// Parent: FormTextItemStyle -public init(title: Adyen.TextStyle, text: Adyen.TextStyle, placeholderText: Adyen.TextStyle? = $DEFAULT_ARG, icon: Adyen.ImageStyle) -> Adyen.FormTextItemStyle -``` -```javascript -// Parent: FormTextItemStyle -public init(tintColor: UIKit.UIColor) -> Adyen.FormTextItemStyle -``` -```javascript -// Parent: FormTextItemStyle -public init() -> Adyen.FormTextItemStyle -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol FormTextItemViewDelegate -``` -```javascript -// Parent: FormTextItemViewDelegate -@_spi(AdyenInternal) public func didReachMaximumLength(in: Adyen.FormTextItemView) -> Swift.Void -``` -```javascript -// Parent: FormTextItemViewDelegate -@_spi(AdyenInternal) public func didSelectReturnKey(in: Adyen.FormTextItemView) -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol AnyFormTextItemView : AnyFormItemView -``` -```javascript -// Parent: AnyFormTextItemView -@_spi(AdyenInternal) public var delegate: (any Adyen.FormTextItemViewDelegate)? { get set } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) open class FormTextItemView : AdyenCompatible, AdyenObserver, AnyFormItemView, AnyFormTextItemView, AnyFormValidatableValueItemView, AnyFormValueItemView, CALayerDelegate, CVarArg, CustomDebugStringConvertible, CustomStringConvertible, Equatable, Hashable, NSCoding, NSObjectProtocol, Sendable, UIAccessibilityIdentification, UIActivityItemsConfigurationProviding, UIAppearance, UIAppearanceContainer, UICoordinateSpace, UIDynamicItem, UIFocusEnvironment, UIFocusItem, UIFocusItemContainer, UILargeContentViewerItem, UIPasteConfigurationSupporting, UIPopoverPresentationControllerSourceItem, UIResponderStandardEditActions, UITextFieldDelegate, UITraitChangeObservable, UITraitEnvironment, UIUserActivityRestoring -``` -```javascript -// Parent: FormTextItemView -@_spi(AdyenInternal) override public var accessibilityLabelView: UIKit.UIView? { get } -``` -```javascript -// Parent: FormTextItemView -@_spi(AdyenInternal) public required init(item: ItemType) -> Adyen.FormTextItemView -``` -```javascript -// Parent: FormTextItemView -@_spi(AdyenInternal) override public func reset() -> Swift.Void -``` -```javascript -// Parent: FormTextItemView -@_spi(AdyenInternal) public weak var delegate: (any Adyen.FormTextItemViewDelegate)? { get set } -``` -```javascript -// Parent: FormTextItemView -@_spi(AdyenInternal) public lazy var textField: Adyen.TextField { get set } -``` -```javascript -// Parent: FormTextItemView -@_spi(AdyenInternal) public var accessory: Adyen.FormTextItemView.AccessoryType { get set } -``` -```javascript -// Parent: FormTextItemView -@_spi(AdyenInternal) override public var isValid: Swift.Bool { get } -``` -```javascript -// Parent: FormTextItemView -@_spi(AdyenInternal) override public func showValidation() -> Swift.Void -``` -```javascript -// Parent: FormTextItemView -@_spi(AdyenInternal) override open func configureSeparatorView() -> Swift.Void -``` -```javascript -// Parent: FormTextItemView -@_spi(AdyenInternal) @objc override open dynamic var lastBaselineAnchor: UIKit.NSLayoutYAxisAnchor { get } -``` -```javascript -// Parent: FormTextItemView -@_spi(AdyenInternal) @objc override open dynamic var canBecomeFirstResponder: Swift.Bool { get } -``` -```javascript -// Parent: FormTextItemView -@_spi(AdyenInternal) @discardableResult @objc override open dynamic func becomeFirstResponder() -> Swift.Bool -``` -```javascript -// Parent: FormTextItemView -@_spi(AdyenInternal) @discardableResult @objc override open dynamic func resignFirstResponder() -> Swift.Bool -``` -```javascript -// Parent: FormTextItemView -@_spi(AdyenInternal) @objc override open dynamic var isFirstResponder: Swift.Bool { get } -``` -```javascript -// Parent: FormTextItemView -@_spi(AdyenInternal) @objc public func textFieldShouldReturn(_: UIKit.UITextField) -> Swift.Bool -``` -```javascript -// Parent: FormTextItemView -@_spi(AdyenInternal) @objc open func textFieldDidEndEditing(_: UIKit.UITextField) -> Swift.Void -``` -```javascript -// Parent: FormTextItemView -@_spi(AdyenInternal) @objc open func textFieldDidBeginEditing(_: UIKit.UITextField) -> Swift.Void -``` -```javascript -// Parent: FormTextItemView -@_spi(AdyenInternal) override open func updateValidationStatus(forced: Swift.Bool = $DEFAULT_ARG) -> Swift.Void -``` -```javascript -// Parent: FormTextItemView -@_spi(AdyenInternal) public func notifyDelegateOfMaxLengthIfNeeded() -> Swift.Void -``` -```javascript -// Parent: FormTextItemView -@_spi(AdyenInternal) public enum AccessoryType : Equatable -``` -```javascript -// Parent: FormTextItemView.AccessoryType -@_spi(AdyenInternal) case invalid -``` -```javascript -// Parent: FormTextItemView.AccessoryType -@_spi(AdyenInternal) case valid -``` -```javascript -// Parent: FormTextItemView.AccessoryType -@_spi(AdyenInternal) case customView(UIKit.UIView) -``` -```javascript -// Parent: FormTextItemView.AccessoryType -@_spi(AdyenInternal) case none -``` -```javascript -// Parent: FormTextItemView.AccessoryType -@_spi(AdyenInternal) public static func __derived_enum_equals(_: Adyen.FormTextItemView.AccessoryType, _: Adyen.FormTextItemView.AccessoryType) -> Swift.Bool -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) @objc public final class TextField : AdyenCompatible, CALayerDelegate, CVarArg, CustomDebugStringConvertible, CustomStringConvertible, Equatable, Hashable, NSCoding, NSObjectProtocol, Sendable, UIAccessibilityIdentification, UIActivityItemsConfigurationProviding, UIAppearance, UIAppearanceContainer, UIContentSizeCategoryAdjusting, UIContextMenuInteractionDelegate, UICoordinateSpace, UIDynamicItem, UIFocusEnvironment, UIFocusItem, UIFocusItemContainer, UIKeyInput, UILargeContentViewerItem, UILetterformAwareAdjusting, UIPasteConfigurationSupporting, UIPopoverPresentationControllerSourceItem, UIResponderStandardEditActions, UITextDraggable, UITextDroppable, UITextInput, UITextInputTraits, UITextPasteConfigurationSupporting, UITraitChangeObservable, UITraitEnvironment, UIUserActivityRestoring -``` -```javascript -// Parent: TextField -@_spi(AdyenInternal) public var allowsEditingActions: Swift.Bool { get set } -``` -```javascript -// Parent: TextField -@_spi(AdyenInternal) @objc override public var accessibilityValue: Swift.String? { get set } -``` -```javascript -// Parent: TextField -@_spi(AdyenInternal) @objc override public var font: UIKit.UIFont? { get set } -``` -```javascript -// Parent: TextField -@_spi(AdyenInternal) @objc override public func canPerformAction(_: ObjectiveC.Selector, withSender: Any?) -> Swift.Bool -``` -```javascript -// Parent: TextField -@_spi(AdyenInternal) @objc override public dynamic init(frame: CoreFoundation.CGRect) -> Adyen.TextField -``` -```javascript -// Parent: TextField -@_spi(AdyenInternal) @objc public required dynamic init(coder: Foundation.NSCoder) -> Adyen.TextField? -``` -```javascript -// Parent: TextField -@_spi(AdyenInternal) public func apply(placeholderText: Swift.String?, with: Adyen.TextStyle?) -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class FormToggleItem : FormItem, Hidable -``` -```javascript -// Parent: FormToggleItem -@_spi(AdyenInternal) public var isHidden: Adyen.AdyenObservable { get set } -``` -```javascript -// Parent: FormToggleItem -@_spi(AdyenInternal) public init(style: Adyen.FormToggleItemStyle = $DEFAULT_ARG) -> Adyen.FormToggleItem -``` -```javascript -// Parent: FormToggleItem -@_spi(AdyenInternal) override public func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: Root -public struct FormToggleItemStyle : FormValueItemStyle, TintableStyle, ViewStyle -``` -```javascript -// Parent: FormToggleItemStyle -public var title: Adyen.TextStyle { get set } -``` -```javascript -// Parent: FormToggleItemStyle -public var tintColor: UIKit.UIColor? { get set } -``` -```javascript -// Parent: FormToggleItemStyle -public var separatorColor: UIKit.UIColor? { get set } -``` -```javascript -// Parent: FormToggleItemStyle -public var backgroundColor: UIKit.UIColor { get set } -``` -```javascript -// Parent: FormToggleItemStyle -public init(title: Adyen.TextStyle) -> Adyen.FormToggleItemStyle -``` -```javascript -// Parent: FormToggleItemStyle -public init() -> Adyen.FormToggleItemStyle -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class FormToggleItemView : AdyenCompatible, AdyenObserver, AnyFormItemView, AnyFormValueItemView, CALayerDelegate, CVarArg, CustomDebugStringConvertible, CustomStringConvertible, Equatable, Hashable, NSCoding, NSObjectProtocol, Sendable, UIAccessibilityIdentification, UIActivityItemsConfigurationProviding, UIAppearance, UIAppearanceContainer, UICoordinateSpace, UIDynamicItem, UIFocusEnvironment, UIFocusItem, UIFocusItemContainer, UILargeContentViewerItem, UIPasteConfigurationSupporting, UIPopoverPresentationControllerSourceItem, UIResponderStandardEditActions, UITraitChangeObservable, UITraitEnvironment, UIUserActivityRestoring -``` -```javascript -// Parent: FormToggleItemView -@_spi(AdyenInternal) public required init(item: Adyen.FormToggleItem) -> Adyen.FormToggleItemView -``` -```javascript -// Parent: FormToggleItemView -@_spi(AdyenInternal) @discardableResult @objc override public func accessibilityActivate() -> Swift.Bool -``` -```javascript -// Parent: FormToggleItemView -@_spi(AdyenInternal) override public func reset() -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol PickerElement : CustomStringConvertible, Equatable -``` -```javascript -// Parent: PickerElement -@_spi(AdyenInternal) public var identifier: Swift.String { get } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct BasePickerElement : CustomStringConvertible, Equatable, PickerElement -``` -```javascript -// Parent: BasePickerElement -@_spi(AdyenInternal) public let identifier: Swift.String { get } -``` -```javascript -// Parent: BasePickerElement -@_spi(AdyenInternal) public let element: ElementType { get } -``` -```javascript -// Parent: BasePickerElement -@_spi(AdyenInternal) public static func ==(_: Adyen.BasePickerElement, _: Adyen.BasePickerElement) -> Swift.Bool -``` -```javascript -// Parent: BasePickerElement -@_spi(AdyenInternal) public var description: Swift.String { get } -``` -```javascript -// Parent: BasePickerElement -@_spi(AdyenInternal) public init(identifier: Swift.String, element: ElementType) -> Adyen.BasePickerElement -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) open class BaseFormPickerItem : FormItem, Hidable, InputViewRequiringFormItem -``` -```javascript -// Parent: BaseFormPickerItem -@_spi(AdyenInternal) public var isHidden: Adyen.AdyenObservable { get set } -``` -```javascript -// Parent: BaseFormPickerItem -@_spi(AdyenInternal) public var selectableValues: [Adyen.BasePickerElement] { get set } -``` -```javascript -// Parent: BaseFormPickerItem -@_spi(AdyenInternal) public var $selectableValues: Adyen.AdyenObservable<[Adyen.BasePickerElement]> { get } -``` -```javascript -// Parent: BaseFormPickerItem -@_spi(AdyenInternal) public init(preselectedValue: Adyen.BasePickerElement, selectableValues: [Adyen.BasePickerElement], style: Adyen.FormTextItemStyle) -> Adyen.BaseFormPickerItem -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) open class BaseFormPickerItemView : AdyenCompatible, AdyenObserver, AnyFormItemView, AnyFormValueItemView, CALayerDelegate, CVarArg, CustomDebugStringConvertible, CustomStringConvertible, Equatable, Hashable, NSCoding, NSObjectProtocol, Sendable, UIAccessibilityIdentification, UIActivityItemsConfigurationProviding, UIAppearance, UIAppearanceContainer, UICoordinateSpace, UIDynamicItem, UIFocusEnvironment, UIFocusItem, UIFocusItemContainer, UILargeContentViewerItem, UIPasteConfigurationSupporting, UIPickerViewDataSource, UIPickerViewDelegate, UIPopoverPresentationControllerSourceItem, UIResponderStandardEditActions, UITraitChangeObservable, UITraitEnvironment, UIUserActivityRestoring -``` -```javascript -// Parent: BaseFormPickerItemView -@_spi(AdyenInternal) public required init(item: Adyen.BaseFormPickerItem) -> Adyen.BaseFormPickerItemView -``` -```javascript -// Parent: BaseFormPickerItemView -@_spi(AdyenInternal) @objc override open dynamic var canBecomeFirstResponder: Swift.Bool { get } -``` -```javascript -// Parent: BaseFormPickerItemView -@_spi(AdyenInternal) @discardableResult @objc override open dynamic func becomeFirstResponder() -> Swift.Bool -``` -```javascript -// Parent: BaseFormPickerItemView -@_spi(AdyenInternal) @discardableResult @objc override open dynamic func resignFirstResponder() -> Swift.Bool -``` -```javascript -// Parent: BaseFormPickerItemView -@_spi(AdyenInternal) open func initialize() -> Swift.Void -``` -```javascript -// Parent: BaseFormPickerItemView -@_spi(AdyenInternal) public lazy var inputControl: any Adyen.PickerTextInputControl { get set } -``` -```javascript -// Parent: BaseFormPickerItemView -@_spi(AdyenInternal) @objc public func numberOfComponents(in: UIKit.UIPickerView) -> Swift.Int -``` -```javascript -// Parent: BaseFormPickerItemView -@_spi(AdyenInternal) @objc public func pickerView(_: UIKit.UIPickerView, numberOfRowsInComponent: Swift.Int) -> Swift.Int -``` -```javascript -// Parent: BaseFormPickerItemView -@_spi(AdyenInternal) @objc public func pickerView(_: UIKit.UIPickerView, titleForRow: Swift.Int, forComponent: Swift.Int) -> Swift.String? -``` -```javascript -// Parent: BaseFormPickerItemView -@_spi(AdyenInternal) @objc public func pickerView(_: UIKit.UIPickerView, didSelectRow: Swift.Int, inComponent: Swift.Int) -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol PickerTextInputControl -``` -```javascript -// Parent: PickerTextInputControl -@_spi(AdyenInternal) public var onDidResignFirstResponder: (() -> Swift.Void)? { get set } -``` -```javascript -// Parent: PickerTextInputControl -@_spi(AdyenInternal) public var onDidBecomeFirstResponder: (() -> Swift.Void)? { get set } -``` -```javascript -// Parent: PickerTextInputControl -@_spi(AdyenInternal) public var onDidTap: (() -> Swift.Void)? { get set } -``` -```javascript -// Parent: PickerTextInputControl -@_spi(AdyenInternal) public var showChevron: Swift.Bool { get set } -``` -```javascript -// Parent: PickerTextInputControl -@_spi(AdyenInternal) public var label: Swift.String? { get set } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public typealias IssuerPickerItem = Adyen.BasePickerElement -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class FormIssuersPickerItem : FormItem, Hidable, InputViewRequiringFormItem -``` -```javascript -// Parent: FormIssuersPickerItem -@_spi(AdyenInternal) override public init(preselectedValue: Adyen.IssuerPickerItem, selectableValues: [Adyen.IssuerPickerItem], style: Adyen.FormTextItemStyle) -> Adyen.FormIssuersPickerItem -``` -```javascript -// Parent: FormIssuersPickerItem -@_spi(AdyenInternal) override public func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: Root -public protocol FormValueItemStyle : TintableStyle, ViewStyle -``` -```javascript -// Parent: FormValueItemStyle -public var separatorColor: UIKit.UIColor? { get } -``` -```javascript -// Parent: FormValueItemStyle -public var title: Adyen.TextStyle { get } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) open class FormValueItem : FormItem -``` -```javascript -// Parent: FormValueItem -@_spi(AdyenInternal) public var subitems: [any Adyen.FormItem] { get } -``` -```javascript -// Parent: FormValueItem -@_spi(AdyenInternal) public var identifier: Swift.String? { get set } -``` -```javascript -// Parent: FormValueItem -@_spi(AdyenInternal) public var value: ValueType { get set } -``` -```javascript -// Parent: FormValueItem -@_spi(AdyenInternal) public var publisher: Adyen.AdyenObservable { get set } -``` -```javascript -// Parent: FormValueItem -@_spi(AdyenInternal) public var style: StyleType { get set } -``` -```javascript -// Parent: FormValueItem -@_spi(AdyenInternal) public var title: Swift.String? { get set } -``` -```javascript -// Parent: FormValueItem -@_spi(AdyenInternal) public var $title: Adyen.AdyenObservable { get } -``` -```javascript -// Parent: FormValueItem -@_spi(AdyenInternal) open func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) open class FormValueItemView> : AdyenCompatible, AdyenObserver, AnyFormItemView, AnyFormValueItemView, CALayerDelegate, CVarArg, CustomDebugStringConvertible, CustomStringConvertible, Equatable, Hashable, NSCoding, NSObjectProtocol, Sendable, UIAccessibilityIdentification, UIActivityItemsConfigurationProviding, UIAppearance, UIAppearanceContainer, UICoordinateSpace, UIDynamicItem, UIFocusEnvironment, UIFocusItem, UIFocusItemContainer, UILargeContentViewerItem, UIPasteConfigurationSupporting, UIPopoverPresentationControllerSourceItem, UIResponderStandardEditActions, UITraitChangeObservable, UITraitEnvironment, UIUserActivityRestoring -``` -```javascript -// Parent: FormValueItemView -@_spi(AdyenInternal) public lazy var titleLabel: UIKit.UILabel { get set } -``` -```javascript -// Parent: FormValueItemView -@_spi(AdyenInternal) public required init>(item: ItemType) -> Adyen.FormValueItemView -``` -```javascript -// Parent: FormValueItemView -@_spi(AdyenInternal) @objc override open dynamic func didAddSubview>(_: UIKit.UIView) -> Swift.Void -``` -```javascript -// Parent: FormValueItemView -@_spi(AdyenInternal) open var isEditing: Swift.Bool { get set } -``` -```javascript -// Parent: FormValueItemView -@_spi(AdyenInternal) public var showsSeparator: Swift.Bool { get set } -``` -```javascript -// Parent: FormValueItemView -@_spi(AdyenInternal) open func configureSeparatorView>() -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol AnyFormValueItemView : AnyFormItemView -``` -```javascript -// Parent: AnyFormValueItemView -@_spi(AdyenInternal) public var isEditing: Swift.Bool { get set } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public protocol FormPickable : Equatable -``` -```javascript -// Parent: FormPickable -@_spi(AdyenInternal) public var identifier: Swift.String { get } -``` -```javascript -// Parent: FormPickable -@_spi(AdyenInternal) public var icon: UIKit.UIImage? { get } -``` -```javascript -// Parent: FormPickable -@_spi(AdyenInternal) public var title: Swift.String { get } -``` -```javascript -// Parent: FormPickable -@_spi(AdyenInternal) public var subtitle: Swift.String? { get } -``` -```javascript -// Parent: FormPickable -@_spi(AdyenInternal) public var trailingText: Swift.String? { get } -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public struct FormPickerElement : Equatable, FormPickable -``` -```javascript -// Parent: FormPickerElement -@_spi(AdyenInternal) public let identifier: Swift.String { get } -``` -```javascript -// Parent: FormPickerElement -@_spi(AdyenInternal) public let icon: UIKit.UIImage? { get } -``` -```javascript -// Parent: FormPickerElement -@_spi(AdyenInternal) public let title: Swift.String { get } -``` -```javascript -// Parent: FormPickerElement -@_spi(AdyenInternal) public let subtitle: Swift.String? { get } -``` -```javascript -// Parent: FormPickerElement -@_spi(AdyenInternal) public let trailingText: Swift.String? { get } -``` -```javascript -// Parent: FormPickerElement -@_spi(AdyenInternal) public init(identifier: Swift.String, icon: UIKit.UIImage? = $DEFAULT_ARG, title: Swift.String, subtitle: Swift.String? = $DEFAULT_ARG, trailingText: Swift.String? = $DEFAULT_ARG) -> Adyen.FormPickerElement -``` -```javascript -// Parent: FormPickerElement -@_spi(AdyenInternal) public static func __derived_struct_equals(_: Adyen.FormPickerElement, _: Adyen.FormPickerElement) -> Swift.Bool -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) open class FormPickerItem : FormItem, ValidatableFormItem -``` -```javascript -// Parent: FormPickerItem -@_spi(AdyenInternal) public let localizationParameters: Adyen.LocalizationParameters? { get } -``` -```javascript -// Parent: FormPickerItem -@_spi(AdyenInternal) public var isOptional: Swift.Bool { get } -``` -```javascript -// Parent: FormPickerItem -@_spi(AdyenInternal) override public var value: Value? { get set } -``` -```javascript -// Parent: FormPickerItem -@_spi(AdyenInternal) public var selectableValues: [Value] { get set } -``` -```javascript -// Parent: FormPickerItem -@_spi(AdyenInternal) public var $selectableValues: Adyen.AdyenObservable<[Value]> { get } -``` -```javascript -// Parent: FormPickerItem -@_spi(AdyenInternal) public init(preselectedValue: Value?, selectableValues: [Value], title: Swift.String, placeholder: Swift.String, style: Adyen.FormTextItemStyle, presenter: (any Adyen.ViewControllerPresenter)?, localizationParameters: Adyen.LocalizationParameters? = $DEFAULT_ARG, identifier: Swift.String? = $DEFAULT_ARG) -> Adyen.FormPickerItem -``` -```javascript -// Parent: FormPickerItem -@_spi(AdyenInternal) public func updateOptionalStatus(isOptional: Swift.Bool) -> Swift.Void -``` -```javascript -// Parent: FormPickerItem -@_spi(AdyenInternal) public func resetValue() -> Swift.Void -``` -```javascript -// Parent: FormPickerItem -@_spi(AdyenInternal) override public func build(with: Adyen.FormItemViewBuilder) -> any Adyen.AnyFormItemView -``` -```javascript -// Parent: FormPickerItem -@_spi(AdyenInternal) override public func isValid() -> Swift.Bool -``` -```javascript -// Parent: FormPickerItem -@_spi(AdyenInternal) override public func validationStatus() -> Adyen.ValidationStatus? -``` -```javascript -// Parent: FormPickerItem -@_spi(AdyenInternal) public func updateValidationFailureMessage() -> Swift.Void -``` -```javascript -// Parent: FormPickerItem -@_spi(AdyenInternal) public func updateFormattedValue() -> Swift.Void -``` -```javascript -// Parent: FormPickerItem -@_spi(AdyenInternal) override public init(value: Value?, style: Adyen.FormTextItemStyle, placeholder: Swift.String) -> Adyen.FormPickerItem -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public class FormPickerItemView : AdyenCompatible, AdyenObserver, AnyFormItemView, AnyFormValidatableValueItemView, AnyFormValueItemView, CALayerDelegate, CVarArg, CustomDebugStringConvertible, CustomStringConvertible, Equatable, Hashable, NSCoding, NSObjectProtocol, Sendable, UIAccessibilityIdentification, UIActivityItemsConfigurationProviding, UIAppearance, UIAppearanceContainer, UICoordinateSpace, UIDynamicItem, UIFocusEnvironment, UIFocusItem, UIFocusItemContainer, UILargeContentViewerItem, UIPasteConfigurationSupporting, UIPopoverPresentationControllerSourceItem, UIResponderStandardEditActions, UITraitChangeObservable, UITraitEnvironment, UIUserActivityRestoring -``` -```javascript -// Parent: FormPickerItemView -@_spi(AdyenInternal) override public func showValidation() -> Swift.Void -``` -```javascript -// Parent: FormPickerItemView -@_spi(AdyenInternal) override public func reset() -> Swift.Void -``` -```javascript -// Parent: Root -@_spi(AdyenInternal) public final class FormPickerSearchViewController