diff --git a/Info.plist b/Info.plist new file mode 100644 index 0000000..06dc84d --- /dev/null +++ b/Info.plist @@ -0,0 +1,8 @@ +// +// File.swift +// public-api-diff +// +// Created by Alexander Guretzki on 11/10/2024. +// + +import Foundation diff --git a/Package.resolved b/Package.resolved index 393f191..5e1196d 100644 --- a/Package.resolved +++ b/Package.resolved @@ -9,13 +9,40 @@ "version" : "1.5.0" } }, + { + "identity" : "swift-docc-plugin", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-docc-plugin", + "state" : { + "revision" : "85e4bb4e1cd62cec64a4b8e769dcefdf0c5b9d64", + "version" : "1.4.3" + } + }, + { + "identity" : "swift-docc-symbolkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/swiftlang/swift-docc-symbolkit", + "state" : { + "revision" : "b45d1f2ed151d057b54504d653e0da5552844e34", + "version" : "1.0.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" : "86ed20990585f478c0daf309af645c2a528b59d8", + "version" : "0.54.6" } } ], diff --git a/Package.swift b/Package.swift index 958ba12..46c4e90 100644 --- a/Package.swift +++ b/Package.swift @@ -8,29 +8,131 @@ let package = Package( platforms: [ .macOS(.v13) ], + products: [ + .executable( + name: "public-api-diff", + targets: ["public-api-diff"] + ), + .library( + name: "SwiftInterfaceDiff", + targets: [ + "PADSwiftInterfaceDiff", + "PADOutputGenerator" + ] + ), + .library( + name: "PublicApiDiff", + targets: [ + "PADProjectBuilder", + "PADPackageFileAnalyzer", + "PADSwiftInterfaceDiff", + "PADOutputGenerator" + ] + ) + ], dependencies: [ .package(url: "https://github.com/apple/swift-argument-parser", from: "1.5.0"), - .package(url: "https://github.com/nicklockwood/SwiftFormat", from: "0.54.6") + .package(url: "https://github.com/swiftlang/swift-syntax", from: "600.0.0"), + .package(url: "https://github.com/nicklockwood/SwiftFormat", from: "0.54.6"), + .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0") ], targets: [ - // Targets are the basic building blocks of a package, defining a module or a test suite. - // Targets can depend on other targets in this package and products from dependencies. + + // MARK: - Executable Targets + .executableTarget( name: "public-api-diff", dependencies: [ + "PADProjectBuilder", + "PADSwiftInterfaceDiff", + "PADOutputGenerator", + "PADPackageFileAnalyzer", .product(name: "ArgumentParser", package: "swift-argument-parser") ], - path: "Sources" + path: "Sources/ExecutableTargets/CommandLineTool" ), + + // MARK: - Public Modules + + .target( + name: "PADSwiftInterfaceDiff", + dependencies: [ + "PADCore", + "PADLogging", + "FileHandlingModule", + .product(name: "SwiftSyntax", package: "swift-syntax"), + .product(name: "SwiftParser", package: "swift-syntax"), + ], + path: "Sources/PublicModules/PADSwiftInterfaceDiff" + ), + .target( + name: "PADPackageFileAnalyzer", + dependencies: [ + "PADCore", + "PADLogging", + "FileHandlingModule", + "ShellModule", + "SwiftPackageFileHelperModule" + ], + path: "Sources/PublicModules/PADPackageFileAnalyzer" + ), + .target( + name: "PADProjectBuilder", + dependencies: [ + "PADCore", + "PADLogging", + "FileHandlingModule", + "ShellModule", + "SwiftPackageFileHelperModule" + ], + path: "Sources/PublicModules/PADProjectBuilder" + ), + .target( + name: "PADOutputGenerator", + dependencies: ["PADCore"], + path: "Sources/PublicModules/PADOutputGenerator" + ), + + // MARK: - Shared/Public + + .target( + name: "PADCore", + path: "Sources/Shared/Public/PADCore" + ), + .target( + name: "PADLogging", + dependencies: ["FileHandlingModule"], + path: "Sources/Shared/Public/PADLogging" + ), + + // MARK: - Shared/Package + + .target( + name: "FileHandlingModule", + path: "Sources/Shared/Package/FileHandlingModule" + ), + .target( + name: "ShellModule", + path: "Sources/Shared/Package/ShellModule" + ), + .target( + name: "SwiftPackageFileHelperModule", + dependencies: ["FileHandlingModule", "ShellModule", "PADLogging"], + path: "Sources/Shared/Package/SwiftPackageFileHelperModule" + ), + + // MARK: - Test Targets + .testTarget( name: "UnitTests", - dependencies: ["public-api-diff"], + dependencies: [ + "public-api-diff" + ], 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/expected-reference-changes.md") ] ), .testTarget( @@ -40,7 +142,8 @@ 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-swift-interface-private.md"), + .copy("Resources/expected-reference-changes-swift-interface-public.md") ] ) ] diff --git a/README.md b/README.md index 7e3507e..c0b641e 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,52 @@ -# Swift Public API diff - -This tool allows comparing 2 versions of a swift package project and lists all changes in a human readable way. - -It makes use of `xcrun swift-api-digester -dump-sdk` to create a dump of the public api of your swift package and then runs it through a custom parser to process them. - -Alternatively you could use `xcrun swift-api-digester -diagnose-sdk` and pass the abi dumps into it. - -## How it works - -![image](https://github.com/user-attachments/assets/cc04d21a-06f6-42bc-8e73-4aef7af21d7a) - - -### Project Builder - -Builds the swift package project which is required for the next step to run the `xcrun swift-api-digester -dump-sdk` - -### ABIGenerator - -Makes use of `xcrun swift-api-digester -dump-sdk` to "dump" the public interface into an abi.json file. - -### SDKDumpGenerator - -Parses the abi.json files into an `SDKDump` object - -### SDKDumpAnalyzer - -Analyzes 2 `SDKDump` objects and detects `addition`s & `removal`s. - -### ChangeConsolidator - -The `ChangeConsolidator` takes 2 independent changes (`addition` & `removal`) and tries to match them based on the name, declKind and parent. - -| Match | -| --- | -| ![image](https://github.com/user-attachments/assets/f057c160-f85d-45af-b08f-203b89e43b41) | - -| No Match | Potentially false positive | -| --- | --- | -| ![image](https://github.com/user-attachments/assets/5ae3b624-b32a-41cc-9026-8ba0117cec57) | ![image](https://github.com/user-attachments/assets/a7e60605-fc1c-49ef-a203-d6a5466a6fda) | - -### OutputGenerator - -Receives a list of `Change`s and processes them into a human readable format. + [![πŸ§ͺ Run Tests](https://github.com/Adyen/adyen-swift-public-api-diff/actions/workflows/run-tests.yml/badge.svg)](https://github.com/Adyen/adyen-swift-public-api-diff/actions/workflows/run-tests.yml) + + # Swift Public API diff + + This tool allows comparing 2 versions of a swift (sdk) project and lists all changes in a human readable way. + + It makes use of `.swiftinterface` files that get produced during the archiving of a swift project and parses them using [`swift-syntax`](https://github.com/swiftlang/swift-syntax). + + ## Usage + + ``` + USAGE: public-api-diff --new --old [--output ] [--log-output ] [--scheme ] + + OPTIONS: + --new Specify the updated version to compare to + --old Specify the old version to compare to + --output Where to output the result (File path) + --log-output + Where to output the logs (File path) + --scheme Which scheme to build (Needed when comparing 2 xcode projects) + -h, --help Show help information. + ``` + +### Run as debug build +``` +swift run public-api-diff + --new "some/local/path" + --old "develop~https://github.com/some/repository" + --output "path/to/output.md" +``` + +### How to create a release build +``` +swift build --configuration release +``` + +### Run release build +``` +./public-api-diff + --new "some/local/path" + --old "develop~https://github.com/some/repository" + --output "path/to/output.md" +``` + +# Alternatives +- **swift-api-digester** + - `xcrun swift-api-digester -dump-sdk` + - `xcrun swift-api-digester -diagnose-sdk` + +# Inspiration + - https://github.com/sdidla/Hatch/blob/main/Sources/Hatch/SymbolParser.swift + - For parsing swift files using [swift-syntax](https://github.com/swiftlang/swift-syntax)'s [`SyntaxVisitor`](https://github.com/swiftlang/swift-syntax/blob/main/Sources/SwiftSyntax/generated/SyntaxVisitor.swift) diff --git a/ReferencePackages/UpdatedPackage/Sources/ReferencePackage/ReferencePackage.swift b/ReferencePackages/UpdatedPackage/Sources/ReferencePackage/ReferencePackage.swift index 27352e6..13cd1c2 100644 --- a/ReferencePackages/UpdatedPackage/Sources/ReferencePackage/ReferencePackage.swift +++ b/ReferencePackages/UpdatedPackage/Sources/ReferencePackage/ReferencePackage.swift @@ -22,18 +22,36 @@ import Foundation // MARK: - Protocol with associatedtype -public protocol CustomProtocol { +public protocol SimpleProtocol {} + +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 - public var getSetVar: Int + @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: Double public var getVar: Int @discardableResult public func function() -> Int { 0 } @@ -44,39 +62,57 @@ 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" } 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) { 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 @_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 @@ -102,7 +138,7 @@ public class ObjcClass: NSObject { // MARK: - Actor -public actor CustomActor {} +public actor CustomActor: SimpleProtocol {} // MARK: - Operators @@ -134,11 +170,44 @@ precedencegroup CustomPrecedence { // MARK: - Enums -public enum CustomEnum { +public enum CustomEnum { case normalCase - case caseWithString(String) - case caseWithTuple(String, Int) + case caseWithNamedString(title: T) + case caseWithTuple(_ foo: String, bar: Int) case caseWithBlock((Int) throws -> Void) + case a, b, c, d, e(NestedStructInExtension) indirect case recursive(CustomEnum) } + +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 + } + } +} + +extension CustomEnum.NestedStructInExtension { + + var description: String { + return string + } +} + +public extension CustomEnum where T == String { + + var titleOfCaseWithNamedString: String? { + if case let .caseWithNamedString(title) = self { + return title + } + return nil + } +} diff --git a/Sources/ExecutableTargets/CommandLineTool/public-api-diff.swift b/Sources/ExecutableTargets/CommandLineTool/public-api-diff.swift new file mode 100644 index 0000000..3bda3d4 --- /dev/null +++ b/Sources/ExecutableTargets/CommandLineTool/public-api-diff.swift @@ -0,0 +1,212 @@ +// +// 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 ArgumentParser +import Foundation + +import PADCore +import PADLogging + +import PADSwiftInterfaceDiff +import PADProjectBuilder +import PADOutputGenerator +import PADPackageFileAnalyzer + +/// The command line tool to analyze public api changes +@main +struct PublicApiDiff: AsyncParsableCommand { + + /// The representation of the new/updated project source + @Option(help: "Specify the updated version to compare to") + public var new: String + + /// The representation of the old/reference project source + @Option(help: "Specify the old version to compare to") + public var old: String + + /// The (optional) output file path + /// + /// If not defined the output will be printed to the console + @Option(help: "Where to output the result (File path)") + public var output: String? + + /// The (optional) path to the log output file + @Option(help: "Where to output the logs (File path)") + public var logOutput: String? + + /// The (optional) scheme to build (Needed when comparing 2 xcode projects) + @Option(help: "Which scheme to build (Needed when comparing 2 xcode projects)") + public var scheme: String? + + /// Entry point of the command line tool + public func run() async throws { + + let logLevel: LogLevel = .debug + let projectType: ProjectType = { // Only needed when we have to produce the .swiftinterface files + if let scheme { return .xcodeProject(scheme: scheme) } + return .swiftPackage + }() + let swiftInterfaceType: SwiftInterfaceType = .public // Only needed when we have to produce the .swiftinterface files + + let logger = Self.logger(with: logLevel, logOutputFilePath: logOutput) + + do { + var warnings = [String]() + var projectChanges = [Change]() + + let oldSource: ProjectSource = try .from(old) + let newSource: ProjectSource = try .from(new) + + // MARK: - Producing .swiftinterface files + + let projectBuilderResult = try await Self.buildProject( + oldSource: oldSource, + newSource: newSource, + projectType: projectType, + swiftInterfaceType: swiftInterfaceType, + logger: logger + ) + + // MARK: - Analyzing .swiftinterface files + + let swiftInterfaceChanges = try await Self.analyzeSwiftInterfaceFiles( + swiftInterfaceFiles: projectBuilderResult.swiftInterfaceFiles, + logger: logger + ) + + // MARK: - Analyzing Package.swift + + try Self.analyzeProject( + ofType: projectType, + projectDirectories: projectBuilderResult.projectDirectories, + changes: &projectChanges, + warnings: &warnings, + logger: logger + ) + + // MARK: - Merging Changes + + var changes = swiftInterfaceChanges + if !projectChanges.isEmpty { + changes["Package.swift"] = projectChanges + } + + // MARK: - Generate Output + + let generatedOutput = try Self.generateOutput( + for: changes, + warnings: warnings, + allTargets: projectBuilderResult.swiftInterfaceFiles.map(\.name).sorted(), + oldVersionName: oldSource.description, + newVersionName: newSource.description + ) + + // MARK: - + + if let output { + try FileManager.default.write(generatedOutput, to: output) + } else { + // We're not using a logger here as we always want to have it printed if no output was specified + print(generatedOutput) + } + + logger.log("βœ… Success", from: "Main") + } catch { + logger.log("πŸ’₯ \(error.localizedDescription)", from: "Main") + } + } +} + +private extension PublicApiDiff { + + static func logger( + with logLevel: LogLevel, + logOutputFilePath: String? + ) -> any Logging { + var loggers = [any Logging]() + if let logOutputFilePath { + loggers += [LogFileLogger(outputFilePath: logOutputFilePath)] + } + loggers += [SystemLogger().withLogLevel(logLevel)] + + return LoggingGroup(with: loggers) + } + + static func buildProject( + oldSource: ProjectSource, + newSource: ProjectSource, + projectType: ProjectType, + swiftInterfaceType: SwiftInterfaceType, + logger: any Logging + ) async throws -> ProjectBuilder.Result { + + let projectBuilder = ProjectBuilder( + projectType: projectType, + swiftInterfaceType: swiftInterfaceType, + logger: logger + ) + + return try await projectBuilder.build( + oldSource: oldSource, + newSource: newSource + ) + } + + static func analyzeProject( + ofType projectType: ProjectType, + projectDirectories: (old: URL, new: URL), + changes: inout [Change], + warnings: inout [String], + logger: any Logging + ) throws { + switch projectType { + case .swiftPackage: + let swiftPackageFileAnalyzer = SwiftPackageFileAnalyzer( + logger: logger + ) + let swiftPackageAnalysis = try swiftPackageFileAnalyzer.analyze( + oldProjectUrl: projectDirectories.old, + newProjectUrl: projectDirectories.new + ) + + warnings = swiftPackageAnalysis.warnings + changes = swiftPackageAnalysis.changes + case .xcodeProject: + warnings = [] + changes = [] + break // Nothing to do + } + } + + static func analyzeSwiftInterfaceFiles( + swiftInterfaceFiles: [SwiftInterfaceFile], + logger: any Logging + ) async throws -> [String: [Change]] { + let swiftInterfaceDiff = SwiftInterfaceDiff(logger: logger) + + return try await swiftInterfaceDiff.run( + with: swiftInterfaceFiles + ) + } + + static func generateOutput( + for changes: [String: [Change]], + warnings: [String], + allTargets: [String], + oldVersionName: String, + newVersionName: String + ) throws -> String { + let outputGenerator: any OutputGenerating = MarkdownOutputGenerator() + + return try outputGenerator.generate( + from: changes, + allTargets: allTargets, + oldVersionName: oldVersionName, + newVersionName: newVersionName, + warnings: warnings + ) + } +} diff --git a/Sources/Helpers/Models/Constants.swift b/Sources/Helpers/Models/Constants.swift deleted file mode 100644 index cf7554d..0000000 --- a/Sources/Helpers/Models/Constants.swift +++ /dev/null @@ -1,12 +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 - -enum Constants { - static let unknownType = "UNKNOWN_TYPE" - static let defaultArg = "$DEFAULT_ARG" -} diff --git a/Sources/Helpers/Models/IndependentChange.swift b/Sources/Helpers/Models/IndependentChange.swift deleted file mode 100644 index 3d324df..0000000 --- a/Sources/Helpers/Models/IndependentChange.swift +++ /dev/null @@ -1,31 +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 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 IndependentChange: 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 parentName: String { element.parentPath } -} diff --git a/Sources/Helpers/Models/SDKDump/ElementDescriptions/EnumCaseElement.swift b/Sources/Helpers/Models/SDKDump/ElementDescriptions/EnumCaseElement.swift deleted file mode 100644 index d04e1aa..0000000 --- a/Sources/Helpers/Models/SDKDump/ElementDescriptions/EnumCaseElement.swift +++ /dev/null @@ -1,58 +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 { - // 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)" - - 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/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 58a48fa..0000000 --- a/Sources/Helpers/Models/SDKDump/SDKDump+Element+Description.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. -// - -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]() - - // 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"] } - 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 1a2849e..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("Final") - } - - var hasDiscardableResult: Bool { - (declAttributes ?? []).contains("DiscardableResult") - } - - var isObjcAccessible: Bool { - (declAttributes ?? []).contains("ObjC") - } - - var isOverride: Bool { - (declAttributes ?? []).contains("Override") - } - - var isDynamic: Bool { - (declAttributes ?? []).contains("Dynamic") - } - - var isLazy: Bool { - (declAttributes ?? []).contains("Lazy") - } - - var isRequired: Bool { - (declAttributes ?? []).contains("Required") - } - - var isPrefix: Bool { - (declAttributes ?? []).contains("Prefix") - } - - var isPostfix: Bool { - (declAttributes ?? []).contains("Postfix") - } - - var isInfix: Bool { - (declAttributes ?? []).contains("Infix") - } - - var isInlinable: Bool { - (declAttributes ?? []).contains("Inlinable") - } - - var isIndirect: Bool { - (declAttributes ?? []).contains("Indirect") - } - - 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/Helpers/PipelineLogger.swift b/Sources/Helpers/PipelineLogger.swift deleted file mode 100644 index 55d3e0a..0000000 --- a/Sources/Helpers/PipelineLogger.swift +++ /dev/null @@ -1,51 +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 -import OSLog - -struct PipelineLogger: Logging { - - private let logLevel: LogLevel - - init(logLevel: LogLevel) { - self.logLevel = logLevel - } - - func log( - _ message: String, - from subsystem: String - ) { - switch logLevel { - case .quiet: - break - case .debug, .default: - 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)") - } - } -} - -private extension PipelineLogger { - - func logger(for subsystem: String) -> Logger { - Logger( - subsystem: subsystem, - category: "" // TODO: Pass the description/tag so it can be differentiated - ) - } -} diff --git a/Sources/Helpers/ProjectSource.swift b/Sources/Helpers/ProjectSource.swift deleted file mode 100644 index f09c029..0000000 --- a/Sources/Helpers/ProjectSource.swift +++ /dev/null @@ -1,49 +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 - -enum ProjectSourceError: LocalizedError, Equatable { - case invalidSourceValue(value: String) - - var errorDescription: String? { - switch self { - case let .invalidSourceValue(value): - "Invalid source parameter `\(value)`. It needs to either be a local file path or a repository in the format `[BRANCH_OR_TAG]\(ProjectSource.gitSourceSeparator)[REPOSITORY_URL]" - } - } -} - -enum ProjectSource: Equatable { - - /// The separator used to join branch & repository - static var gitSourceSeparator: String { "~" } - - case local(path: String) - case remote(branch: String, repository: String) - - static func from(_ rawValue: String, fileHandler: FileHandling) throws -> ProjectSource { - if fileHandler.fileExists(atPath: rawValue) { - return .local(path: rawValue) - } - - let remoteComponents = rawValue.components(separatedBy: gitSourceSeparator) - if remoteComponents.count == 2, let branch = remoteComponents.first, let repository = remoteComponents.last, URL(string: repository) != nil { - return .remote(branch: branch, repository: repository) - } - - throw ProjectSourceError.invalidSourceValue(value: rawValue) - } - - var description: String { - switch self { - case let .local(path): - return path - case let .remote(branch, repository): - return "\(repository) @ \(branch)" - } - } -} diff --git a/Sources/Helpers/XcodeTools.swift b/Sources/Helpers/XcodeTools.swift deleted file mode 100644 index 447fbd6..0000000 --- a/Sources/Helpers/XcodeTools.swift +++ /dev/null @@ -1,121 +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 XcodeToolsError: LocalizedError, CustomDebugStringConvertible { - var errorDescription: String - var underlyingError: String - - var debugDescription: String { errorDescription } -} - -struct XcodeTools { - - private 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" - } - - private let shell: ShellHandling - private let fileHandler: FileHandling - - init( - shell: ShellHandling = Shell(), - fileHandler: FileHandling = FileManager.default - ) { - self.shell = shell - self.fileHandler = fileHandler - } - - func loadPackageDescription( - projectDirectoryPath: String - ) throws -> String { - let command = [ - "cd \(projectDirectoryPath);", - "swift package describe --type json" - ] - - return shell.execute(command.joined(separator: " ")) - } - - func build( - projectDirectoryPath: String, - scheme: String, - isPackage: Bool - ) throws { - var command = [ - "cd \(projectDirectoryPath);", - "xcodebuild -scheme \"\(scheme)\"", - "-derivedDataPath \(Constants.derivedDataPath)", - iOSTarget, - "-destination \"platform=iOS,name=Any iOS Device\"" - ] - - if isPackage { - command += [ - "-skipPackagePluginValidation" - ] - } - - // print("πŸ‘Ύ \(command.joined(separator: " "))") - let result = shell.execute(command.joined(separator: " ")) - - if - !fileHandler.fileExists(atPath: "\(projectDirectoryPath)/\(Constants.derivedDataPath)") || - result.range(of: "xcodebuild: error:") != nil || - result.range(of: "BUILD FAILED") != nil - { - print(result) - throw XcodeToolsError( - errorDescription: "πŸ’₯ Building project failed", - underlyingError: result - ) - } - } - - func dumpSdk( - projectDirectoryPath: String, - module: String, - outputFilePath: String - ) { - let sdkDumpInputPath = "\(Constants.derivedDataPath)/Build/Products/Debug-iphonesimulator" - - let command = [ - "cd \(projectDirectoryPath);", - "xcrun swift-api-digester -dump-sdk", - "-module \(module)", - "-I \(sdkDumpInputPath)", - "-o \(outputFilePath)", - iOSTarget, - "-abort-on-module-fail" - ] - - // print("πŸ‘Ύ \(command.joined(separator: " "))") - shell.execute(command.joined(separator: " ")) - } - - func diagnoseSdk( - oldAbiJsonFilePath: String, - newAbiJsonFilePath: String, - module: String - ) -> String { - - let command = [ - "xcrun --sdk iphoneos swift-api-digester -diagnose-sdk", - "-module \(module)", - "-input-paths \(oldAbiJsonFilePath)", - "-input-paths \(newAbiJsonFilePath)" - ] - - return shell.execute(command.joined(separator: " ")) - } - - private var iOSTarget: String { - "-sdk `\(Constants.simulatorSdkCommand)` -target \(Constants.deviceTarget)" - } -} diff --git a/Sources/Pipeline/Modules/ABIGenerator/ABIGenerator.swift b/Sources/Pipeline/Modules/ABIGenerator/ABIGenerator.swift deleted file mode 100644 index a39df1f..0000000 --- a/Sources/Pipeline/Modules/ABIGenerator/ABIGenerator.swift +++ /dev/null @@ -1,58 +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 ABIGenerator: ABIGenerating { - - private let shell: ShellHandling - private let xcodeTools: XcodeTools - private let packageFileHelper: SwiftPackageFileHelper - private let fileHandler: FileHandling - private let logger: Logging? - - init( - shell: ShellHandling = Shell(), - fileHandler: FileHandling = FileManager.default, - logger: Logging? - ) { - self.shell = shell - self.xcodeTools = XcodeTools(shell: shell, fileHandler: fileHandler) - self.packageFileHelper = .init(fileHandler: fileHandler, xcodeTools: xcodeTools) - self.fileHandler = fileHandler - self.logger = logger - } - - func generate( - for projectDirectory: URL, - scheme: String?, - description: String - ) throws -> [ABIGeneratorOutput] { - - let generator: ABIGenerating - - if scheme != nil { - generator = ProjectABIProvider( - shell: shell, - fileHandler: fileHandler, - logger: logger - ) - } else { - generator = PackageABIGenerator( - fileHandler: fileHandler, - xcodeTools: xcodeTools, - packageFileHelper: packageFileHelper, - logger: logger - ) - } - - return try generator.generate( - for: projectDirectory, - scheme: scheme, - description: description - ) - } -} diff --git a/Sources/Pipeline/Modules/ABIGenerator/PackageABIGenerator.swift b/Sources/Pipeline/Modules/ABIGenerator/PackageABIGenerator.swift deleted file mode 100644 index 5bbf6df..0000000 --- a/Sources/Pipeline/Modules/ABIGenerator/PackageABIGenerator.swift +++ /dev/null @@ -1,65 +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 PackageABIGenerator: ABIGenerating { - - let fileHandler: FileHandling - let xcodeTools: XcodeTools - let packageFileHelper: SwiftPackageFileHelper - let logger: Logging? - - func generate( - for projectDirectory: URL, - scheme: String?, - description: String - ) throws -> [ABIGeneratorOutput] { - - logger?.log("πŸ“‹ Generating ABI files for `\(description)`", from: String(describing: Self.self)) - - return try packageFileHelper.availableTargets( - at: projectDirectory.path(), - moduleType: .swiftTarget, - targetType: .library - ).map { target in - - let abiJsonFileUrl = try generateApiDump( - for: target, - projectDirectory: projectDirectory - ) - - return .init( - targetName: target, - abiJsonFileUrl: abiJsonFileUrl - ) - } - } -} - -private extension PackageABIGenerator { - - func generateApiDump( - for module: String, - projectDirectory: URL - ) throws -> URL { - - let abiJsonFileUrl = projectDirectory.appending(component: "\(module).abi.json") - logger?.debug("- `\(module).abi.json`", from: String(describing: Self.self)) - - xcodeTools.dumpSdk( - projectDirectoryPath: projectDirectory.path(), - module: module, - outputFilePath: abiJsonFileUrl.path() - ) - - if !fileHandler.fileExists(atPath: abiJsonFileUrl.path()) { - throw FileHandlerError.pathDoesNotExist(path: abiJsonFileUrl.path()) - } - - return abiJsonFileUrl - } -} diff --git a/Sources/Pipeline/Modules/ABIGenerator/ProjectABIProvider.swift b/Sources/Pipeline/Modules/ABIGenerator/ProjectABIProvider.swift deleted file mode 100644 index a964d38..0000000 --- a/Sources/Pipeline/Modules/ABIGenerator/ProjectABIProvider.swift +++ /dev/null @@ -1,54 +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 -import OSLog - -struct ProjectABIProvider: ABIGenerating { - - let shell: ShellHandling - let fileHandler: FileHandling - let logger: Logging? - - func generate( - for projectDirectory: URL, - scheme: String?, - 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 [] - } - - logger?.log("πŸ“‹ Locating ABI file for `\(scheme)` in `\(description)`", from: String(describing: Self.self)) - - let swiftModulePaths = shell.execute("cd '\(projectDirectory.path())'; 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 swiftModuleDirectory = projectDirectory.appending(path: swiftModulePath) - let swiftModuleDirectoryContent = try fileHandler.contentsOfDirectory(atPath: swiftModuleDirectory.path()) - guard let abiJsonFilePath = swiftModuleDirectoryContent.first(where: { - $0.hasSuffix(".abi.json") - }) else { - throw FileHandlerError.pathDoesNotExist(path: swiftModuleDirectory.appending(path: "[MODULE_NAME].abi.json").path()) - } - - logger?.debug("- `\(abiJsonFilePath)`", from: String(describing: Self.self)) - let abiJsonFileUrl = swiftModuleDirectory.appending(path: abiJsonFilePath) - return [.init(targetName: scheme, abiJsonFileUrl: abiJsonFileUrl)] - } -} diff --git a/Sources/Pipeline/Modules/ProjectBuilder.swift b/Sources/Pipeline/Modules/ProjectBuilder.swift deleted file mode 100644 index 0339da2..0000000 --- a/Sources/Pipeline/Modules/ProjectBuilder.swift +++ /dev/null @@ -1,203 +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 - ) - - 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, - isPackage: scheme == nil - ) - 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 35a3769..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: ChangeConsolidating - - init( - changeConsolidator: ChangeConsolidating = ChangeConsolidator() - ) { - 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 - ) -> [IndependentChange] { - - 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 = [IndependentChange]() - - 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: IndependentChange.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 - ) -> [IndependentChange] { - - var changes: [IndependentChange] = [ - .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 { - printedName == otherElement.printedName && - declKind == otherElement.declKind && - parentPath == otherElement.parentPath - } -} 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 deleted file mode 100644 index 9c483ed..0000000 --- a/Sources/Pipeline/Pipeline+Protocols.swift +++ /dev/null @@ -1,64 +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 - -protocol ProjectBuilding { - func build(source: ProjectSource, scheme: String?) async throws -> URL -} - -struct ABIGeneratorOutput: Equatable { - let targetName: String - let abiJsonFileUrl: URL -} - -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 OutputGenerating { - func generate( - from changesPerTarget: [String: [Change]], - allTargets: [String], - oldSource: ProjectSource, - newSource: ProjectSource, - warnings: [String] - ) throws -> String -} - -struct ProjectAnalyzerResult { - let changes: [Change] - let warnings: [String] -} - -protocol ProjectAnalyzing { - /// Analyzes whether or not the available libraries changed between the old and new version - func analyze( - oldProjectUrl: URL, - newProjectUrl: URL - ) throws -> ProjectAnalyzerResult -} - -enum LogLevel { - case quiet - case `default` - case debug -} - -protocol Logging { - - init(logLevel: LogLevel) - func log(_ message: String, from subsystem: String) - func debug(_ message: String, from subsystem: String) -} diff --git a/Sources/Pipeline/Pipeline.swift b/Sources/Pipeline/Pipeline.swift deleted file mode 100644 index a074c6d..0000000 --- a/Sources/Pipeline/Pipeline.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 Pipeline { - - 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 Pipeline { - - 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/Pipeline/PipelineError.swift b/Sources/Pipeline/PipelineError.swift deleted file mode 100644 index 3994a6e..0000000 --- a/Sources/Pipeline/PipelineError.swift +++ /dev/null @@ -1,17 +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 - -enum PipelineError: LocalizedError { - case noTargetFound - - var errorDescription: String? { - switch self { - case .noTargetFound: "No targets found to analyze" - } - } -} diff --git a/Sources/PublicModules/.DS_Store b/Sources/PublicModules/.DS_Store new file mode 100644 index 0000000..7dc9b2e Binary files /dev/null and b/Sources/PublicModules/.DS_Store differ diff --git a/Sources/PublicModules/PADOutputGenerator/Documentation.docc/PADOutputGenerator.md b/Sources/PublicModules/PADOutputGenerator/Documentation.docc/PADOutputGenerator.md new file mode 100644 index 0000000..eea682e --- /dev/null +++ b/Sources/PublicModules/PADOutputGenerator/Documentation.docc/PADOutputGenerator.md @@ -0,0 +1,59 @@ +# ``PADOutputGenerator`` + +Allows generation of human readable output from the provided information + +## Usage + +```swift +// Generated in previous steps +let warnings: [String] = ... +let changes: [String: [Change]] = ... +let oldVersionName: String = ... +let newVersionName: String = ... +let allTargets: [String] = ... +let swiftInterfaceFiles: [SwiftInterfaceFile] = ... + +let outputGenerator: any OutputGenerating = MarkdownOutputGenerator() + +let markdownOutput: String = try outputGenerator.generate( + from: changes, + allTargets: allTargets, + oldVersionName: oldVersionName, + newVersionName: newVersionName, + warnings: warnings +) +``` + +--- + +Example output for ``PADOutputGenerator/MarkdownOutputGenerator`` + +## πŸ‘€ 3 public changes detected +_Comparing `old` to `new`_ + +--- +## SomeModule +#### ❇️ Added +```javascript +public protocol NewProtocol { + var property: String { get } +} +``` +#### πŸ”€ Changed +```javascript +// From +open class SomeClass : SomeProtocol, OldProtocol + +// To +open class SomeClass : SomeProtocol, NewProtocol + +/** +Changes: +- Added `NewProtocol` conformance +- Removed `OldProtocol` conformance +*/ +``` +#### πŸ˜Άβ€πŸŒ«οΈ Removed +```javascript +public protocol OldProtocol +``` diff --git a/Sources/Pipeline/Modules/MarkdownOutputGenerator.swift b/Sources/PublicModules/PADOutputGenerator/MarkdownOutputGenerator.swift similarity index 85% rename from Sources/Pipeline/Modules/MarkdownOutputGenerator.swift rename to Sources/PublicModules/PADOutputGenerator/MarkdownOutputGenerator.swift index 9f77c00..c7798a8 100644 --- a/Sources/Pipeline/Modules/MarkdownOutputGenerator.swift +++ b/Sources/PublicModules/PADOutputGenerator/MarkdownOutputGenerator.swift @@ -5,16 +5,19 @@ // import Foundation +import PADCore /// Allows generation of human readable output from the provided information -struct MarkdownOutputGenerator: OutputGenerating { +public struct MarkdownOutputGenerator: OutputGenerating { + + public init() {} /// Generates human readable output from the provided information - func generate( + public func generate( from changesPerTarget: [String: [Change]], allTargets: [String], - oldSource: ProjectSource, - newSource: ProjectSource, + oldVersionName: String, + newVersionName: String, warnings: [String] ) -> String { @@ -23,7 +26,7 @@ struct MarkdownOutputGenerator: OutputGenerating { var lines = [ Self.title(changesPerTarget: changesPerTarget), - Self.repoInfo(oldSource: oldSource, newSource: newSource), + Self.repoInfo(oldVersionName: oldVersionName, newVersionName: newVersionName), separator ] @@ -57,8 +60,8 @@ private extension MarkdownOutputGenerator { return "# πŸ‘€ \(totalChangeCount) public \(totalChangeCount == 1 ? "change" : "changes") detected" } - static func repoInfo(oldSource: ProjectSource, newSource: ProjectSource) -> String { - "_Comparing `\(newSource.description)` to `\(oldSource.description)`_" + static func repoInfo(oldVersionName: String, newVersionName: String) -> String { + "_Comparing `\(newVersionName)` to `\(oldVersionName)`_" } static func analyzedModulesInfo(allTargets: [String]) -> String { @@ -82,7 +85,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 @@ -153,3 +156,14 @@ private extension MarkdownOutputGenerator { } } } + +private extension [String: [Change]] { + + var totalChangeCount: Int { + var totalChangeCount = 0 + keys.forEach { targetName in + totalChangeCount += self[targetName]?.count ?? 0 + } + return totalChangeCount + } +} diff --git a/Sources/PublicModules/PADOutputGenerator/OutputGenerating.swift b/Sources/PublicModules/PADOutputGenerator/OutputGenerating.swift new file mode 100644 index 0000000..8c54003 --- /dev/null +++ b/Sources/PublicModules/PADOutputGenerator/OutputGenerating.swift @@ -0,0 +1,30 @@ +// +// 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 +import PADCore + +/// Interface definition for an output generator +public protocol OutputGenerating { + + associatedtype OutputType + + /// Generates an output from input parameters + /// - Parameters: + /// - changesPerTarget: A list of changes per target/module + /// - allTargets: A list of all targets/modules that were analysed in previous steps + /// - oldVersionName: The name of the old/reference version + /// - newVersionName: The name of the new/updated version + /// - warnings: A list of warnings produced in previous steps + /// - Returns: An output of type ``OutputType`` + func generate( + from changesPerTarget: [String: [Change]], + allTargets: [String], + oldVersionName: String, + newVersionName: String, + warnings: [String] + ) throws -> OutputType +} diff --git a/Sources/PublicModules/PADPackageFileAnalyzer/Documentation.docc/PADPackageFileAnalyzer.md b/Sources/PublicModules/PADPackageFileAnalyzer/Documentation.docc/PADPackageFileAnalyzer.md new file mode 100644 index 0000000..42efe41 --- /dev/null +++ b/Sources/PublicModules/PADPackageFileAnalyzer/Documentation.docc/PADPackageFileAnalyzer.md @@ -0,0 +1,20 @@ +# ``PADPackageFileAnalyzer`` + +The ``PADPackageFileAnalyzer/SwiftPackageFileAnalyzer`` allows analyzing of 2 versions of a `Package.swift` file. + +It lists all changes to products, dependencies and targets + surfaces any warnings that the new version of the `Package.swift` file might have. +Under the hood it uses `swift package describe --type json` to get a description of the `Package.swift` file + +## Usage + +```swift +let swiftPackageFileAnalyzer = SwiftPackageFileAnalyzer() + +let swiftPackageAnalysis = try swiftPackageFileAnalyzer.analyze( + oldProjectUrl: projectDirectories.old, + newProjectUrl: projectDirectories.new +) + +let warnings: [String] = swiftPackageAnalysis.warnings +let changes: [Change] = swiftPackageAnalysis.changes +``` diff --git a/Sources/Pipeline/Modules/SwiftPackageFileAnalyzer.swift b/Sources/PublicModules/PADPackageFileAnalyzer/SwiftPackageFileAnalyzer.swift similarity index 88% rename from Sources/Pipeline/Modules/SwiftPackageFileAnalyzer.swift rename to Sources/PublicModules/PADPackageFileAnalyzer/SwiftPackageFileAnalyzer.swift index f403eb5..020bd86 100644 --- a/Sources/Pipeline/Modules/SwiftPackageFileAnalyzer.swift +++ b/Sources/PublicModules/PADPackageFileAnalyzer/SwiftPackageFileAnalyzer.swift @@ -6,27 +6,49 @@ import Foundation -struct SwiftPackageFileAnalyzer: ProjectAnalyzing { +import PADCore +import PADLogging + +import FileHandlingModule +import ShellModule +import SwiftPackageFileHelperModule + +/// Analyzes 2 versions of a `Package.swift` +public struct SwiftPackageFileAnalyzer: SwiftPackageFileAnalyzing { - let fileHandler: FileHandling - let xcodeTools: XcodeTools + private let fileHandler: any FileHandling + private let shell: any ShellHandling + private let logger: (any Logging)? private enum Constants { static let packageFileName = "Package.swift" static func packageFileName(child: String) -> String { - "\(packageFileName) / \(child)" + ".\(child)" } } - init( + public init(logger: (any Logging)? = nil) { + self.init( + fileHandler: FileManager.default, + shell: Shell(), + logger: logger + ) + } + + package init( fileHandler: FileHandling = FileManager.default, - xcodeTools: XcodeTools = XcodeTools() + shell: ShellHandling = Shell(), + logger: (any Logging)? = nil ) { self.fileHandler = fileHandler - self.xcodeTools = xcodeTools + self.logger = logger + self.shell = shell } - func analyze(oldProjectUrl: URL, newProjectUrl: URL) throws -> ProjectAnalyzerResult { + public func analyze( + oldProjectUrl: URL, + newProjectUrl: URL + ) throws -> SwiftPackageFileAnalyzingResult { let oldProjectPath = oldProjectUrl.path() let newProjectPath = newProjectUrl.path() @@ -37,7 +59,8 @@ struct SwiftPackageFileAnalyzer: ProjectAnalyzing { if fileHandler.fileExists(atPath: oldPackagePath), fileHandler.fileExists(atPath: newPackagePath) { let packageHelper = SwiftPackageFileHelper( fileHandler: fileHandler, - xcodeTools: xcodeTools + shell: shell, + logger: logger ) return try analyze( @@ -52,10 +75,11 @@ struct SwiftPackageFileAnalyzer: ProjectAnalyzing { private extension SwiftPackageFileAnalyzer { + /// Compiles all changes between 2 `SwiftPackageDescription`s private func analyze( old: SwiftPackageDescription, new: SwiftPackageDescription - ) throws -> ProjectAnalyzerResult { + ) throws -> SwiftPackageFileAnalyzingResult { guard old != new else { return .init(changes: [], warnings: []) } @@ -86,14 +110,14 @@ private extension SwiftPackageFileAnalyzer { if let old, new == nil { return [.init( changeType: .removal(description: "\(keyName): \"\(old)\""), - parentName: Constants.packageFileName + parentPath: Constants.packageFileName )] } if let new, old == nil { return [.init( changeType: .addition(description: "\(keyName): \"\(new)\""), - parentName: Constants.packageFileName + parentPath: Constants.packageFileName )] } @@ -104,7 +128,7 @@ private extension SwiftPackageFileAnalyzer { oldDescription: "\(keyName): \"\(old)\"", newDescription: "\(keyName): \"\(new)\"" ), - parentName: Constants.packageFileName + parentPath: Constants.packageFileName )] } @@ -123,7 +147,7 @@ private extension SwiftPackageFileAnalyzer { oldDescription: "\(keyName): \"\(old)\"", newDescription: "\(keyName): \"\(new)\"" ), - parentName: Constants.packageFileName + parentPath: Constants.packageFileName )] } @@ -171,7 +195,7 @@ private extension SwiftPackageFileAnalyzer { oldDescription: "platforms: [\(oldPlatformsString)]", newDescription: "platforms: [\(newPlatformsString)]" ), - parentName: Constants.packageFileName, + parentPath: Constants.packageFileName, listOfChanges: listOfChanges )] } @@ -197,7 +221,7 @@ private extension SwiftPackageFileAnalyzer { guard let addedProduct = new.first(where: { $0.name == addition }) else { return nil } return .init( changeType: .addition(description: addedProduct.description), - parentName: Constants.packageFileName(child: "products") + parentPath: Constants.packageFileName(child: "products") ) } @@ -217,7 +241,7 @@ private extension SwiftPackageFileAnalyzer { guard let removedProduct = old.first(where: { $0.name == removal }) else { return nil } return .init( changeType: .removal(description: removedProduct.description), - parentName: Constants.packageFileName(child: "products") + parentPath: Constants.packageFileName(child: "products") ) } @@ -245,7 +269,7 @@ private extension SwiftPackageFileAnalyzer { oldDescription: oldProduct.description, newDescription: newProduct.description ), - parentName: Constants.packageFileName(child: "products"), + parentPath: Constants.packageFileName(child: "products"), listOfChanges: listOfChanges )] } @@ -271,7 +295,7 @@ private extension SwiftPackageFileAnalyzer { guard let addedTarget = new.first(where: { $0.name == addition }) else { return nil } return .init( changeType: .addition(description: addedTarget.description), - parentName: Constants.packageFileName(child: "targets") + parentPath: Constants.packageFileName(child: "targets") ) } @@ -291,7 +315,7 @@ private extension SwiftPackageFileAnalyzer { guard let removedTarget = old.first(where: { $0.name == removal }) else { return nil } return .init( changeType: .removal(description: removedTarget.description), - parentName: Constants.packageFileName(child: "targets") + parentPath: Constants.packageFileName(child: "targets") ) } @@ -340,7 +364,7 @@ private extension SwiftPackageFileAnalyzer { oldDescription: oldTarget.description, newDescription: newTarget.description ), - parentName: Constants.packageFileName(child: "targets"), + parentPath: Constants.packageFileName(child: "targets"), listOfChanges: listOfChanges )] @@ -367,7 +391,7 @@ private extension SwiftPackageFileAnalyzer { guard let addedDependency = new.first(where: { $0.identity == addition }) else { return nil } return .init( changeType: .addition(description: addedDependency.description), - parentName: Constants.packageFileName(child: "dependencies") + parentPath: Constants.packageFileName(child: "dependencies") ) } @@ -387,7 +411,7 @@ private extension SwiftPackageFileAnalyzer { guard let removedDependency = old.first(where: { $0.identity == addition }) else { return nil } return .init( changeType: .removal(description: removedDependency.description), - parentName: Constants.packageFileName(child: "dependencies") + parentPath: Constants.packageFileName(child: "dependencies") ) } @@ -405,7 +429,7 @@ private extension SwiftPackageFileAnalyzer { oldDescription: oldDependency.description, newDescription: newDependency.description ), - parentName: Constants.packageFileName(child: "dependencies"), + parentPath: Constants.packageFileName(child: "dependencies"), listOfChanges: [] // TODO: Improvement: Provide a `listOfChanges` )] } @@ -423,7 +447,7 @@ private extension SwiftPackageFileAnalyzer { oldDescription: "// swift-tools-version: \(old)", newDescription: "// swift-tools-version: \(new)" ), - parentName: Constants.packageFileName + parentPath: Constants.packageFileName )] } } diff --git a/Sources/PublicModules/PADPackageFileAnalyzer/SwiftPackageFileAnalyzing.swift b/Sources/PublicModules/PADPackageFileAnalyzer/SwiftPackageFileAnalyzing.swift new file mode 100644 index 0000000..1e653c8 --- /dev/null +++ b/Sources/PublicModules/PADPackageFileAnalyzer/SwiftPackageFileAnalyzing.swift @@ -0,0 +1,21 @@ +import Foundation +import PADCore + +public struct SwiftPackageFileAnalyzingResult { + /// The changes between 2 `Package.swift` files + public let changes: [Change] + /// Any warnings that occured while inspecting the `Package.swift` file + public let warnings: [String] +} + +protocol SwiftPackageFileAnalyzing { + /// Analyzes 2 versions of a `Package.swift` and returns a `SwiftPackageFileAnalyzingResult` containing the findings + /// - Parameters: + /// - oldProjectUrl: The directory url to the reference project + /// - newProjectUrl: The directory url to the updated project + /// - Returns: A `SwiftPackageFileAnalyzingResult` containing the findings + func analyze( + oldProjectUrl: URL, + newProjectUrl: URL + ) throws -> SwiftPackageFileAnalyzingResult +} diff --git a/Sources/PublicModules/PADProjectBuilder/Documentation.docc/PADProjectBuilder.md b/Sources/PublicModules/PADProjectBuilder/Documentation.docc/PADProjectBuilder.md new file mode 100644 index 0000000..4d1faf3 --- /dev/null +++ b/Sources/PublicModules/PADProjectBuilder/Documentation.docc/PADProjectBuilder.md @@ -0,0 +1,20 @@ +# ``PADProjectBuilder`` + +The ``PADProjectBuilder/ProjectBuilder`` builds the old & new version of a project and outputs a list of ``PADCore/SwiftInterfaceFile``s as well as changes that happened to the project files including any warnings if applicable. + +## Usage + +```swift +let oldSource: ProjectSource = try .from("develop~https://github.com/Adyen/adyen-ios.git") +let newSource: ProjectSource = try .from("some/local/path") + +let projectBuilder = ProjectBuilder( + projectType: .swiftPackage, // .xcodeProject("scheme_name") + swiftInterfaceType: .public // .private +) + +let projectBuilderResult: ProjectBuilder.Result = try await projectBuilder.build( + oldSource: oldSource, + newSource: newSource +) +``` diff --git a/Sources/PublicModules/PADProjectBuilder/PADProjectBuilder.swift b/Sources/PublicModules/PADProjectBuilder/PADProjectBuilder.swift new file mode 100644 index 0000000..2b081a2 --- /dev/null +++ b/Sources/PublicModules/PADProjectBuilder/PADProjectBuilder.swift @@ -0,0 +1,111 @@ +import Foundation + +import PADLogging +import PADCore + +import ShellModule +import FileHandlingModule + +/// The ``PADProjectBuilder/ProjectBuilder`` builds the old & new project and outputs a list +/// of ``PADCore/SwiftInterfaceFile``s as well as changes that happened to the +/// project files including any warnings if applicable. +/// +/// Following tasks are performed: +/// - Fetch remote projects (if applicable) +/// - Archiving projects +/// - Inspecting `Package.swift` for any changes between versions (if applicable / if ``ProjectType/swiftPackage``) +/// - Returning a ``PADProjectBuilder/ProjectBuilder/Result`` containing package file changes, warnings + the found ``PADCore/SwiftInterfaceFile``s +public struct ProjectBuilder { + + /// The result returned by the build function of ``PADProjectBuilder/ProjectBuilder`` + public struct Result { + /// The `.swiftinterface` file references found + public let swiftInterfaceFiles: [SwiftInterfaceFile] + /// The project directories for the setup projects + public let projectDirectories: (old: URL, new: URL) + } + + private let projectType: ProjectType + private let swiftInterfaceType: SwiftInterfaceType + private let fileHandler: any FileHandling + private let shell: any ShellHandling + private let logger: (any Logging)? + + public init( + projectType: ProjectType, + swiftInterfaceType: SwiftInterfaceType, + logger: (any Logging)? = nil + ) { + self.init( + projectType: projectType, + swiftInterfaceType: swiftInterfaceType, + fileHandler: FileManager.default, + shell: Shell(), + logger: logger + ) + } + + init( + projectType: ProjectType, + swiftInterfaceType: SwiftInterfaceType, + fileHandler: any FileHandling = FileManager.default, + shell: any ShellHandling = Shell(), + logger: (any Logging)? + ) { + self.projectType = projectType + self.swiftInterfaceType = swiftInterfaceType + self.fileHandler = fileHandler + self.shell = shell + self.logger = logger + } + + public func build( + oldSource: ProjectSource, + newSource: ProjectSource + ) async throws -> Result { + + let oldVersionName = oldSource.description + let newVersionName = newSource.description + + logger?.log("Comparing `\(newVersionName)` to `\(oldVersionName)`", from: "Main") + + let currentDirectory = fileHandler.currentDirectoryPath + let workingDirectoryPath = currentDirectory.appending("/tmp-public-api-diff") + + // MARK: - Setup projects + + let projectSetupHelper = ProjectSetupHelper( + workingDirectoryPath: workingDirectoryPath, + shell: shell, + fileHandler: fileHandler, + logger: logger + ) + + let projectDirectories = try await projectSetupHelper.setupProjects( + oldSource: oldSource, + newSource: newSource, + projectType: projectType + ) + + // MARK: - Produce .swiftinterface files + + let producer = SwiftInterfaceProducer( + workingDirectoryPath: workingDirectoryPath, + projectType: projectType, + swiftInterfaceType: swiftInterfaceType, + fileHandler: fileHandler, + shell: shell, + logger: logger + ) + + let swiftInterfaceFiles = try await producer.produceInterfaceFiles( + oldProjectDirectory: projectDirectories.old, + newProjectDirectory: projectDirectories.new + ) + + return .init( + swiftInterfaceFiles: swiftInterfaceFiles, + projectDirectories: projectDirectories + ) + } +} diff --git a/Sources/PublicModules/PADProjectBuilder/PADProjectSource+Error.swift b/Sources/PublicModules/PADProjectBuilder/PADProjectSource+Error.swift new file mode 100644 index 0000000..b724574 --- /dev/null +++ b/Sources/PublicModules/PADProjectBuilder/PADProjectSource+Error.swift @@ -0,0 +1,22 @@ +// +// File.swift +// +// +// Created by Alexander Guretzki on 11/10/2024. +// + +import Foundation + +internal extension ProjectSource { + enum Error: LocalizedError, Equatable { + case invalidSourceValue(value: String) + + var errorDescription: String? { + switch self { + case let .invalidSourceValue(value): + "Invalid source parameter `\(value)`. It needs to either be a local file path or a repository in the format `[BRANCH_OR_TAG]\(ProjectSource.gitSourceSeparator)[REPOSITORY_URL]" + } + } + } +} + diff --git a/Sources/PublicModules/PADProjectBuilder/PADProjectSource.swift b/Sources/PublicModules/PADProjectBuilder/PADProjectSource.swift new file mode 100644 index 0000000..1f05dd2 --- /dev/null +++ b/Sources/PublicModules/PADProjectBuilder/PADProjectSource.swift @@ -0,0 +1,51 @@ +// +// 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 +import FileHandlingModule + +/// The source type of the project (local/remote) +public enum ProjectSource: Equatable, CustomStringConvertible { + + /// The separator used to join branch & repository + static var gitSourceSeparator: String { "~" } + + /// Representing a local `path` + case local(path: String) + /// Representing a `branch` of a **git** `repository` + case git(branch: String, repository: String) + + /// Creates a ``ProjectSource`` from a rawValue + /// - Parameters: + /// - rawValue: The rawValue presentation of a ``ProjectSource`` + /// - Returns: A valid ``ProjectSource`` + /// - Throws: An error if the `rawValue` does not match a ``ProjectSource`` representation + public static func from(_ rawValue: String) throws -> Self { + try from(rawValue, fileHandler: FileManager.default) + } + + package static func from(_ rawValue: String, fileHandler: FileHandling) throws -> Self { + if fileHandler.fileExists(atPath: rawValue) { + return .local(path: rawValue) + } + + let remoteComponents = rawValue.components(separatedBy: gitSourceSeparator) + if remoteComponents.count == 2, let branch = remoteComponents.first, let repository = remoteComponents.last, URL(string: repository) != nil { + return .git(branch: branch, repository: repository) + } + + throw Error.invalidSourceValue(value: rawValue) + } + + public var description: String { + switch self { + case let .local(path): + return path + case let .git(branch, repository): + return "\(repository) @ \(branch)" + } + } +} diff --git a/Sources/PublicModules/PADProjectBuilder/PADProjectType.swift b/Sources/PublicModules/PADProjectBuilder/PADProjectType.swift new file mode 100644 index 0000000..44cd3c9 --- /dev/null +++ b/Sources/PublicModules/PADProjectBuilder/PADProjectType.swift @@ -0,0 +1,13 @@ +import Foundation + +/// The type of project to build +public enum ProjectType { + + /// The project is a `Package.swift` + /// When using this project type all targets get built + case swiftPackage + + /// The project is an Xcode project/workspace + /// When using this project type the specified scheme get built + case xcodeProject(scheme: String) +} diff --git a/Sources/PublicModules/PADProjectBuilder/PADSwiftInterfaceType.swift b/Sources/PublicModules/PADProjectBuilder/PADSwiftInterfaceType.swift new file mode 100644 index 0000000..918cfc8 --- /dev/null +++ b/Sources/PublicModules/PADProjectBuilder/PADSwiftInterfaceType.swift @@ -0,0 +1,14 @@ +import Foundation + +/// The type of the .swiftinterface to parse/generate +public enum SwiftInterfaceType { + case `private` + case `public` + + var name: String { + switch self { + case .private: "private" + case .public: "public" + } + } +} diff --git a/Sources/Helpers/Git.swift b/Sources/PublicModules/PADProjectBuilder/ProjectSetup/Git.swift similarity index 88% rename from Sources/Helpers/Git.swift rename to Sources/PublicModules/PADProjectBuilder/ProjectSetup/Git.swift index 904da49..76424dc 100644 --- a/Sources/Helpers/Git.swift +++ b/Sources/PublicModules/PADProjectBuilder/ProjectSetup/Git.swift @@ -1,12 +1,12 @@ -// -// 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 -enum GitError: LocalizedError, Equatable { +import PADCore +import PADLogging + +import FileHandlingModule +import ShellModule + +internal enum GitError: LocalizedError, Equatable { case couldNotClone(branchOrTag: String, repository: String) var errorDescription: String? { @@ -17,7 +17,7 @@ enum GitError: LocalizedError, Equatable { } } -struct Git { +internal struct Git { private let shell: ShellHandling private let fileHandler: FileHandling diff --git a/Sources/PublicModules/PADProjectBuilder/ProjectSetup/ProjectSetupHelper.swift b/Sources/PublicModules/PADProjectBuilder/ProjectSetup/ProjectSetupHelper.swift new file mode 100644 index 0000000..4c6435a --- /dev/null +++ b/Sources/PublicModules/PADProjectBuilder/ProjectSetup/ProjectSetupHelper.swift @@ -0,0 +1,100 @@ +import Foundation + +import PADCore +import PADLogging + +import ShellModule +import FileHandlingModule + +/// Helps setting up the project by: +/// - Copying project files into a working directory (and skipping unwanted files) +/// - Fetching a remote project (if applicable) +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 -> URL { + try await Task { + let checkoutPath = workingDirectoryPath + "\(randomStringGenerator.generateRandomString())" + switch projectSource { + case .local(let path): + shell.execute("cp -a '\(path)' '\(checkoutPath)'") + case .git(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 URL(filePath: 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)") + } + } +} + +extension ProjectSetupHelper { + + /// Convenience method that calls into `setup(_:projectType:)` for the old and new source + func setupProjects( + oldSource: ProjectSource, + newSource: ProjectSource, + projectType: ProjectType + ) async throws -> (old: URL, new: URL) { + let projectSetupHelper = ProjectSetupHelper( + workingDirectoryPath: workingDirectoryPath, + logger: logger + ) + + // async let to make them perform in parallel + async let newProjectDirectoryPath = try projectSetupHelper.setup(newSource, projectType: projectType) + async let oldProjectDirectoryPath = try projectSetupHelper.setup(oldSource, projectType: projectType) + + return try await (oldProjectDirectoryPath, newProjectDirectoryPath) + } +} + +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/PublicModules/PADProjectBuilder/ProjectSetup/ProjectSetupHelping.swift b/Sources/PublicModules/PADProjectBuilder/ProjectSetup/ProjectSetupHelping.swift new file mode 100644 index 0000000..0c0f0ce --- /dev/null +++ b/Sources/PublicModules/PADProjectBuilder/ProjectSetup/ProjectSetupHelping.swift @@ -0,0 +1,6 @@ +import Foundation +import PADCore + +protocol ProjectSetupHelping { + func setup(_ projectSource: ProjectSource, projectType: ProjectType) async throws -> URL +} diff --git a/Sources/Helpers/RandomStringGenerating.swift b/Sources/PublicModules/PADProjectBuilder/ProjectSetup/RandomStringGenerating.swift similarity index 57% rename from Sources/Helpers/RandomStringGenerating.swift rename to Sources/PublicModules/PADProjectBuilder/ProjectSetup/RandomStringGenerating.swift index 6123b18..81dc358 100644 --- a/Sources/Helpers/RandomStringGenerating.swift +++ b/Sources/PublicModules/PADProjectBuilder/ProjectSetup/RandomStringGenerating.swift @@ -6,14 +6,16 @@ import Foundation -protocol RandomStringGenerating { +package protocol RandomStringGenerating { func generateRandomString() -> String } -struct RandomStringGenerator: RandomStringGenerating { +package struct RandomStringGenerator: RandomStringGenerating { - func generateRandomString() -> String { + package init() {} + + package func generateRandomString() -> String { UUID().uuidString } } diff --git a/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/SwiftInterfaceFileLocator.swift b/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/SwiftInterfaceFileLocator.swift new file mode 100644 index 0000000..04bbc57 --- /dev/null +++ b/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/SwiftInterfaceFileLocator.swift @@ -0,0 +1,66 @@ +import Foundation + +import FileHandlingModule +import ShellModule +import PADLogging + +/// A helper to locate `.swiftinterface` files +struct SwiftInterfaceFileLocator { + + let fileHandler: any FileHandling + let shell: any ShellHandling + let logger: (any Logging)? + + init( + fileHandler: any FileHandling = FileManager.default, + shell: any ShellHandling = Shell(), + logger: (any Logging)? + ) { + self.fileHandler = fileHandler + self.shell = shell + self.logger = logger + } + + + /// Tries to locate a `.swiftinterface` files in the derivedData folder for a specific scheme + /// - Parameters: + /// - scheme: The scheme to find the `.swiftinterface` file for + /// - derivedDataPath: The path to the derived data directory (e.g. .../.build) + /// - type: The swift interface type (.public, .private) to look for + /// - Returns: The file url to the found `.swiftinterface` + /// - Throws: An error if no `.swiftinterface` file can be found for the given scheme + derived data path + 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 = swiftModulePathsForScheme.first?.path() else { + throw FileHandlerError.pathDoesNotExist(path: "find . -type d -name '\(schemeSwiftModuleName)'") + } + + 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") } + } + + guard let swiftInterfacePath = swiftInterfacePaths.first else { + switch type { + case .private: + throw FileHandlerError.pathDoesNotExist(path: "'\(completeSwiftModulePath)/\(scheme).private.swiftinterface'") + case .public: + throw FileHandlerError.pathDoesNotExist(path: "'\(completeSwiftModulePath)/\(scheme).swiftinterface'") + } + } + + return URL(filePath: "\(completeSwiftModulePath)/\(swiftInterfacePath)") + } +} diff --git a/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/SwiftInterfaceProducer+Error.swift b/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/SwiftInterfaceProducer+Error.swift new file mode 100644 index 0000000..fa9a066 --- /dev/null +++ b/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/SwiftInterfaceProducer+Error.swift @@ -0,0 +1,19 @@ +// +// 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 SwiftInterfaceProducer { + enum Error: LocalizedError { + case noTargetFound + + var errorDescription: String? { + switch self { + case .noTargetFound: "No targets found to analyze" + } + } + } +} diff --git a/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/SwiftInterfaceProducer.swift b/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/SwiftInterfaceProducer.swift new file mode 100644 index 0000000..ff8c8e4 --- /dev/null +++ b/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/SwiftInterfaceProducer.swift @@ -0,0 +1,171 @@ +import Foundation + +import PADLogging +import PADCore + +import FileHandlingModule +import ShellModule +import SwiftPackageFileHelperModule + +/// Allows building of the old & new project and returns the `.swiftinterface` files +struct SwiftInterfaceProducer { + + private typealias ProjectPreparationResult = (archiveScheme: String, schemesToCompare: [String]) + private typealias DerivedDataPaths = (new: String, old: String) + + let workingDirectoryPath: String + let projectType: ProjectType + let swiftInterfaceType: SwiftInterfaceType + let fileHandler: any FileHandling + let shell: any ShellHandling + let logger: (any Logging)? + + init( + workingDirectoryPath: String, + projectType: ProjectType, + swiftInterfaceType: SwiftInterfaceType, + fileHandler: any FileHandling, + shell: any ShellHandling, + logger: (any Logging)? + ) { + self.workingDirectoryPath = workingDirectoryPath + self.projectType = projectType + self.swiftInterfaceType = swiftInterfaceType + self.fileHandler = fileHandler + self.shell = shell + self.logger = logger + } + + /// Builds the projects and returns the `.swiftinterface` files + func produceInterfaceFiles( + oldProjectDirectory: URL, + newProjectDirectory: URL + ) async throws -> [SwiftInterfaceFile] { + + let newProjectDirectoryPath = newProjectDirectory.path() + let oldProjectDirectoryPath = oldProjectDirectory.path() + + let projectPreparationResult = try prepareProjectsForArchiving( + newProjectDirectoryPath: newProjectDirectoryPath, + oldProjectDirectoryPath: oldProjectDirectoryPath + ) + + let derivedDataPaths = try await archiveProjects( + newProjectDirectoryPath: newProjectDirectoryPath, + oldProjectDirectoryPath: oldProjectDirectoryPath, + scheme: projectPreparationResult.archiveScheme + ) + + return try locateInterfaceFiles( + newDerivedDataPath: derivedDataPaths.new, + oldDerivedDataPath: derivedDataPaths.old, + schemes: projectPreparationResult.schemesToCompare + ) + } +} + +extension SwiftInterfaceProducer { + + /// Prepares the projects for archiving considering the project type + /// + /// - .swiftPackage + /// - Adds a library `_AllTargets` that contains all targets found inside targets list of the Package.swift + /// + /// - .xcodeProject: + /// - Nothing specific + /// + /// - Returns: `ProjectPreparationResult` containing the scheme to archive and sub-schemes that are included + private func prepareProjectsForArchiving( + newProjectDirectoryPath: String, + oldProjectDirectoryPath: String + ) throws -> ProjectPreparationResult { + let archiveScheme: String + let schemesToCompare: [String] + + switch projectType { + case .swiftPackage: + archiveScheme = "_AllTargets" + let packageFileHelper = SwiftPackageFileHelper(fileHandler: fileHandler, shell: shell, logger: logger) + 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() + + if schemesToCompare.isEmpty { + throw Error.noTargetFound + } + + case let .xcodeProject(scheme): + archiveScheme = scheme + schemesToCompare = [scheme] + } + + return (archiveScheme, schemesToCompare) + } + + /// Archives the projects to produce `.swiftinterface` files + /// - Parameters: + /// - newProjectDirectoryPath: The path to the "new" project directory + /// - oldProjectDirectoryPath: The path to the "old" project directory + /// - scheme: The scheme to archive + /// - Returns: The old and new derived data path + private func archiveProjects( + newProjectDirectoryPath: String, + oldProjectDirectoryPath: String, + scheme: String + ) async throws -> DerivedDataPaths { // TODO: Typed return type + + // We don't run them in parallel to not conflict with resolving dependencies concurrently + + let xcodeTools = XcodeTools( + shell: shell, + fileHandler: fileHandler, + logger: logger + ) + + let newDerivedDataPath = try await xcodeTools.archive( + projectDirectoryPath: newProjectDirectoryPath, + scheme: scheme, + projectType: projectType + ) + let oldDerivedDataPath = try await xcodeTools.archive( + projectDirectoryPath: oldProjectDirectoryPath, + scheme: scheme, + projectType: projectType + ) + + return (newDerivedDataPath, oldDerivedDataPath) + } + + + /// Locates the `.swiftinterface` files for the provided schemes within the derived data directories + /// - Parameters: + /// - newDerivedDataPath: The "new" derived data directory path + /// - oldDerivedDataPath: The "old" derived data directory path + /// - schemesToCompare: The schemes/modules to find the `.swiftinterface` files for + /// - Returns: A list of ``SwiftInterfaceFile``s + private func locateInterfaceFiles( + newDerivedDataPath: String, + oldDerivedDataPath: String, + schemes schemesToCompare: [String] + ) throws -> [SwiftInterfaceFile] { + logger?.log("πŸ”Ž Locating interface files for \(schemesToCompare.joined(separator: ", "))", from: String(describing: Self.self)) + + let interfaceFileLocator = SwiftInterfaceFileLocator(fileHandler: fileHandler, shell: shell, 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?.debug("πŸ‘» \(error.localizedDescription)", from: String(describing: Self.self)) + return nil + } + } + } +} diff --git a/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/XcodeTools.swift b/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/XcodeTools.swift new file mode 100644 index 0000000..ec404b4 --- /dev/null +++ b/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/XcodeTools.swift @@ -0,0 +1,96 @@ +// +// 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 + +import PADCore +import ShellModule +import FileHandlingModule +import PADLogging + +struct XcodeToolsError: LocalizedError, CustomDebugStringConvertible { + var errorDescription: String + var underlyingError: String + + var debugDescription: String { errorDescription } +} + +/// A helper that provides tools to build a project +struct XcodeTools { + + internal enum Constants { + static let derivedDataPath: String = ".build" + static let simulatorSdkCommand = "xcrun --sdk iphonesimulator --show-sdk-path" + } + + private let shell: ShellHandling + private let fileHandler: FileHandling + private let logger: Logging? + + init( + shell: ShellHandling = Shell(), + fileHandler: FileHandling = FileManager.default, + logger: Logging? + ) { + self.shell = shell + self.fileHandler = fileHandler + self.logger = logger + } + + /// Archives a project at the specified path / scheme by building for library evolution + /// - Parameters: + /// - projectDirectoryPath: The path to the project root directory + /// - scheme: The scheme/target to build + /// - projectType: The type of the project + /// - Returns: The derived data directory path + func archive( + projectDirectoryPath: String, + scheme: String, + projectType: ProjectType + ) async throws -> String { + var commandComponents = [ + "cd \(projectDirectoryPath);", + "xcodebuild clean build -scheme \"\(scheme)\"", + "-destination \"generic/platform=iOS\"", + "-derivedDataPath \(Constants.derivedDataPath)", + "-sdk `\(Constants.simulatorSdkCommand)`", + "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)" + + 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. + // + // Also see: https://github.com/swiftlang/swift/issues/56573 + guard fileHandler.fileExists(atPath: derivedDataPath) else { + print(result) + + throw XcodeToolsError( + errorDescription: "πŸ’₯ Building project failed", + underlyingError: result + ) + } + + return derivedDataPath + }.value + } +} diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/.DS_Store b/Sources/PublicModules/PADSwiftInterfaceDiff/.DS_Store new file mode 100644 index 0000000..cf3786f Binary files /dev/null and b/Sources/PublicModules/PADSwiftInterfaceDiff/.DS_Store differ diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/Documentation.docc/.DS_Store b/Sources/PublicModules/PADSwiftInterfaceDiff/Documentation.docc/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/Sources/PublicModules/PADSwiftInterfaceDiff/Documentation.docc/.DS_Store differ diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/Documentation.docc/ChangeConsolidator_FalsePositive.png b/Sources/PublicModules/PADSwiftInterfaceDiff/Documentation.docc/ChangeConsolidator_FalsePositive.png new file mode 100644 index 0000000..9fa3873 Binary files /dev/null and b/Sources/PublicModules/PADSwiftInterfaceDiff/Documentation.docc/ChangeConsolidator_FalsePositive.png differ diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/Documentation.docc/ChangeConsolidator_Match.png b/Sources/PublicModules/PADSwiftInterfaceDiff/Documentation.docc/ChangeConsolidator_Match.png new file mode 100644 index 0000000..ef972a4 Binary files /dev/null and b/Sources/PublicModules/PADSwiftInterfaceDiff/Documentation.docc/ChangeConsolidator_Match.png differ diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/Documentation.docc/ChangeConsolidator_NoMatch.png b/Sources/PublicModules/PADSwiftInterfaceDiff/Documentation.docc/ChangeConsolidator_NoMatch.png new file mode 100644 index 0000000..0d9376a Binary files /dev/null and b/Sources/PublicModules/PADSwiftInterfaceDiff/Documentation.docc/ChangeConsolidator_NoMatch.png differ diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/Documentation.docc/PADSwiftInterfaceDiff.md b/Sources/PublicModules/PADSwiftInterfaceDiff/Documentation.docc/PADSwiftInterfaceDiff.md new file mode 100644 index 0000000..d2503b3 --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/Documentation.docc/PADSwiftInterfaceDiff.md @@ -0,0 +1,26 @@ +# ``PADSwiftInterfaceDiff`` + +The ``SwiftInterfaceDiff`` consumes a list of ``PADCore/SwiftInterfaceFile``s and detects changes between the old and new version + +## Usage + +```swift +let swiftInterfaceFiles: [SwiftInterfaceFile] = ... + +let swiftInterfaceDiff = SwiftInterfaceDiff() + +let changes: [String: [Change]] = try await swiftInterfaceDiff.run( + with: swiftInterfaceFiles +) +``` + +## How it works +![SwiftInterfaceDiff](SwiftInterfaceDiff.png) + +## Consolidating individual Changes +### Match +![False positive](ChangeConsolidator_Match.png) +### No Match +![False positive](ChangeConsolidator_NoMatch.png) +### False positive +![False positive](ChangeConsolidator_FalsePositive.png) diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/Documentation.docc/SwiftInterfaceDiff.png b/Sources/PublicModules/PADSwiftInterfaceDiff/Documentation.docc/SwiftInterfaceDiff.png new file mode 100644 index 0000000..724c131 Binary files /dev/null and b/Sources/PublicModules/PADSwiftInterfaceDiff/Documentation.docc/SwiftInterfaceDiff.png differ diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/PADSwiftInterfaceDiff.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/PADSwiftInterfaceDiff.swift new file mode 100644 index 0000000..06dcc3e --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/PADSwiftInterfaceDiff.swift @@ -0,0 +1,70 @@ +import Foundation + +import PADCore +import PADLogging +import FileHandlingModule + +/// Takes a list of ``PADCore/SwiftInterfaceFile``s and detects changes between the old and new version +public struct SwiftInterfaceDiff { + + public typealias ModuleName = String + + let fileHandler: any FileHandling + let swiftInterfaceParser: any SwiftInterfaceParsing + let swiftInterfaceAnalyzer: any SwiftInterfaceAnalyzing + let logger: (any Logging)? + + + /// Creates a new instance of ``SwiftInterfaceDiff`` + /// - Parameter logger: The (optional) logger + public init( + logger: (any Logging)? = nil + ) { + self.init( + fileHandler: FileManager.default, + swiftInterfaceParser: SwiftInterfaceParser(), + swiftInterfaceAnalyzer: SwiftInterfaceAnalyzer(), + logger: logger + ) + } + + init( + fileHandler: FileHandling = FileManager.default, + swiftInterfaceParser: any SwiftInterfaceParsing = SwiftInterfaceParser(), + swiftInterfaceAnalyzer: any SwiftInterfaceAnalyzing = SwiftInterfaceAnalyzer(), + logger: (any Logging)? = nil + ) { + self.fileHandler = fileHandler + self.swiftInterfaceParser = swiftInterfaceParser + self.swiftInterfaceAnalyzer = swiftInterfaceAnalyzer + self.logger = logger + } + + + /// Analyzes the passed ``PADCore/SwiftInterfaceFile``s and returns a list of changes grouped by scheme/target + /// - Parameter swiftInterfaceFiles: The ``PADCore/SwiftInterfaceFile``s to analyze + /// - Returns: A list of changes grouped by scheme/target + public func run(with swiftInterfaceFiles: [SwiftInterfaceFile]) async throws -> [ModuleName: [Change]] { + + 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) + 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/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceAnalyzer/IndependentSwiftInterfaceChange.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceAnalyzer/IndependentSwiftInterfaceChange.swift new file mode 100644 index 0000000..0035555 --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceAnalyzer/IndependentSwiftInterfaceChange.swift @@ -0,0 +1,38 @@ +import Foundation +import PADCore + +/// 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 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 + } + + func differences(to otherIndependentChange: IndependentSwiftInterfaceChange) -> [String] { + element.differences(to: otherIndependentChange.element).sorted() + } +} diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceAnalyzer/SwiftInterfaceAnalyzer.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceAnalyzer/SwiftInterfaceAnalyzer.swift new file mode 100644 index 0000000..4a6a67f --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceAnalyzer/SwiftInterfaceAnalyzer.swift @@ -0,0 +1,117 @@ +// +// 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 +import PADCore + +struct SwiftInterfaceAnalyzer: SwiftInterfaceAnalyzing { + + let changeConsolidator: SwiftInterfaceChangeConsolidating + + init(changeConsolidator: SwiftInterfaceChangeConsolidating = SwiftInterfaceChangeConsolidator()) { + self.changeConsolidator = changeConsolidator + } + + func analyze( + old: some SwiftInterfaceElement, + new: some SwiftInterfaceElement + ) -> [Change] { + + // Very naive diff from both sides + // There is room for improvement here but it's "performant enough" for now + + 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] { + + 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 recursive description + // as we don't want to match a non-change with a change + // + // 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 + 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 + 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] { + [ + .from( + changeType: .removal(lhs.description), + element: lhs, + oldFirst: oldFirst + ), + .from( + changeType: .addition(rhs.recursiveDescription()), + element: rhs, + oldFirst: oldFirst + ) + ] + } +} diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceAnalyzer/SwiftInterfaceAnalyzing.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceAnalyzer/SwiftInterfaceAnalyzing.swift new file mode 100644 index 0000000..07c3dce --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceAnalyzer/SwiftInterfaceAnalyzing.swift @@ -0,0 +1,6 @@ +import Foundation +import PADCore + +protocol SwiftInterfaceAnalyzing { + func analyze(old: some SwiftInterfaceElement, new: some SwiftInterfaceElement) throws -> [Change] +} diff --git a/Sources/Pipeline/Modules/SDKDumpAnalyzer/ChangeConsolidator.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceAnalyzer/SwiftInterfaceChangeConsolidator.swift similarity index 72% rename from Sources/Pipeline/Modules/SDKDumpAnalyzer/ChangeConsolidator.swift rename to Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceAnalyzer/SwiftInterfaceChangeConsolidator.swift index 1d68f14..44d89f6 100644 --- a/Sources/Pipeline/Modules/SDKDumpAnalyzer/ChangeConsolidator.swift +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceAnalyzer/SwiftInterfaceChangeConsolidator.swift @@ -5,19 +5,20 @@ // import Foundation +import PADCore /// A helper to consolidate a `removal` and `addition` to `change` -protocol ChangeConsolidating { +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: [IndependentChange]) -> [Change] + func consolidate(_ changes: [IndependentSwiftInterfaceChange]) -> [Change] } -struct ChangeConsolidator: ChangeConsolidating { - +struct SwiftInterfaceChangeConsolidator: SwiftInterfaceChangeConsolidating { + /// Tries to match a `removal` and `addition` to a `change` /// /// - Parameters: @@ -31,7 +32,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: [IndependentSwiftInterfaceChange]) -> [Change] { var independentChanges = changes var consolidatedChanges = [Change]() @@ -49,14 +50,19 @@ struct ChangeConsolidator: ChangeConsolidating { 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) - + + if listOfChanges.isEmpty { + assertionFailure("We should not end up here - investigate how this happened") + break + } + consolidatedChanges.append( .init( changeType: .change( oldDescription: oldDescription, newDescription: newDescription ), - parentName: match.parentName, + parentPath: match.parentPath, listOfChanges: listOfChanges ) ) @@ -66,16 +72,16 @@ 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: IndependentSwiftInterfaceChange, and rhs: IndependentSwiftInterfaceChange) -> [String] { if lhs.oldFirst { - lhs.element.differences(to: rhs.element) + rhs.differences(to: lhs) } else { - rhs.element.differences(to: lhs.element) + lhs.differences(to: rhs) } } } -extension IndependentChange { +extension IndependentSwiftInterfaceChange { var toConsolidatedChange: Change { let changeType: Change.ChangeType = { @@ -89,13 +95,13 @@ 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 { + static func from(changeType: ChangeType, element: some SwiftInterfaceElement, oldFirst: Bool) -> Self { .init( changeType: changeType, element: element, @@ -103,26 +109,26 @@ extension IndependentChange { ) } - /// Checks whether or not 2 changes can be diffed based on their elements `name`, `declKind` and `parentPath`. + /// 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 `name`, `declKind`, `parentPath` of the element is the same we can assume that it's the same element but altered. + /// 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 `printedName` as it (for functions) does not take the arguments into account. + /// `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: IndependentChange) -> 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 + 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 IndependentChange.ChangeType { +private extension IndependentSwiftInterfaceChange.ChangeType { /// The name of the type (without associated value) as String var name: String { diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/ActorDeclSyntax+SwiftInterface.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/ActorDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..4b2eef7 --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/ActorDeclSyntax+SwiftInterface.swift @@ -0,0 +1,18 @@ +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/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/AssociatedTypeDeclSyntax+SwiftInterface.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/AssociatedTypeDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..b1de1f3 --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/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( + attributes: self.attributes.sanitizedList, + modifiers: self.modifiers.sanitizedList, + name: self.name.trimmedDescription, + inheritance: self.inheritanceClause?.inheritedTypes.sanitizedList, + initializerValue: self.initializer?.value.trimmedDescription, + genericWhereClauseDescription: self.genericWhereClause?.trimmedDescription + ) + } +} diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/ClassDeclSyntac+SwiftInterface.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/ClassDeclSyntac+SwiftInterface.swift new file mode 100644 index 0000000..f06c225 --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/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( + 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/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/DeclSyntax+Convenience.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/DeclSyntax+Convenience.swift new file mode 100644 index 0000000..248f032 --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/DeclSyntax+Convenience.swift @@ -0,0 +1,37 @@ +import SwiftSyntax + +extension SyntaxCollection { + + /// Produces a description where all elements in the list are mapped to their `trimmedDescription` + var sanitizedList: [String] { + self.map { $0.trimmedDescription } + } +} + +extension InheritedTypeListSyntax { + + /// Produces a description where all elements in the list are mapped to their type's `trimmedDescription` + var sanitizedList: [String] { + self.map { $0.type.trimmedDescription } + } +} + +extension AccessorBlockSyntax { + + /// Produces a description where all newlines and spaces are replaced by a single space + /// + /// e.g. "get\n set\n" -> "get set" + var sanitizedDescription: String { + accessors.trimmedDescription.sanitizingNewlinesAndSpaces + } +} + +extension String { + + /// Produces a string where all newlines and spaces are replaced by a single space + /// + /// e.g. "get\n set\n" -> "get set" + var sanitizingNewlinesAndSpaces: String { + self.replacingOccurrences(of: "[\n ]+", with: " ", options: .regularExpression) + } +} diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/EnumCaseDeclSyntax+SwiftInterface.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/EnumCaseDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..1c9beea --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/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.sanitizedList + let modifiers = self.modifiers.sanitizedList + + return elements.map { + SwiftInterfaceEnumCase( + attributes: 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?.value.description + ) + }, + rawValue: $0.rawValue?.value.trimmedDescription + ) + } + } +} diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/EnumDeclSyntax+SwiftInterface.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/EnumDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..44761ce --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/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( + 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/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/ExtensionDeclSyntax+SwiftInterface.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/ExtensionDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..8c4fd42 --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/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 { + 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/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/FunctionDeclSyntax+SwiftInterface.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/FunctionDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..9832c8b --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/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?.value.trimmedDescription.sanitizingNewlinesAndSpaces + ) + } + + return SwiftInterfaceFunction( + attributes: self.attributes.sanitizedList, + modifiers: self.modifiers.sanitizedList, + name: self.name.trimmedDescription, + genericParameterDescription: self.genericParameterClause?.trimmedDescription, + parameters: parameters, + effectSpecifiers: effectSpecifiers, + returnType: signature.returnClause?.type.trimmedDescription, + genericWhereClauseDescription: self.genericWhereClause?.trimmedDescription + ) + } +} diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/InitializerDeclSyntax+SwiftInterface.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/InitializerDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..5bc8e1c --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/InitializerDeclSyntax+SwiftInterface.swift @@ -0,0 +1,39 @@ +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.trimmedDescription.sanitizingNewlinesAndSpaces + ) + } + + return SwiftInterfaceInitializer( + attributes: self.attributes.sanitizedList, + modifiers: self.modifiers.sanitizedList, + optionalMark: optionalMark?.trimmedDescription, + genericParameterDescription: self.genericParameterClause?.trimmedDescription, + parameters: parameters, + effectSpecifiers: effectSpecifiers, + genericWhereClauseDescription: self.genericWhereClause?.trimmedDescription + ) + } +} diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/ProtocolDeclSyntax+SwiftInterface.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/ProtocolDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..981c834 --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/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( + attributes: self.attributes.sanitizedList, + modifiers: self.modifiers.sanitizedList, + name: self.name.trimmedDescription, + primaryAssociatedTypes: self.primaryAssociatedTypeClause?.primaryAssociatedTypes.map { $0.name.trimmedDescription }, + inheritance: self.inheritanceClause?.inheritedTypes.sanitizedList, + genericWhereClauseDescription: self.genericWhereClause?.trimmedDescription, + children: children + ) + } +} diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/StructDeclSyntax+SwiftInterface.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/StructDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..5a78bc1 --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/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( + 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/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/SubscriptDeclSyntax+SwiftInterface.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/SubscriptDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..1551789 --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/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.trimmedDescription.sanitizingNewlinesAndSpaces + ) + } + + 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/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/TypeAliasDeclSyntax+SwiftInterface.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/TypeAliasDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..3f17c66 --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/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( + attributes: self.attributes.sanitizedList, + modifiers: self.modifiers.sanitizedList, + name: self.name.trimmedDescription, + genericParameterDescription: self.genericParameterClause?.trimmedDescription, + initializerValue: self.initializer.value.trimmedDescription, + genericWhereClauseDescription: self.genericWhereClause?.trimmedDescription + ) + } +} diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/VarDeclSyntax+SwiftInterface.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/VarDeclSyntax+SwiftInterface.swift new file mode 100644 index 0000000..4f720b6 --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/DeclSyntax+SwiftInterface/VarDeclSyntax+SwiftInterface.swift @@ -0,0 +1,37 @@ +import SwiftSyntax +import SwiftParser + +/// See: https://swiftpackageindex.com/swiftlang/swift-syntax/documentation/swiftsyntax/structdeclsyntax +extension VariableDeclSyntax { + + func toInterfaceElement() -> [SwiftInterfaceVar] { + + 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: + // - final public let a: Int = 0 + // - 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 ?? "UNKNOWN_TYPE", + initializerValue: $0.initializer?.value.trimmedDescription, + accessors: accessors + ) + } + } +} diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Actor.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Actor.swift new file mode 100644 index 0000000..1c9f498 --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Actor.swift @@ -0,0 +1,97 @@ +import Foundation + +class SwiftInterfaceActor: SwiftInterfaceExtendableElement { + + var pathComponentName: String { name } + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let attributes: [String] + + /// The name of the element + let name: String + + /// e.g. + let genericParameterDescription: String? + + /// Types/Protocols the element inherits from + var inheritance: [String]? + + /// e.g. public, private, package, open, internal + let modifiers: [String] + + /// e.g. where T : Equatable + let genericWhereClauseDescription: String? + + var children: [any SwiftInterfaceElement] + + var parent: (any SwiftInterfaceElement)? = nil + + var diffableSignature: String { name } + + var consolidatableName: String { name } + + var description: String { compileDescription() } + + var typeName: String { name } + + 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 + } +} + +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 { + + 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/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+AssociatedType.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+AssociatedType.swift new file mode 100644 index 0000000..987d554 --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+AssociatedType.swift @@ -0,0 +1,89 @@ +import Foundation + +class SwiftInterfaceAssociatedType: SwiftInterfaceElement { + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let attributes: [String] + + /// The name of the element + let name: String + + /// Types/Protocols the element inherits from + 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? + + var pathComponentName: String { name } + + /// 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( + attributes: [String], + modifiers: [String], + name: String, + inheritance: [String]?, + initializerValue: String?, + genericWhereClauseDescription: String? + ) { + self.attributes = attributes + self.modifiers = modifiers + self.name = name + self.inheritance = inheritance + self.initializerValue = initializerValue + self.genericWhereClauseDescription = genericWhereClauseDescription + } +} + +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 { + + var components = [String]() + + components += attributes + components += modifiers + components += ["associatedtype"] + + if let inheritance, !inheritance.isEmpty { + components += ["\(name): \(inheritance.joined(separator: ", "))"] + } else { + components += [name] + } + + initializerValue.map { components += ["= \($0)"] } + + genericWhereClauseDescription.map { components += [$0] } + + return components.joined(separator: " ") + } +} diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Class.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Class.swift new file mode 100644 index 0000000..60d9322 --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Class.swift @@ -0,0 +1,97 @@ +import Foundation + +class SwiftInterfaceClass: SwiftInterfaceExtendableElement { + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let attributes: [String] + + /// The name of the element + let name: String + + /// e.g. + let genericParameterDescription: String? + + /// Types/Protocols the element inherits from + var inheritance: [String]? + + /// e.g. public, private, package, open, internal + let modifiers: [String] + + /// e.g. where T : Equatable + let genericWhereClauseDescription: String? + + var pathComponentName: String { name } + + var children: [any SwiftInterfaceElement] + + var parent: (any SwiftInterfaceElement)? = nil + + var diffableSignature: String { name } + + var consolidatableName: String { name } + + var description: String { compileDescription() } + + var typeName: String { name } + + 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 + } +} + +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 { + + var components = [String]() + + components += attributes + components += modifiers + components += ["class"] + + 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/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Enum.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Enum.swift new file mode 100644 index 0000000..1c6fe02 --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Enum.swift @@ -0,0 +1,95 @@ +import Foundation + +class SwiftInterfaceEnum: SwiftInterfaceExtendableElement { + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let attributes: [String] + + /// e.g. public, private, package, open, internal + let modifiers: [String] + + let name: String + + /// e.g. + let genericParameterDescription: String? + + var inheritance: [String]? + + /// e.g. where T : Equatable + let genericWhereClauseDescription: String? + + var pathComponentName: String { name } + + var children: [any SwiftInterfaceElement] + + var parent: (any SwiftInterfaceElement)? = nil + + var diffableSignature: String { name } + + var consolidatableName: String { name } + + var description: String { compileDescription() } + + var typeName: String { name } + + 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 + } +} + +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 { + + var components = [String]() + + components += attributes + components += modifiers + components += ["enum"] + + 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/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+EnumCase.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+EnumCase.swift new file mode 100644 index 0000000..d945f23 --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+EnumCase.swift @@ -0,0 +1,109 @@ +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 + } + } +} + +class SwiftInterfaceEnumCase: SwiftInterfaceElement { + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let attributes: [String] + + /// e.g. public, private, package, open, internal + let modifiers: [String] + + let name: String + + let parameters: [Parameter]? + + let rawValue: String? + + var pathComponentName: String { "" } // Not relevant as / no children + + /// An enum case 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( + attributes: [String], + modifiers: [String], + name: String, + parameters: [Parameter]?, + rawValue: String? + ) { + self.attributes = attributes + self.modifiers = modifiers + self.name = name + self.parameters = parameters + self.rawValue = rawValue + } +} + +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 }) + changes += diffDescription(propertyType: "raw value", oldValue: other.rawValue, newValue: rawValue) + return changes.compactMap { $0 } + } +} + +private extension SwiftInterfaceEnumCase { + + func compileDescription() -> String { + + var components = [String]() + + components += attributes + 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/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Extension.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Extension.swift new file mode 100644 index 0000000..06a7564 --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Extension.swift @@ -0,0 +1,85 @@ +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? + + var pathComponentName: String { + [extendedType, genericWhereClauseDescription.map { "[\($0)]"}].compactMap { $0 }.joined() + } + + /// The members, declarations, ... inside of the body of the struct + var 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 + } +} + +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 { + + 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/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Function.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Function.swift new file mode 100644 index 0000000..2f7f3ae --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Function.swift @@ -0,0 +1,136 @@ +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 + } + } +} + +class SwiftInterfaceFunction: SwiftInterfaceElement { + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let attributes: [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? + + var pathComponentName: String { name } + + /// 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( + attributes: [String], + modifiers: [String], + name: String, + genericParameterDescription: String?, + parameters: [Parameter], + effectSpecifiers: [String], + returnType: String?, + genericWhereClauseDescription: String? + ) { + self.attributes = attributes + self.modifiers = modifiers + self.name = name + self.genericParameterDescription = genericParameterDescription + self.parameters = parameters + self.effectSpecifiers = effectSpecifiers + self.returnType = returnType ?? "Swift.Void" + self.genericWhereClauseDescription = genericWhereClauseDescription + } +} + +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 { + var components = [String]() + + components += attributes + 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/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Initializer.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Initializer.swift new file mode 100644 index 0000000..ca49acf --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Initializer.swift @@ -0,0 +1,133 @@ +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 pathComponentName: String { "" } // Not relevant as / no children + + /// A initializer 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], + genericWhereClauseDescription: String? + ) { + self.attributes = attributes + self.modifiers = modifiers + self.optionalMark = optionalMark + self.genericParameterDescription = genericParameterDescription + self.parameters = parameters + self.effectSpecifiers = effectSpecifiers + self.genericWhereClauseDescription = genericWhereClauseDescription + } +} + +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 { + 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/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Protocol.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Protocol.swift new file mode 100644 index 0000000..b9e1cc8 --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Protocol.swift @@ -0,0 +1,95 @@ +import Foundation + +class SwiftInterfaceProtocol: SwiftInterfaceExtendableElement { + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let attributes: [String] + + let name: String + + let primaryAssociatedTypes: [String]? + + var inheritance: [String]? + + /// e.g. public, private, package, open, internal + let modifiers: [String] + + /// e.g. where T : Equatable + let genericWhereClauseDescription: String? + + var pathComponentName: String { name } + + /// The members, declarations, ... inside of the body of the struct + var children: [any SwiftInterfaceElement] + + var parent: (any SwiftInterfaceElement)? = nil + + var diffableSignature: String { name } + + var consolidatableName: String { name } + + var description: String { compileDescription() } + + var typeName: String { name } + + init( + attributes: [String], + modifiers: [String], + name: String, + primaryAssociatedTypes: [String]?, + inheritance: [String]?, + genericWhereClauseDescription: String?, + children: [any SwiftInterfaceElement] + ) { + self.attributes = attributes + self.name = name + self.primaryAssociatedTypes = primaryAssociatedTypes + self.inheritance = inheritance + self.modifiers = modifiers + self.genericWhereClauseDescription = genericWhereClauseDescription + self.children = children + } +} + +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 { + + var components = [String]() + + components += attributes + components += modifiers + components += ["protocol"] + + components += [{ + var components = [ + name, + primaryAssociatedTypes.map { "<\($0.joined(separator: ", "))>"} + ].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/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Struct.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Struct.swift new file mode 100644 index 0000000..c21962c --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Struct.swift @@ -0,0 +1,95 @@ +import Foundation + +class SwiftInterfaceStruct: SwiftInterfaceExtendableElement { + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let attributes: [String] + + let name: String + + /// e.g. + let genericParameterDescription: String? + + var inheritance: [String]? + + /// e.g. public, private, package, open, internal + let modifiers: [String] + + /// e.g. where T : Equatable + let genericWhereClauseDescription: String? + + var pathComponentName: String { name } + + var children: [any SwiftInterfaceElement] + + var parent: (any SwiftInterfaceElement)? = nil + + var diffableSignature: String { name } + + var consolidatableName: String { name } + + var description: String { compileDescription() } + + var typeName: String { name } + + 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 + } +} + +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 { + + var components = [String]() + + components += attributes + components += modifiers + components += ["struct"] + + 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/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Subscript.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Subscript.swift new file mode 100644 index 0000000..666daff --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Subscript.swift @@ -0,0 +1,132 @@ +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 pathComponentName: String { "" } // Not relevant as / no 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( + 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 + } +} + +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 { + 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/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+TypeAlias.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+TypeAlias.swift new file mode 100644 index 0000000..99a89ee --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+TypeAlias.swift @@ -0,0 +1,90 @@ +import Foundation + +class SwiftInterfaceTypeAlias: SwiftInterfaceElement { + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let attributes: [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? + + var pathComponentName: String { "" } // Not relevant as / no children + + 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?, + initializerValue: String, + genericWhereClauseDescription: String? + ) { + self.attributes = attributes + self.name = name + self.genericParameterDescription = genericParameterDescription + self.initializerValue = initializerValue + self.modifiers = modifiers + self.genericWhereClauseDescription = genericWhereClauseDescription + } +} + +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 { + + var components = [String]() + + components += attributes + components += modifiers + components += ["typealias"] + + components += [ + [ + name, + genericParameterDescription + ].compactMap { $0 }.joined() + ] + + components += ["= \(initializerValue)"] + + genericWhereClauseDescription.map { components += [$0] } + + return components.joined(separator: " ") + } +} diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Var.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Var.swift new file mode 100644 index 0000000..d48c6ff --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement+Declaration/SwiftInterfaceElement+Var.swift @@ -0,0 +1,86 @@ +import Foundation + +class SwiftInterfaceVar: SwiftInterfaceElement { + + /// e.g. @discardableResult, @MainActor, @objc, @_spi(...), ... + let attributes: [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? + + var pathComponentName: String { "" } // Not relevant as / no children + + 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], + bindingSpecifier: String, + name: String, + typeAnnotation: String, + initializerValue: String?, + accessors: String? + ) { + self.attributes = attributes + self.modifiers = modifiers + self.bindingSpecifier = bindingSpecifier + self.name = name + self.typeAnnotation = typeAnnotation + self.initializerValue = initializerValue + self.accessors = accessors + } +} + +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 { + + var components = [String]() + + components += attributes + components += modifiers + components += [bindingSpecifier] + components += ["\(name): \(typeAnnotation)"] + + initializerValue.map { components += ["= \($0)"] } + accessors.map { components += ["{ \($0) }"] } + + return components.joined(separator: " ") + } +} diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement/SwiftInterfaceElement+DiffHelper.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement/SwiftInterfaceElement+DiffHelper.swift new file mode 100644 index 0000000..a5960de --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement/SwiftInterfaceElement+DiffHelper.swift @@ -0,0 +1,90 @@ +import Foundation +import PADCore + +extension SwiftInterfaceElement { + + /// Returns a description for a change between an old and new value + /// - Parameters: + /// - propertyType: The (optional) property type name (e.g. "accessor", "modifier", "generic where clause", ...) for additional information + /// - oldValue: The (optional) old value + /// - newValue: The (optional) new value + /// - Returns: A list with a single item that represents a change description caused by a value change + 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] + } + + /// Returns a list of change descriptions for changes between the old and new values + /// - Parameters: + /// - propertyType: The (optional) property type name (e.g. "accessor", "modifier", "generic where clause", ...) for additional information + /// - oldValue: The (optional) old values + /// - newValue: The (optional) new values + /// - Returns: A list of change descriptions caused by a value change + 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 [] + } +} + +// MARK: - + +/// File-private helper to produce detailed descriptions +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 + } +} diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement/SwiftInterfaceElement.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement/SwiftInterfaceElement.swift new file mode 100644 index 0000000..73fb803 --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement/SwiftInterfaceElement.swift @@ -0,0 +1,132 @@ +import Foundation + +protocol SwiftInterfaceExtendableElement: SwiftInterfaceElement { + + /// Name of the type + /// + /// Is used to match an extension's `extendedType` to the element it extends + var typeName: String { get } + + /// Types/Protocols the element inherits from + var inheritance: [String]? { get set } + + var children: [any SwiftInterfaceElement] { get set } +} + +protocol SwiftInterfaceElement: CustomStringConvertible, AnyObject { + + /// The name of the element used to construct the parent path for its children + var pathComponentName: String { get } + + /// The full description of the element (without children) + var description: String { get } + + /// The cildren of the element (e.g. properties/functions of a struct/class/...) + 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 } + + /// The parent of the element (setup by using ``setupParentRelationships(parent:)`` + var parent: (any SwiftInterfaceElement)? { get set } + + /// Produces a list of differences between one and another element + func differences(to otherElement: T) -> [String] +} + +extension SwiftInterfaceElement { + + func setupParentRelationships(parent: (any SwiftInterfaceElement)? = nil) { + self.parent = parent + children.forEach { + $0.setupParentRelationships(parent: self) + } + } + + /// The path to the parent based on the `pathComponentName` + /// + /// The path does not including the own `pathComponentName` + /// + /// - Important: `SwiftInterfaceExtension`'s parentPath is always the `extendedType` + /// of the element to group them under the extended element + 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 sanitized( + parentPath: extensionElement.extendedType + ) + } + + var parent = self.parent + var path = [parent?.pathComponentName] + + while parent != nil { + parent = parent?.parent + path += [parent?.pathComponentName] + } + + 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: ".") + } +} + +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 { + + /// Produces the complete recursive description of the element + 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))}") + } + + if indentation == 0 { + recursiveDescription.append("\n") + } + + return recursiveDescription + } +} diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceParser+Root.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceParser+Root.swift new file mode 100644 index 0000000..59fc775 --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceParser+Root.swift @@ -0,0 +1,147 @@ +import Foundation + +extension SwiftInterfaceParser { + + /// The root element returned as the result of parsing the interface + class Root: SwiftInterfaceElement { + + var parent: (any SwiftInterfaceElement)? = nil + + var diffableSignature: String { "" } + + var consolidatableName: String { "" } + + /// Produces the complete recursive description of the interface + var description: String { + var description = "" + children.forEach { child in + description.append(child.recursiveDescription()) + description.append("\n") + } + return description + } + + var pathComponentName: 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 [] + } + } +} + +// MARK: - Convenience methods + +private extension SwiftInterfaceParser.Root { + + /// 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 ``SwiftInterfaceExtension.extendedType`` and there might be a lot of changes inside of the extensions between versions + /// + /// Example: + /// ``` + /// struct S { + /// var a: String + /// } + /// + /// extension S: SomeProtocol { + /// var b: Int { 1 } + /// } + /// ``` + /// + /// ... Is turned into ... + /// ``` + /// struct S: SomeProtocol { + /// var a: String + /// var b: Int { 1 } + /// } + /// ``` + static func mergeExtensions(for elements: [any SwiftInterfaceElement], moduleName: String) -> [any SwiftInterfaceElement] { + + let extensions = elements.compactMap { $0 as? SwiftInterfaceExtension } + let extendableElements = elements.compactMap { $0 as? SwiftInterfaceExtendableElement } + 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 + /// + /// Example: + /// ``` + /// struct S { + /// enum E { + /// class C {} + /// } + /// } + /// + /// extension S.E.C: SomeProtocol { + /// var b: Int { 1 } + /// } + /// ``` + /// + /// ... Is turned into ... + /// ``` + /// struct S { + /// enum E { + /// class C: SomeProtocol { + /// var b: Int { 1 } + /// } + /// } + /// } + /// ``` + static func merge( + extensionElement: SwiftInterfaceExtension, + with extendableElements: [any SwiftInterfaceExtendableElement], + prefix: String + ) -> Bool { + + // Finding the first extendable element that has the same prefix as the extension + guard let extendedElement = extendableElements.first(where: { extensionElement.extendedType.hasPrefix("\(prefix).\($0.typeName)") }) else { + return false + } + + 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 } + return merge(extensionElement: extensionElement, with: extendableChildren, prefix: extendedElementPrefix) + } +} diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceParser.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceParser.swift new file mode 100644 index 0000000..21b9dd5 --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceParser.swift @@ -0,0 +1,217 @@ +import Foundation +import SwiftSyntax +import SwiftParser + +/// Parses the source content of a swift file into intermediate objects for further processing +/// +/// See: +/// - [DeclSyntax](https://swiftpackageindex.com/swiftlang/swift-syntax/documentation/swiftsyntax/declsyntax) +class SwiftInterfaceParser: SyntaxVisitor, SwiftInterfaceParsing { + + // TODO: Handle (Nice to have) + // - DeinitializerDeclSyntax + // - PrecedenceGroupDeclSyntax + // - OperatorDeclSyntax + // - IfConfigClauseListSyntax + // - ... (There are more but not important right now) + + private var scope: Scope = .root(elements: []) + + func parse(source: String, moduleName: String) -> any SwiftInterfaceElement { + let visitor = Self() + visitor.walk(Parser.parse(source: source)) + return Root( + moduleName: moduleName, + elements: visitor.scope.elements + ) + } + + /// Designated initializer + required init() { + super.init(viewMode: .sourceAccurate) + } + + /// Starts a new scope which can contain zero or more nested symbols + 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 + func endScopeAndAddSymbol(makeElementsWithChildrenInScope: (_ children: [any SwiftInterfaceElement]) -> [any SwiftInterfaceElement]) { + scope.end(makeElementsWithChildrenInScope: makeElementsWithChildrenInScope) + } + + // 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: - 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: - Scope + +fileprivate indirect enum Scope { + + /// The root scope of a file + case root(elements: [any SwiftInterfaceElement]) + + /// A nested scope, within a parent scope + case nested(parent: Scope, elements: [any SwiftInterfaceElement]) + + /// Starts a new nested scope + mutating func start() { + self = .nested(parent: self, elements: []) + } + + /// 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(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 rootElements), _): + self = .root(elements: rootElements + newElements) + + case .nested(.nested(let parent, let parentElements), _): + self = .nested(parent: parent, elements: parentElements + newElements) + } + } + + var elements: [any SwiftInterfaceElement] { + switch self { + 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/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceParsing.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceParsing.swift new file mode 100644 index 0000000..02489ea --- /dev/null +++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceParsing.swift @@ -0,0 +1,5 @@ +import Foundation + +protocol SwiftInterfaceParsing { + func parse(source: String, moduleName: String) -> any SwiftInterfaceElement +} diff --git a/Sources/Helpers/FileHandling/FileHandling+Convenience.swift b/Sources/Shared/Package/FileHandlingModule/FileHandling+Convenience.swift similarity index 95% rename from Sources/Helpers/FileHandling/FileHandling+Convenience.swift rename to Sources/Shared/Package/FileHandlingModule/FileHandling+Convenience.swift index d23200f..634e0d3 100644 --- a/Sources/Helpers/FileHandling/FileHandling+Convenience.swift +++ b/Sources/Shared/Package/FileHandlingModule/FileHandling+Convenience.swift @@ -6,7 +6,7 @@ import Foundation -enum FileHandlerError: LocalizedError, Equatable { +package enum FileHandlerError: LocalizedError, Equatable { /// Could not encode the output string into data case couldNotEncodeOutput /// Could not persist output at the specified `outputFilePath` @@ -16,7 +16,7 @@ enum FileHandlerError: LocalizedError, Equatable { /// File/Directory does not exist at `path` case pathDoesNotExist(path: String) - var errorDescription: String? { + public var errorDescription: String? { switch self { case .couldNotEncodeOutput: "Could not encode the output string into data" @@ -32,7 +32,7 @@ enum FileHandlerError: LocalizedError, Equatable { // MARK: - Convenience -extension FileHandling { +package extension FileHandling { /// Creates a directory at the specified path and deletes any old directory if existing /// diff --git a/Sources/Helpers/FileHandling/FileHandling.swift b/Sources/Shared/Package/FileHandlingModule/FileHandling.swift similarity index 72% rename from Sources/Helpers/FileHandling/FileHandling.swift rename to Sources/Shared/Package/FileHandlingModule/FileHandling.swift index 720f0f7..87d6e6b 100644 --- a/Sources/Helpers/FileHandling/FileHandling.swift +++ b/Sources/Shared/Package/FileHandlingModule/FileHandling.swift @@ -1,12 +1,6 @@ -// -// 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 -protocol FileHandling { +package protocol FileHandling { var currentDirectoryPath: String { get } diff --git a/Sources/Helpers/FileHandling/FileManager+FileHandling.swift b/Sources/Shared/Package/FileHandlingModule/FileManager+FileHandling.swift similarity index 76% rename from Sources/Helpers/FileHandling/FileManager+FileHandling.swift rename to Sources/Shared/Package/FileHandlingModule/FileManager+FileHandling.swift index 1823519..109ae07 100644 --- a/Sources/Helpers/FileHandling/FileManager+FileHandling.swift +++ b/Sources/Shared/Package/FileHandlingModule/FileManager+FileHandling.swift @@ -9,16 +9,16 @@ import Foundation extension FileManager: FileHandling { /// Creates a directory at the specified path - func createDirectory(atPath path: String) throws { + package func createDirectory(atPath path: String) throws { try createDirectory(atPath: path, withIntermediateDirectories: true) } /// Creates a file at the specified path with the provided content - func createFile(atPath path: String, contents data: Data) -> Bool { + package func createFile(atPath path: String, contents data: Data) -> Bool { createFile(atPath: path, contents: data, attributes: nil) } - func loadData(from filePath: String) throws -> Data { + package func loadData(from filePath: String) throws -> Data { guard let data = self.contents(atPath: filePath) else { throw FileHandlerError.couldNotLoadFile(filePath: filePath) } diff --git a/Sources/Helpers/Shell.swift b/Sources/Shared/Package/ShellModule/Shell.swift similarity index 81% rename from Sources/Helpers/Shell.swift rename to Sources/Shared/Package/ShellModule/Shell.swift index 5cd3c89..0217380 100644 --- a/Sources/Helpers/Shell.swift +++ b/Sources/Shared/Package/ShellModule/Shell.swift @@ -6,16 +6,18 @@ import Foundation -protocol ShellHandling { +package protocol ShellHandling { @discardableResult func execute(_ command: String) -> String } -struct Shell: ShellHandling { +package struct Shell: ShellHandling { + + package init() {} @discardableResult - func execute(_ command: String) -> String { + package func execute(_ command: String) -> String { let task = Process() let pipe = Pipe() diff --git a/Sources/Helpers/Models/SwiftPackageDescription.swift b/Sources/Shared/Package/SwiftPackageFileHelperModule/SwiftPackageDescription.swift similarity index 73% rename from Sources/Helpers/Models/SwiftPackageDescription.swift rename to Sources/Shared/Package/SwiftPackageFileHelperModule/SwiftPackageDescription.swift index 7410d2a..5bbcb97 100644 --- a/Sources/Helpers/Models/SwiftPackageDescription.swift +++ b/Sources/Shared/Package/SwiftPackageFileHelperModule/SwiftPackageDescription.swift @@ -6,22 +6,22 @@ import Foundation -// See: https://docs.swift.org/package-manager/PackageDescription/index.html -// See: https://github.com/swiftlang/swift-package-manager/blob/main/Sources/PackageDescription/PackageDescriptionSerialization.swift - -struct SwiftPackageDescription: Codable, Equatable { +/// The object representation of a `Package.swift` file +/// +/// See: [PackageDescription](https://docs.swift.org/package-manager/PackageDescription/index.html) & [PackageDescriptionSerialization](https://github.com/swiftlang/swift-package-manager/blob/main/Sources/PackageDescription/PackageDescriptionSerialization.swift) +package struct SwiftPackageDescription: Codable, Equatable { - let name: String - let platforms: [Platform] - let defaultLocalization: String? + package let name: String + package let platforms: [Platform] + package let defaultLocalization: String? - let targets: [Target] - let products: [Product] - let dependencies: [Dependency] + package let targets: [Target] + package let products: [Product] + package let dependencies: [Dependency] - let toolsVersion: String + package let toolsVersion: String - var warnings = [String]() + package var warnings = [String]() init( defaultLocalization: String?, @@ -56,51 +56,53 @@ struct SwiftPackageDescription: Codable, Equatable { extension SwiftPackageDescription { - struct Platform: Codable, Equatable, Hashable { + package struct Platform: Codable, Equatable, Hashable { - let name: String - let version: String + package let name: String + package let version: String } } extension SwiftPackageDescription.Platform: CustomStringConvertible { - var description: String { + + package var description: String { "\(name)(\(version))" } } -extension SwiftPackageDescription { +package extension SwiftPackageDescription { struct Product: Codable, Equatable, Hashable { // TODO: Add `rule` property - let name: String - let targets: [String] + package let name: String + package let targets: [String] } } extension SwiftPackageDescription.Product: CustomStringConvertible { - var description: String { + + package var description: String { let targetsDescription = targets.map { "\"\($0)\"" }.joined(separator: ", ") return ".library(name: \"\(name)\", targets: [\(targetsDescription)])" } } -extension SwiftPackageDescription { +package extension SwiftPackageDescription { struct Dependency: Codable, Equatable { - let identity: String - let requirement: Requirement - let type: String - let url: String? + package let identity: String + package let requirement: Requirement + package let type: String + package let url: String? } } extension SwiftPackageDescription.Dependency: CustomStringConvertible { - var description: String { + package var description: String { var description = ".package(" var fields = [String]() @@ -118,19 +120,19 @@ extension SwiftPackageDescription.Dependency: CustomStringConvertible { } } -extension SwiftPackageDescription.Dependency { +package extension SwiftPackageDescription.Dependency { struct Requirement: Codable, Equatable { // TODO: Which other requirements exist? - let exact: [String]? + package let exact: [String]? } } extension SwiftPackageDescription.Dependency.Requirement: CustomStringConvertible { - var description: String { + package var description: String { if let exactVersion = exact?.first { return "exact: \"\(exactVersion)\"" } @@ -139,31 +141,31 @@ extension SwiftPackageDescription.Dependency.Requirement: CustomStringConvertibl } } -extension SwiftPackageDescription { +package extension SwiftPackageDescription { struct Target: Codable, Equatable { - enum ModuleType: String, Codable, Equatable { + package enum ModuleType: String, Codable, Equatable { case swiftTarget = "SwiftTarget" case binaryTarget = "BinaryTarget" case clangTarget = "ClangTarget" } - enum TargetType: String, Codable, Equatable { + package enum TargetType: String, Codable, Equatable { case library = "library" case binary = "binary" case test = "test" } - let name: String - let type: TargetType - let path: String - let moduleType: ModuleType + package let name: String + package let type: TargetType + package let path: String + package let moduleType: ModuleType /// `.product(name: ...)` dependency - let productDependencies: [String]? + package let productDependencies: [String]? /// `.target(name: ...) dependency - let targetDependencies: [String]? + package let targetDependencies: [String]? // Ignoring following properties for now as they are not handled in the `PackageAnalyzer` // and thus would produce changes that are not visible @@ -200,7 +202,8 @@ extension SwiftPackageDescription { } extension SwiftPackageDescription.Target.TargetType: CustomStringConvertible { - var description: String { + + package var description: String { switch self { case .binary: "binaryTarget" case .library: "target" @@ -211,7 +214,7 @@ extension SwiftPackageDescription.Target.TargetType: CustomStringConvertible { extension SwiftPackageDescription.Target: CustomStringConvertible { - var description: String { + package var description: String { var description = ".\(type.description)(name: \"\(name)\"" var dependencyDescriptions = [String]() @@ -237,12 +240,12 @@ extension SwiftPackageDescription.Target: CustomStringConvertible { } } -extension SwiftPackageDescription.Target { +package extension SwiftPackageDescription.Target { struct Resource: Codable, Equatable { // TODO: Add `rule` property - let path: String + package let path: String } } diff --git a/Sources/Helpers/SwiftPackageFileHelper.swift b/Sources/Shared/Package/SwiftPackageFileHelperModule/SwiftPackageFileHelper.swift similarity index 85% rename from Sources/Helpers/SwiftPackageFileHelper.swift rename to Sources/Shared/Package/SwiftPackageFileHelperModule/SwiftPackageFileHelper.swift index 1f45386..8805391 100644 --- a/Sources/Helpers/SwiftPackageFileHelper.swift +++ b/Sources/Shared/Package/SwiftPackageFileHelperModule/SwiftPackageFileHelper.swift @@ -6,6 +6,11 @@ import Foundation +import PADLogging + +import FileHandlingModule +import ShellModule + enum SwiftPackageFileHelperError: LocalizedError { case packageDescriptionError(_ description: String) case couldNotGeneratePackageDescription @@ -23,24 +28,27 @@ enum SwiftPackageFileHelperError: LocalizedError { } } -struct SwiftPackageFileHelper { +package struct SwiftPackageFileHelper { private let fileHandler: FileHandling - private let xcodeTools: XcodeTools + private let shell: any ShellHandling + private let logger: (any Logging)? - init( + package init( fileHandler: FileHandling, - xcodeTools: XcodeTools + shell: any ShellHandling, + logger: (any Logging)? ) { self.fileHandler = fileHandler - self.xcodeTools = xcodeTools + self.shell = shell + self.logger = logger } - static func packagePath(for projectDirectoryPath: String) -> String { + package static func packagePath(for projectDirectoryPath: String) -> String { projectDirectoryPath.appending("/Package.swift") } - func availableTargets( + package func availableTargets( at projectDirectoryPath: String, moduleType: SwiftPackageDescription.Target.ModuleType? = nil, targetType: SwiftPackageDescription.Target.TargetType? = nil @@ -59,12 +67,12 @@ struct SwiftPackageFileHelper { return Set(targets.map(\.name)) } - func packageDescription(at projectDirectoryPath: String) throws -> SwiftPackageDescription { + package func packageDescription(at projectDirectoryPath: String) throws -> SwiftPackageDescription { try generatePackageDescription(at: projectDirectoryPath) } /// Inserts a new library into the targets section containing all targets from the target section - func preparePackageWithConsolidatedLibrary( + package func preparePackageWithConsolidatedLibrary( named consolidatedLibraryName: String, at projectDirectoryPath: String ) throws { @@ -93,7 +101,7 @@ private extension SwiftPackageFileHelper { func generatePackageDescription(at projectDirectoryPath: String) throws -> SwiftPackageDescription { - let result = try xcodeTools.loadPackageDescription(projectDirectoryPath: projectDirectoryPath) + let result = try loadPackageDescription(projectDirectoryPath: projectDirectoryPath) let newLine = "\n" let errorTag = "error: " @@ -133,6 +141,17 @@ private extension SwiftPackageFileHelper { throw SwiftPackageFileHelperError.couldNotGeneratePackageDescription } + func loadPackageDescription( + projectDirectoryPath: String + ) throws -> String { + let command = [ + "cd \(projectDirectoryPath);", + "swift package describe --type json" + ] + + return shell.execute(command.joined(separator: " ")) + } + func decodePackageDescription(from packageDescriptionData: Data, warnings: [String]) throws -> SwiftPackageDescription { var packageDescription = try JSONDecoder().decode(SwiftPackageDescription.self, from: packageDescriptionData) packageDescription.warnings = warnings diff --git a/Sources/Helpers/Models/Change.swift b/Sources/Shared/Public/PADCore/PADChange.swift similarity index 63% rename from Sources/Helpers/Models/Change.swift rename to Sources/Shared/Public/PADCore/PADChange.swift index 9fd9bac..5b8d885 100644 --- a/Sources/Helpers/Models/Change.swift +++ b/Sources/Shared/Public/PADCore/PADChange.swift @@ -7,22 +7,32 @@ import Foundation /// A change indicating an `addition`, `removal` or genuine `change` of an element -struct Change: Equatable { - enum ChangeType: Equatable { +public struct Change: Equatable { + public enum ChangeType: Equatable { case addition(description: String) case removal(description: String) case change(oldDescription: String, newDescription: String) } - var changeType: ChangeType - var parentName: String + public private(set) var changeType: ChangeType + public private(set) var parentPath: String? - var listOfChanges: [String] = [] + public private(set) var listOfChanges: [String] = [] + + public init( + changeType: ChangeType, + parentPath: String? = nil, + listOfChanges: [String] = [] + ) { + self.changeType = changeType + self.parentPath = parentPath + self.listOfChanges = listOfChanges + } } extension Change.ChangeType { - var isAddition: Bool { + public var isAddition: Bool { switch self { case .addition: return true @@ -33,7 +43,7 @@ extension Change.ChangeType { } } - var isRemoval: Bool { + public var isRemoval: Bool { switch self { case .addition: return false @@ -44,7 +54,7 @@ extension Change.ChangeType { } } - var isChange: Bool { + public var isChange: Bool { switch self { case .addition: return false @@ -55,14 +65,3 @@ extension Change.ChangeType { } } } - -extension [String: [Change]] { - - var totalChangeCount: Int { - var totalChangeCount = 0 - keys.forEach { targetName in - totalChangeCount += self[targetName]?.count ?? 0 - } - return totalChangeCount - } -} diff --git a/Sources/Shared/Public/PADCore/PADSwiftInterfaceFile.swift b/Sources/Shared/Public/PADCore/PADSwiftInterfaceFile.swift new file mode 100644 index 0000000..2bb689d --- /dev/null +++ b/Sources/Shared/Public/PADCore/PADSwiftInterfaceFile.swift @@ -0,0 +1,22 @@ +import Foundation + +/// A representation of 2 versions of a `.swiftinterface` file +public struct SwiftInterfaceFile { + /// The name of the target/scheme that is represented in the `.swiftinterface` file + public let name: String + /// The file path to the old/reference `.swiftinterface` + public let oldFilePath: String + /// The file path to the new/updated `.swiftinterface` + public let newFilePath: String + + /// Creates a new instance of a ``SwiftInterfaceFile`` + public init( + name: String, + oldFilePath: String, + newFilePath: String + ) { + self.name = name + self.oldFilePath = oldFilePath + self.newFilePath = newFilePath + } +} diff --git a/Sources/Shared/Public/PADLogging/PADLogFileLogger.swift b/Sources/Shared/Public/PADLogging/PADLogFileLogger.swift new file mode 100644 index 0000000..fa835a0 --- /dev/null +++ b/Sources/Shared/Public/PADLogging/PADLogFileLogger.swift @@ -0,0 +1,41 @@ +import Foundation +import FileHandlingModule + +/// Logs into a log file at a specified output path +public 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) + } + } + + /// Creates a new instance that targets the specified output path + public convenience init(outputFilePath: String) { + self.init(fileHandler: FileManager.default, outputFilePath: outputFilePath) + } + + init( + fileHandler: any FileHandling, + outputFilePath: String + ) { + self.fileHandler = fileHandler + self.outputFilePath = outputFilePath + } + + public func log(_ message: String, from subsystem: String) { + Task { @MainActor in + output += ["πŸͺ΅ [\(subsystem)] \(message)\n"] + } + } + + public func debug(_ message: String, from subsystem: String) { + Task { @MainActor in + output += ["🐞 [\(subsystem)] \(message)\n"] + } + } +} diff --git a/Sources/Shared/Public/PADLogging/PADLogLevelLogger.swift b/Sources/Shared/Public/PADLogging/PADLogLevelLogger.swift new file mode 100644 index 0000000..f5cc021 --- /dev/null +++ b/Sources/Shared/Public/PADLogging/PADLogLevelLogger.swift @@ -0,0 +1,67 @@ +import Foundation +import OSLog + +/// A log level specifying the granularity of the emitted logs +public enum LogLevel { + /// No logs + case quiet + /// All logs except `debug` + case `default` + /// All logs + 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 + } + } +} + +// MARK: - LogLevelLogger + +/// Logger that respects a ``LogLevel`` +public struct LogLevelLogger: Logging { + + private let logLevel: LogLevel + internal let wrappedLogger: LoggerType + + init(with logger: LoggerType, logLevel: LogLevel) { + self.wrappedLogger = logger + self.logLevel = logLevel + } + + public func log(_ message: String, from subsystem: String) { + guard logLevel.shouldLog else { return } + wrappedLogger.log("\(message)", from: subsystem) + } + + public func debug(_ message: String, from subsystem: String) { + guard logLevel.shouldDebugLog else { return } + wrappedLogger.debug("\(message)", from: subsystem) + } +} + +// MARK: - Logging Extension + +extension Logging { + /// Wraps a logger into a ``LogLevelLogger`` to make them respect the ``LogLevel`` + public func withLogLevel(_ logLevel: LogLevel) -> LogLevelLogger { + .init(with: self, logLevel: logLevel) + } +} diff --git a/Sources/Shared/Public/PADLogging/PADLogging.swift b/Sources/Shared/Public/PADLogging/PADLogging.swift new file mode 100644 index 0000000..6874de7 --- /dev/null +++ b/Sources/Shared/Public/PADLogging/PADLogging.swift @@ -0,0 +1,9 @@ +import Foundation + +/// Specifying the logger interface +public protocol Logging { + /// Logs a message marked as `log` + func log(_ message: String, from subsystem: String) + /// Logs a message marked as `debug` + func debug(_ message: String, from subsystem: String) +} diff --git a/Sources/Shared/Public/PADLogging/PADLoggingGroup.swift b/Sources/Shared/Public/PADLogging/PADLoggingGroup.swift new file mode 100644 index 0000000..d2de3f4 --- /dev/null +++ b/Sources/Shared/Public/PADLogging/PADLoggingGroup.swift @@ -0,0 +1,19 @@ +import Foundation + +/// A group of loggers +public struct LoggingGroup: Logging { + + let logger: [any Logging] + + public init(with logger: [any Logging]) { + self.logger = logger + } + + public func log(_ message: String, from subsystem: String) { + logger.forEach { $0.log(message, from: subsystem) } + } + + public func debug(_ message: String, from subsystem: String) { + logger.forEach { $0.debug(message, from: subsystem) } + } +} diff --git a/Sources/Shared/Public/PADLogging/PADSystemLogger.swift b/Sources/Shared/Public/PADLogging/PADSystemLogger.swift new file mode 100644 index 0000000..a4bdd32 --- /dev/null +++ b/Sources/Shared/Public/PADLogging/PADSystemLogger.swift @@ -0,0 +1,26 @@ +import Foundation +import OSLog + +/// A logger that outputs logs to the console +public struct SystemLogger: Logging { + + public init() {} + + public func log(_ message: String, from subsystem: String) { + logger(for: subsystem).log("\(message)") + } + + public func debug(_ message: String, from subsystem: String) { + logger(for: subsystem).debug("\(message)") + } +} + +private extension SystemLogger { + + func logger(for subsystem: String) -> Logger { + Logger( + subsystem: subsystem, + category: "" // TODO: Pass the description/tag so it can be differentiated + ) + } +} diff --git a/Sources/public-api-diff.swift b/Sources/public-api-diff.swift deleted file mode 100644 index 54847d4..0000000 --- a/Sources/public-api-diff.swift +++ /dev/null @@ -1,86 +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 ArgumentParser -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 - - @Option(help: "Specify the old version to compare to") - public var old: String - - @Option(help: "Where to output the result (File path)") - public var output: 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 - - 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, - oldSource: oldSource, - scheme: scheme, - workingDirectoryPath: workingDirectoryPath, - fileHandler: fileHandler, - logger: logger - ) - - if let output { - try fileHandler.write(pipelineOutput, 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) - } - } -} - -internal extension Pipeline { - - 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 Pipeline( - newProjectSource: newSource, - oldProjectSource: oldSource, - scheme: scheme, - projectBuilder: ProjectBuilder(baseWorkingDirectoryPath: workingDirectoryPath, logger: logger), - abiGenerator: ABIGenerator(logger: logger), - projectAnalyzer: SwiftPackageFileAnalyzer(), - sdkDumpGenerator: SDKDumpGenerator(), - sdkDumpAnalyzer: SDKDumpAnalyzer(), - outputGenerator: MarkdownOutputGenerator(), - logger: logger - ).run() - } -} diff --git a/Tests/IntegrationTests/ReferencePackageTests.swift b/Tests/IntegrationTests/ReferencePackageTests.swift index b0e73d6..34a39cd 100644 --- a/Tests/IntegrationTests/ReferencePackageTests.swift +++ b/Tests/IntegrationTests/ReferencePackageTests.swift @@ -4,51 +4,89 @@ // This file is open source and available under the MIT license. See the LICENSE file for more info. // -@testable import public_api_diff +@testable import PADProjectBuilder +@testable import PADOutputGenerator +@testable import PADSwiftInterfaceDiff +@testable import PADCore import XCTest class ReferencePackageTests: XCTestCase { - func test_defaultPipeline() async throws { + override func setUp() 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 + 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 referencePackagesRoot = URL(filePath: String(projectRoot)).appending(path: "ReferencePackages") + let xcodeTools = XcodeTools(logger: nil) - let oldReferencePackageDirectory = referencePackagesRoot.appending(path: "ReferencePackage") - let newReferencePackageDirectory = referencePackagesRoot.appending(path: "UpdatedPackage") + _ = 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() { + + 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 - 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 fileHandler: FileHandling = FileManager.default - let logger: any Logging = PipelineLogger(logLevel: .debug) - - let currentDirectory = fileHandler.currentDirectoryPath - let workingDirectoryPath = currentDirectory.appending("/tmp-public-api-diff") - - 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 expectedOutput = try expectedOutput(for: interfaceType) + let pipelineOutput = try await runPipeline(for: interfaceType) + + let markdownOutput = MarkdownOutputGenerator().generate( + from: pipelineOutput, + allTargets: ["ReferencePackage"], + oldVersionName: "old_public", + newVersionName: "new_public", + warnings: [] ) let expectedLines = sanitizeOutput(expectedOutput).components(separatedBy: "\n") - let pipelineOutputLines = sanitizeOutput(pipelineOutput).components(separatedBy: "\n") + let markdownOutputLines = sanitizeOutput(markdownOutput).components(separatedBy: "\n") for i in 0.. 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` + + 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: + "\(XcodeTools.Constants.derivedDataPath)/Build/Products/Debug-iphoneos/ReferencePackage.swiftmodule/arm64-apple-ios.swiftinterface" + case .private: + "\(XcodeTools.Constants.derivedDataPath)/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 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)) + return interfaceFilePath.path() + } + + func runPipeline(for interfaceType: InterfaceType) async throws -> [String: [Change]] { + + let referencePackagesRoot = try Self.referencePackagesPath() + + let oldPrivateSwiftInterfaceFilePath = try swiftInterfaceFilePath( + for: referencePackagesRoot, + packageName: "ReferencePackage", + interfaceType: interfaceType + ) + + let newPrivateSwiftInterfaceFilePath = try swiftInterfaceFilePath( + for: referencePackagesRoot, + packageName: "UpdatedPackage", + interfaceType: interfaceType + ) + + let interfaceFiles = [ + SwiftInterfaceFile( + name: "ReferencePackage", + oldFilePath: oldPrivateSwiftInterfaceFilePath, + newFilePath: newPrivateSwiftInterfaceFilePath + ) + ] + + return try await SwiftInterfaceDiff( + fileHandler: FileManager.default, + swiftInterfaceParser: SwiftInterfaceParser(), + swiftInterfaceAnalyzer: SwiftInterfaceAnalyzer(), + logger: nil + ).run(with: interfaceFiles) + } + /// Removes the 2nd line that contains local file paths + empty newline at the end of the content if it exists func sanitizeOutput(_ output: String) -> String { var lines = output.components(separatedBy: "\n") 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..e4eb7a8 --- /dev/null +++ b/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-private.md @@ -0,0 +1,455 @@ +# πŸ‘€ 54 public changes detected +_Comparing `new_private` to `old_private`_ + +--- +## `ReferencePackage` +#### ❇️ Added +```javascript +public enum RawValueEnum: Swift.String, Swift.Equatable, Swift.Hashable, Swift.RawRepresentable +{ + 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 + +/** +Changes: +- Added inheritance `ReferencePackage.SimpleProtocol` +*/ +``` +```javascript +// From +@_spi(SystemProgrammingInterface) open class OpenSpiConformingClass: ReferencePackage.CustomProtocol + +// 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: ReferencePackage.SimpleProtocol + +/** +Changes: +- Added generic parameter description `` +- Added inheritance `ReferencePackage.SimpleProtocol` +*/ +``` +```javascript +// From +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 +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 } +} + +``` +### `CustomClass` +#### ❇️ Added +```javascript +final public let a: Swift.Int { get } + +``` +```javascript +final public let b: Swift.Int { get } + +``` +```javascript +final public let c: Swift.Int { get } + +``` +```javascript +final public let d: Swift.Double { get } + +``` +```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 + +/** +Changes: +- Added generic parameter description `` +- Added generic where clause `where Element : Swift.Strideable` +- Added parameter `_ element: Element` +*/ +``` +```javascript +// From +convenience public init(value: T) + +// To +convenience public init!(value: T) + +/** +Changes: +- Added optional mark `!` +*/ +``` +```javascript +// From +public init() + +// To +public init?() + +/** +Changes: +- Added optional mark `?` +*/ +``` +### `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 +public struct NestedStructInExtension +{ + public let string: Swift.String { get } + public init(string: Swift.String = "Hello") +} + +``` +#### πŸ”€ Changed +```javascript +// From +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 +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) +``` +### `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 + +/** +Changes: +- Changed return type from `any Swift.Equatable` to `Self.CustomAssociatedType` +*/ +``` +```javascript +// From +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 +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 +``` +### `CustomStruct` +#### ❇️ Added +```javascript +@available(macOS, unavailable, message: "Unavailable on macOS") public struct NestedStruct +{ + @available(*, deprecated, renamed: "nestedVar") public let nestedLet: Swift.String { get } + @available(swift 5.9) public let nestedVar: Swift.String { get } +} + +``` +```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 + +/** +Changes: +- Changed return type from `any Swift.Equatable` to `Swift.Int` +*/ +``` +```javascript +// From +public var getSetVar: any Swift.Equatable + +// To +public var getSetVar: Swift.Double + +/** +Changes: +- Changed type from `any Swift.Equatable` to `Swift.Double` +*/ +``` +```javascript +// From +public var getVar: any Swift.Equatable + +// To +public var getVar: Swift.Int + +/** +Changes: +- Changed type from `any Swift.Equatable` to `Swift.Int` +*/ +``` +### `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 + +/** +Changes: +- Changed return type from `ReferencePackage.OpenSpiConformingClass.CustomAssociatedType` to `T` +*/ +``` +```javascript +// From +@_spi(SystemProgrammingInterface) public init(getSetVar: ReferencePackage.OpenSpiConformingClass.CustomAssociatedType, getVar: ReferencePackage.OpenSpiConformingClass.CustomAssociatedType) + +// 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 +@_spi(SystemProgrammingInterface) public typealias CustomAssociatedType = any Swift.Equatable + +// To +@_spi(SystemProgrammingInterface) public typealias CustomAssociatedType = T + +/** +Changes: +- Changed assignment from `any Swift.Equatable` to `T` +*/ +``` +```javascript +// From +@_spi(SystemProgrammingInterface) public var getSetVar: ReferencePackage.OpenSpiConformingClass.CustomAssociatedType + +// To +@_spi(SystemProgrammingInterface) public var getSetVar: T + +/** +Changes: +- Changed type from `ReferencePackage.OpenSpiConformingClass.CustomAssociatedType` to `T` +*/ +``` +```javascript +// From +@_spi(SystemProgrammingInterface) public var getVar: ReferencePackage.OpenSpiConformingClass.CustomAssociatedType + +// To +@_spi(SystemProgrammingInterface) public var getVar: T + +/** +Changes: +- Changed type from `ReferencePackage.OpenSpiConformingClass.CustomAssociatedType` to `T` +*/ +``` + +--- +**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..7d00b8f --- /dev/null +++ b/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-public.md @@ -0,0 +1,364 @@ +# πŸ‘€ 45 public changes detected +_Comparing `new_public` to `old_public`_ + +--- +## `ReferencePackage` +#### ❇️ Added +```javascript +public enum RawValueEnum: Swift.String, Swift.Equatable, Swift.Hashable, Swift.RawRepresentable +{ + 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 + +/** +Changes: +- Added inheritance `ReferencePackage.SimpleProtocol` +*/ +``` +```javascript +// From +public enum CustomEnum + +// To +public enum CustomEnum: ReferencePackage.SimpleProtocol + +/** +Changes: +- Added generic parameter description `` +- Added inheritance `ReferencePackage.SimpleProtocol` +*/ +``` +```javascript +// From +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 +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 } +} + +``` +### `CustomClass` +#### ❇️ Added +```javascript +final public let a: Swift.Int { get } + +``` +```javascript +final public let b: Swift.Int { get } + +``` +```javascript +final public let c: Swift.Int { get } + +``` +```javascript +final public let d: Swift.Double { get } + +``` +```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 + +/** +Changes: +- Added generic parameter description `` +- Added generic where clause `where Element : Swift.Strideable` +- Added parameter `_ element: Element` +*/ +``` +```javascript +// From +convenience public init(value: T) + +// To +convenience public init!(value: T) + +/** +Changes: +- Added optional mark `!` +*/ +``` +```javascript +// From +public init() + +// To +public init?() + +/** +Changes: +- Added optional mark `?` +*/ +``` +### `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 +public struct NestedStructInExtension +{ + public let string: Swift.String { get } + public init(string: Swift.String = "Hello") +} + +``` +#### πŸ”€ Changed +```javascript +// From +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 +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) +``` +### `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 + +/** +Changes: +- Changed return type from `any Swift.Equatable` to `Self.CustomAssociatedType` +*/ +``` +```javascript +// From +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 +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 +``` +### `CustomStruct` +#### ❇️ Added +```javascript +@available(macOS, unavailable, message: "Unavailable on macOS") public struct NestedStruct +{ + @available(*, deprecated, renamed: "nestedVar") public let nestedLet: Swift.String { get } + @available(swift 5.9) public let nestedVar: Swift.String { get } +} + +``` +```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 + +/** +Changes: +- Changed return type from `any Swift.Equatable` to `Swift.Int` +*/ +``` +```javascript +// From +public var getSetVar: any Swift.Equatable + +// To +public var getSetVar: Swift.Double + +/** +Changes: +- Changed type from `any Swift.Equatable` to `Swift.Double` +*/ +``` +```javascript +// From +public var getVar: any Swift.Equatable + +// To +public var getVar: Swift.Int + +/** +Changes: +- Changed type from `any Swift.Equatable` to `Swift.Int` +*/ +``` + +--- +**Analyzed targets:** ReferencePackage 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/FileHandlingTests.swift b/Tests/UnitTests/FileHandlingTests.swift index e9f3066..8a067ca 100644 --- a/Tests/UnitTests/FileHandlingTests.swift +++ b/Tests/UnitTests/FileHandlingTests.swift @@ -4,7 +4,7 @@ // This file is open source and available under the MIT license. See the LICENSE file for more info. // -@testable import public_api_diff +@testable import FileHandlingModule import XCTest class FileHandlingTests: XCTestCase { diff --git a/Tests/UnitTests/GitTests.swift b/Tests/UnitTests/GitTests.swift index fad008a..4fda4d8 100644 --- a/Tests/UnitTests/GitTests.swift +++ b/Tests/UnitTests/GitTests.swift @@ -4,7 +4,7 @@ // This file is open source and available under the MIT license. See the LICENSE file for more info. // -@testable import public_api_diff +@testable import PADProjectBuilder import XCTest class GitTests: XCTestCase { @@ -21,7 +21,7 @@ class GitTests: XCTestCase { } let mockFileHandler = MockFileHandler(handleFileExists: { _ in true }) - var mockLogger = MockLogger(logLevel: .default) + var mockLogger = MockLogger() mockLogger.handleLog = { message, subsystem in XCTAssertEqual(message, "🐱 Cloning repository @ branch into targetDirectoryPath") XCTAssertEqual(subsystem, "Git") @@ -43,7 +43,7 @@ class GitTests: XCTestCase { } let mockFileHandler = MockFileHandler(handleFileExists: { _ in false }) - var mockLogger = MockLogger(logLevel: .default) + var mockLogger = MockLogger() mockLogger.handleLog = { message, subsystem in XCTAssertEqual(message, "🐱 Cloning repository @ branch into targetDirectoryPath") XCTAssertEqual(subsystem, "Git") diff --git a/Tests/UnitTests/LoggerTests.swift b/Tests/UnitTests/LoggerTests.swift new file mode 100644 index 0000000..b997ca7 --- /dev/null +++ b/Tests/UnitTests/LoggerTests.swift @@ -0,0 +1,81 @@ +// +// 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 PADLogging +import XCTest + +class LoggerTests: XCTestCase { + + func test_logLevels() async throws { + + var logger = MockLogger() + + // .quiet + + logger.handleLog = { _, _ in XCTFail(".handleLog should not be called") } + logger.handleDebug = { _, _ in XCTFail(".handleDebug should not be called") } + logger.withLogLevel(.quiet).log("log", from: "quiet") + logger.withLogLevel(.quiet).debug("debug", from: "quiet") + + // .default + + logger.handleLog = { message, subsystem in + XCTAssertEqual(message, "log") + XCTAssertEqual(subsystem, "default") + } + logger.handleDebug = { _, _ in XCTFail(".handleDebug should not be called") } + logger.withLogLevel(.default).log("log", from: "default") + logger.withLogLevel(.default).debug("debug", from: "default") + + // .debug + + logger.handleLog = { message, subsystem in + XCTAssertEqual(message, "log") + XCTAssertEqual(subsystem, "debug") + } + logger.handleDebug = { message, subsystem in + XCTAssertEqual(message, "debug") + XCTAssertEqual(subsystem, "debug") + } + logger.withLogLevel(.debug).log("log", from: "debug") + logger.withLogLevel(.debug).debug("debug", from: "debug") + } + + func test_logFileLogger() async throws { + + let outputFilePath = "output_file_path" + + let removeExpectation = expectation(description: "remove was called twice") + removeExpectation.expectedFulfillmentCount = 2 + + var expectedHandleCreateFileCalls = [ + "πŸͺ΅ [test] log\n", + "πŸͺ΅ [test] log\n\n🐞 [test] debug\n" + ] + + var fileHandler = MockFileHandler() + fileHandler.handleRemoveItem = { path in + XCTAssertEqual(path, outputFilePath) + removeExpectation.fulfill() + } + fileHandler.handleCreateFile = { path, data in + XCTAssertEqual(path, outputFilePath) + let expectedInput = expectedHandleCreateFileCalls.removeFirst() + XCTAssertEqual(String(data: data, encoding: .utf8), expectedInput) + return true + } + + let logFileLogger = LogFileLogger(fileHandler: fileHandler, outputFilePath: outputFilePath) + + logFileLogger.log("log", from: "test") + // Small sleep because the file manager calls are done on a detached Task and we want to guarantee the order + try await Task.sleep(for: .milliseconds(10)) + logFileLogger.debug("debug", from: "test") + + await fulfillment(of: [removeExpectation]) + XCTAssertTrue(expectedHandleCreateFileCalls.isEmpty) + } +} diff --git a/Tests/UnitTests/OutputGeneratorTests.swift b/Tests/UnitTests/OutputGeneratorTests.swift index 2f69f39..26e8bc4 100644 --- a/Tests/UnitTests/OutputGeneratorTests.swift +++ b/Tests/UnitTests/OutputGeneratorTests.swift @@ -4,7 +4,7 @@ // This file is open source and available under the MIT license. See the LICENSE file for more info. // -@testable import public_api_diff +@testable import PADOutputGenerator import XCTest class OutputGeneratorTests: XCTestCase { @@ -23,8 +23,8 @@ class OutputGeneratorTests: XCTestCase { let output = outputGenerator.generate( from: [:], allTargets: ["Target_1"], - oldSource: .local(path: "old_source"), - newSource: .local(path: "new_source"), + oldVersionName: "old_source", + newVersionName: "new_source", warnings: [] ) XCTAssertEqual(output, expectedOutput) @@ -50,10 +50,10 @@ class OutputGeneratorTests: XCTestCase { let outputGenerator = MarkdownOutputGenerator() let output = outputGenerator.generate( - from: ["Target_1": [.init(changeType: .addition(description: "Some Addition"), parentName: "")]], + from: ["Target_1": [.init(changeType: .addition(description: "Some Addition"), parentPath: "")]], allTargets: ["Target_1"], - oldSource: .local(path: "old_source"), - newSource: .local(path: "new_source"), + oldVersionName: "old_source", + newVersionName: "new_source", warnings: [] ) XCTAssertEqual(output, expectedOutput) @@ -94,17 +94,17 @@ class OutputGeneratorTests: XCTestCase { let output = outputGenerator.generate( from: [ "Target_1": [ - .init(changeType: .addition(description: "Some Addition"), parentName: ""), - .init(changeType: .removal(description: "Some Removal"), parentName: "") + .init(changeType: .addition(description: "Some Addition"), parentPath: ""), + .init(changeType: .removal(description: "Some Removal"), parentPath: "") ], "Target_2": [ - .init(changeType: .addition(description: "Another Addition"), parentName: ""), - .init(changeType: .removal(description: "Another Removal"), parentName: "") + .init(changeType: .addition(description: "Another Addition"), parentPath: ""), + .init(changeType: .removal(description: "Another Removal"), parentPath: "") ] ], allTargets: ["Target_1", "Target_2"], - oldSource: .remote(branch: "old_branch", repository: "old_repository"), - newSource: .local(path: "new_source"), + oldVersionName: "old_repository @ old_branch", + newVersionName: "new_source", warnings: [] ) XCTAssertEqual(output, expectedOutput) diff --git a/Tests/UnitTests/PipelineTests.swift b/Tests/UnitTests/PipelineTests.swift index 0c32d3c..474bc96 100644 --- a/Tests/UnitTests/PipelineTests.swift +++ b/Tests/UnitTests/PipelineTests.swift @@ -4,141 +4,83 @@ // This file is open source and available under the MIT license. See the LICENSE file for more info. // -@testable import public_api_diff +@testable import PADSwiftInterfaceDiff +@testable import PADCore import XCTest class PipelineTests: XCTestCase { func test_pipeline() async throws { - let projectBuilderExpectation = expectation(description: "ProjectBuilder is called twice") - projectBuilderExpectation.expectedFulfillmentCount = 2 + let swiftInterfaceFile = SwiftInterfaceFile( + name: "MODULE_NAME", + oldFilePath: "old_file_path", + newFilePath: "new_file_path" + ) - let abiGeneratorExpectation = expectation(description: "ABIGenerator is called twice") - abiGeneratorExpectation.expectedFulfillmentCount = 2 + let expectedChanges: [Change] = [.init(changeType: .addition(description: "addition"))] + var expectedHandleLoadDataCalls = ["new_file_path", "old_file_path"] + var expectedHandleParseSourceCalls: [(source: String, moduleName: String)] = [ + ("content_for_new_file_path", "MODULE_NAME"), + ("content_for_old_file_path", "MODULE_NAME") + ] + var expectedHandleAnalyzeCalls: [(old: SwiftInterfaceParser.Root, new: SwiftInterfaceParser.Root)] = [ + (.init(moduleName: "MODULE_NAME", elements: []), .init(moduleName: "MODULE_NAME", elements: [])) + ] + var expectedHandleLogCalls: [(message: String, subsystem: String)] = [ + ("πŸ§‘β€πŸ”¬ Analyzing MODULE_NAME", "SwiftInterfaceDiff") + ] + let expectedPipelineOutput: [String: [Change]] = ["MODULE_NAME": expectedChanges] - let projectAnalyzerExpectation = expectation(description: "ProjectAnalyzer is called once") + // Mock Setup - let dumpGeneratorExpectation = expectation(description: "SDKDumpGenerator is called twice") - dumpGeneratorExpectation.expectedFulfillmentCount = 2 + var fileHandler = MockFileHandler() + fileHandler.handleLoadData = { path in + let expectedInput = expectedHandleLoadDataCalls.removeFirst() + XCTAssertEqual(path, expectedInput) + return try XCTUnwrap(String("content_for_\(path)").data(using: .utf8)) + } - let dumpAnalyzerExpectation = expectation(description: "SDKDumpAnalyzer is called once") + var swiftInterfaceParser = MockSwiftInterfaceParser() + swiftInterfaceParser.handleParseSource = { source, moduleName in + let expectedInput = expectedHandleParseSourceCalls.removeFirst() + XCTAssertEqual(expectedInput.source, source) + XCTAssertEqual(expectedInput.moduleName, moduleName) + return SwiftInterfaceParser.Root(moduleName: moduleName, elements: []) + } - let oldProjectSource = ProjectSource.local(path: "old") - let newProjectSource = ProjectSource.local(path: "new") + var swiftInterfaceAnalyzer = MockSwiftInterfaceAnalyzer() + swiftInterfaceAnalyzer.handleAnalyze = { old, new in + let expectedInput = expectedHandleAnalyzeCalls.removeFirst() + XCTAssertEqual(old.recursiveDescription(), expectedInput.old.recursiveDescription()) + XCTAssertEqual(new.recursiveDescription(), expectedInput.new.recursiveDescription()) + return expectedChanges + } - 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"), parentName: "Parent")], - "Target": [Change(changeType: .addition(description: "Something was added"), parentName: "Parent")] - ], - ["Target"], - oldProjectSource, - newProjectSource, - - "Output" - ] + var logger = MockLogger() + logger.handleLog = { message, subsystem in + let expectedInput = expectedHandleLogCalls.removeFirst() + XCTAssertEqual(message, expectedInput.message) + XCTAssertEqual(subsystem, expectedInput.subsystem) + } - let pipeline = Pipeline( - 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" - ), - parentName: "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"), parentName: "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) - ) + // Pipeline run - let pipelineOutput = try await pipeline.run() + let pipeline = SwiftInterfaceDiff( + fileHandler: fileHandler, + swiftInterfaceParser: swiftInterfaceParser, + swiftInterfaceAnalyzer: swiftInterfaceAnalyzer, + logger: logger + ) - await fulfillment(of: [ - projectBuilderExpectation, - abiGeneratorExpectation, - projectAnalyzerExpectation, - dumpGeneratorExpectation, - dumpAnalyzerExpectation - ]) + let pipelineOutput = try await pipeline.run(with: [swiftInterfaceFile]) - XCTAssertEqual(pipelineOutput, expectedSteps.first as? String) - expectedSteps.removeFirst() + // Validation - XCTAssertEqual(expectedSteps.count, 0) + XCTAssertEqual(pipelineOutput, expectedPipelineOutput) + XCTAssertTrue(expectedHandleLoadDataCalls.isEmpty) + XCTAssertTrue(expectedHandleParseSourceCalls.isEmpty) + XCTAssertTrue(expectedHandleLogCalls.isEmpty) + XCTAssertTrue(expectedHandleAnalyzeCalls.isEmpty) } } diff --git a/Tests/UnitTests/ProjectBuilderTests.swift b/Tests/UnitTests/ProjectBuilderTests.swift deleted file mode 100644 index f0942cb..0000000 --- a/Tests/UnitTests/ProjectBuilderTests.swift +++ /dev/null @@ -1,91 +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 logger = MockLogger() - logger.handleLog = { message, subsystem in - XCTAssertEqual(message, "πŸ› οΈ Building project `\(localPath)` at\n`\(baseWorkingDirectoryPath)/\(randomString)`") - XCTAssertEqual(subsystem, "ProjectBuilder") - } - 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/ProjectSourceTests.swift b/Tests/UnitTests/ProjectSourceTests.swift index 29dc050..4da7aee 100644 --- a/Tests/UnitTests/ProjectSourceTests.swift +++ b/Tests/UnitTests/ProjectSourceTests.swift @@ -4,7 +4,7 @@ // This file is open source and available under the MIT license. See the LICENSE file for more info. // -@testable import public_api_diff +@testable import PADProjectBuilder import XCTest class ProjectSourceTests: XCTestCase { @@ -29,7 +29,7 @@ class ProjectSourceTests: XCTestCase { XCTAssertEqual( projectSource, - .remote(branch: branch, repository: repositoryUrl) + .git(branch: branch, repository: repositoryUrl) ) } @@ -51,11 +51,11 @@ class ProjectSourceTests: XCTestCase { ) XCTAssertNil(source) // Guard to make sure that we catch if it succeeds } catch { - let projectSourceError = try XCTUnwrap(error as? ProjectSourceError) + let projectSourceError = try XCTUnwrap(error as? ProjectSource.Error) XCTAssertEqual( projectSourceError, - ProjectSourceError.invalidSourceValue(value: rawProjectSourceValue) + ProjectSource.Error.invalidSourceValue(value: rawProjectSourceValue) ) } } @@ -78,11 +78,11 @@ class ProjectSourceTests: XCTestCase { ) XCTAssertNil(source) // Guard to make sure that we catch if it succeeds } catch { - let projectSourceError = try XCTUnwrap(error as? ProjectSourceError) + let projectSourceError = try XCTUnwrap(error as? ProjectSource.Error) XCTAssertEqual( projectSourceError, - ProjectSourceError.invalidSourceValue(value: rawProjectSourceValue) + ProjectSource.Error.invalidSourceValue(value: rawProjectSourceValue) ) } } 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