diff --git a/.sourcery-macOS.yml b/.sourcery-macOS.yml new file mode 100644 index 000000000..9218d92af --- /dev/null +++ b/.sourcery-macOS.yml @@ -0,0 +1,10 @@ +sources: + - SourceryRuntime/Sources/Common + - SourceryRuntime/Sources/macOS +templates: + - Sourcery/Templates/Coding.stencil + - Sourcery/Templates/JSExport.ejs + - Sourcery/Templates/Typed.stencil + - Sourcery/Templates/TypedSpec.stencil +output: + SourceryRuntime/Sources/Generated diff --git a/.sourcery-ubuntu.yml b/.sourcery-ubuntu.yml new file mode 100644 index 000000000..c797c0ab2 --- /dev/null +++ b/.sourcery-ubuntu.yml @@ -0,0 +1,10 @@ +sources: + - SourceryRuntime/Sources/Common + - SourceryRuntime/Sources/Linux +templates: + - Sourcery/Templates/Coding.stencil + - Sourcery/Templates/JSExport.ejs + - Sourcery/Templates/Typed.stencil + - Sourcery/Templates/TypedSpec.stencil +output: + SourceryRuntime/Sources/Generated diff --git a/.sourcery.yml b/.sourcery.yml deleted file mode 100644 index 3133e272f..000000000 --- a/.sourcery.yml +++ /dev/null @@ -1,6 +0,0 @@ -sources: - - SourceryRuntime/Sources -templates: - - Sourcery/Templates -output: - SourceryRuntime/Sources/Generated diff --git a/Rakefile b/Rakefile index 84caa905d..558f0f29d 100644 --- a/Rakefile +++ b/Rakefile @@ -87,12 +87,14 @@ end task :run_sourcery do print_info "Generating internal boilerplate code" - sh "#{CLI_DIR}bin/sourcery" + sh "#{CLI_DIR}bin/sourcery --config .sourcery-macOS.yml" + sh "#{CLI_DIR}bin/sourcery --config .sourcery-ubuntu.yml" end desc "Update internal boilerplate code" -task :generate_internal_boilerplate_code => [:fat_build, :run_sourcery, :clean] do - sh "Scripts/package_content \"SourceryRuntime/Sources\" > \"SourcerySwift/Sources/SourceryRuntime.content.generated.swift\"" +task :generate_internal_boilerplate_code => [:build, :run_sourcery] do + sh "Scripts/package_content \"SourceryRuntime/Sources/Common,SourceryRuntime/Sources/macOS,SourceryRuntime/Sources/Generated\" \"true\" > \"SourcerySwift/Sources/SourceryRuntime.content.generated.swift\"" + sh "Scripts/package_content \"SourceryRuntime/Sources/Common,SourceryRuntime/Sources/Linux,SourceryRuntime/Sources/Generated\" \"false\" > \"SourcerySwift/Sources/SourceryRuntime_Linux.content.generated.swift\"" generated_files = `git status --porcelain` .split("\n") .select { |item| item.include?('.generated.') } diff --git a/Scripts/package_content b/Scripts/package_content index 8810f8f9a..6addd3b5f 100755 --- a/Scripts/package_content +++ b/Scripts/package_content @@ -4,7 +4,8 @@ /// Merge all Swift files contained in FOLDER into swift code that can be used by the FolderSynchronizer. /// Example: $0 Sources/SourceryRuntime > file.swift /// Options: -/// FOLDER: the path where the Swift files to merge are +/// FOLDERS: the paths where the Swift files to merge are, separated with comma "," +/// isForDarwinPlatform: if true, the generated code will be compilable on Darwin platforms /// -h: Display this help message import Foundation @@ -40,37 +41,45 @@ extension String { } } -func package(folder folderPath: String) throws { +func package(folders folderPaths: [String], isForDarwinPlatform: Bool) throws { + if !isForDarwinPlatform { + print("#if !canImport(ObjectiveC)") + } else { + print("#if canImport(ObjectiveC)") + } print("let sourceryRuntimeFiles: [FolderSynchronizer.File] = [") - let folderURL = URL(fileURLWithPath: folderPath) + for folderPath in folderPaths { + let folderURL = URL(fileURLWithPath: folderPath) - guard let enumerator = FileManager.default.enumerator(at: folderURL, includingPropertiesForKeys: [.isRegularFileKey], options: [.skipsHiddenFiles, .skipsPackageDescendants]) else { - print("Unable to retrieve file enumerator") - exit(1) - } - var files = [URL]() - for case let fileURL as URL in enumerator { - do { - let fileAttributes = try fileURL.resourceValues(forKeys:[.isRegularFileKey]) - if fileAttributes.isRegularFile! { - files.append(fileURL) + guard let enumerator = FileManager.default.enumerator(at: folderURL, includingPropertiesForKeys: [.isRegularFileKey], options: [.skipsHiddenFiles, .skipsPackageDescendants]) else { + print("Unable to retrieve file enumerator") + exit(1) + } + var files = [URL]() + for case let fileURL as URL in enumerator { + do { + let fileAttributes = try fileURL.resourceValues(forKeys:[.isRegularFileKey]) + if fileAttributes.isRegularFile! { + files.append(fileURL) + } + } catch { + print(error, fileURL) } - } catch { - print(error, fileURL) + } + + try files + .sorted(by: { $0.lastPathComponent < $1.lastPathComponent }) + .forEach { sourceFileURL in + print(" .init(name: \"\(sourceFileURL.lastPathComponent)\", content:") + print("\"\"\"") + let content = try String(contentsOf: sourceFileURL, encoding: .utf8) + .escapedSwiftTokens() + print(content) + print("\"\"\"),") } } - - try files - .sorted(by: { $0.lastPathComponent < $1.lastPathComponent }) - .forEach { sourceFileURL in - print(" .init(name: \"\(sourceFileURL.lastPathComponent)\", content:") - print("\"\"\"") - let content = try String(contentsOf: sourceFileURL, encoding: .utf8) - .escapedSwiftTokens() - print(content) - print("\"\"\"),") - } print("]") + print("#endif") } func main() { @@ -82,10 +91,16 @@ func main() { print("Missing folderPath argument") exit(1) } - let folder = CommandLine.arguments[1] + guard CommandLine.arguments.count > 2 else { + print("Missing isForDarwinPlatform argument") + exit(1) + } + let foldersPaths = CommandLine.arguments[1] + let isForDarwinPlatform = Bool(CommandLine.arguments[2]) ?? false + let folders = foldersPaths.split(separator: ",").map(String.init) do { - try package(folder: folder) + try package(folders: folders, isForDarwinPlatform: isForDarwinPlatform) } catch { print("Failed with error: \(error)") exit(1) diff --git a/Sourcery/Templates/JSExport.ejs b/Sourcery/Templates/JSExport.ejs index 8ef0e1f91..daacf1622 100644 --- a/Sourcery/Templates/JSExport.ejs +++ b/Sourcery/Templates/JSExport.ejs @@ -1,5 +1,6 @@ // swiftlint:disable vertical_whitespace trailing_newline +#if canImport(JavaScriptCore) import JavaScriptCore <%_ for (type of types.implementing.AutoJSExport) { -%> @@ -15,3 +16,4 @@ import JavaScriptCore extension <%= type.name %>: <%= type.name %>AutoJSExport {} <%_ } %> <%_ } %> +#endif \ No newline at end of file diff --git a/Sourcery/Templates/Typed.stencil b/Sourcery/Templates/Typed.stencil index dee50a053..5df972d8d 100644 --- a/Sourcery/Templates/Typed.stencil +++ b/Sourcery/Templates/Typed.stencil @@ -17,6 +17,8 @@ extension {{ type.name }} { {{ type.accessLevel }} var isClosure: Bool { return typeName.isClosure } /// Whether type is an array. Shorthand for `typeName.isArray` {{ type.accessLevel }} var isArray: Bool { return typeName.isArray } + /// Whether type is a set. Shorthand for `typeName.isSet` + {{ type.accessLevel }} var isSet: Bool { return typeName.isSet } /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` {{ type.accessLevel }} var isDictionary: Bool { return typeName.isDictionary } }{% endfor %} diff --git a/Sourcery/Templates/TypedSpec.stencil b/Sourcery/Templates/TypedSpec.stencil index 586f8e76d..49a985e41 100644 --- a/Sourcery/Templates/TypedSpec.stencil +++ b/Sourcery/Templates/TypedSpec.stencil @@ -28,6 +28,7 @@ class TypedSpec: QuickSpec { return variable?.typeName ?? TypeName(name: "") } +#if canImport(ObjectiveC) it("can report optional via KVC") { expect({{ type.name }}(typeName: typeName("Int?")).value(forKeyPath: "isOptional") as? Bool).to(equal(true)) expect({{ type.name }}(typeName: typeName("Int!")).value(forKeyPath: "isOptional") as? Bool).to(equal(true)) @@ -68,6 +69,7 @@ class TypedSpec: QuickSpec { sut.typeName.actualTypeName = typeName("Int") expect(sut.value(forKeyPath: "actualTypeName") as? TypeName).to(equal(typeName("Int"))) } +#endif } {% endfor %} } diff --git a/SourceryRuntime/Sources/AST/AccessLevel.swift b/SourceryRuntime/Sources/Common/AST/AccessLevel.swift similarity index 100% rename from SourceryRuntime/Sources/AST/AccessLevel.swift rename to SourceryRuntime/Sources/Common/AST/AccessLevel.swift diff --git a/SourceryRuntime/Sources/AST/Actor.swift b/SourceryRuntime/Sources/Common/AST/Actor.swift similarity index 91% rename from SourceryRuntime/Sources/AST/Actor.swift rename to SourceryRuntime/Sources/Common/AST/Actor.swift index 0d5e22832..2c6b20dba 100644 --- a/SourceryRuntime/Sources/AST/Actor.swift +++ b/SourceryRuntime/Sources/Common/AST/Actor.swift @@ -11,7 +11,7 @@ public final class Actor: Type { /// Whether type is final public var isFinal: Bool { - return modifiers.contains { $0.name == "final" } + modifiers.contains { $0.name == "final" } } /// :nodoc: @@ -54,11 +54,12 @@ public final class Actor: Type { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = super.description - string += ", " - string += "kind = \(String(describing: self.kind)), " - string += "isFinal = \(String(describing: self.isFinal))" + string.append(", ") + string.append("kind = \(String(describing: self.kind)), ") + string.append("isFinal = \(String(describing: self.isFinal))") return string } @@ -72,6 +73,8 @@ public final class Actor: Type { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(super.hash) diff --git a/SourceryRuntime/Sources/AST/Annotations.swift b/SourceryRuntime/Sources/Common/AST/Annotations.swift similarity index 100% rename from SourceryRuntime/Sources/AST/Annotations.swift rename to SourceryRuntime/Sources/Common/AST/Annotations.swift diff --git a/SourceryRuntime/Sources/AST/Attribute.swift b/SourceryRuntime/Sources/Common/AST/Attribute.swift similarity index 99% rename from SourceryRuntime/Sources/AST/Attribute.swift rename to SourceryRuntime/Sources/Common/AST/Attribute.swift index 4120f7974..4a80be35e 100644 --- a/SourceryRuntime/Sources/AST/Attribute.swift +++ b/SourceryRuntime/Sources/Common/AST/Attribute.swift @@ -166,6 +166,8 @@ public class Attribute: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJ return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) diff --git a/SourceryRuntime/Sources/AST/Class.swift b/SourceryRuntime/Sources/Common/AST/Class.swift similarity index 91% rename from SourceryRuntime/Sources/AST/Class.swift rename to SourceryRuntime/Sources/Common/AST/Class.swift index fe955e399..10d5acce0 100644 --- a/SourceryRuntime/Sources/AST/Class.swift +++ b/SourceryRuntime/Sources/Common/AST/Class.swift @@ -10,7 +10,7 @@ public final class Class: Type { /// Whether type is final public var isFinal: Bool { - return modifiers.contains { $0.name == "final" } + modifiers.contains { $0.name == "final" } } /// :nodoc: @@ -53,11 +53,12 @@ public final class Class: Type { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = super.description - string += ", " - string += "kind = \(String(describing: self.kind)), " - string += "isFinal = \(String(describing: self.isFinal))" + string.append(", ") + string.append("kind = \(String(describing: self.kind)), ") + string.append("isFinal = \(String(describing: self.isFinal))") return string } @@ -71,6 +72,8 @@ public final class Class: Type { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(super.hash) diff --git a/SourceryRuntime/Sources/AST/Definition.swift b/SourceryRuntime/Sources/Common/AST/Definition.swift similarity index 100% rename from SourceryRuntime/Sources/AST/Definition.swift rename to SourceryRuntime/Sources/Common/AST/Definition.swift diff --git a/SourceryRuntime/Sources/AST/Documentation.swift b/SourceryRuntime/Sources/Common/AST/Documentation.swift similarity index 100% rename from SourceryRuntime/Sources/AST/Documentation.swift rename to SourceryRuntime/Sources/Common/AST/Documentation.swift diff --git a/SourceryRuntime/Sources/AST/Import.swift b/SourceryRuntime/Sources/Common/AST/Import.swift similarity index 98% rename from SourceryRuntime/Sources/AST/Import.swift rename to SourceryRuntime/Sources/Common/AST/Import.swift index ce46c576d..c4463f0f9 100644 --- a/SourceryRuntime/Sources/AST/Import.swift +++ b/SourceryRuntime/Sources/Common/AST/Import.swift @@ -50,6 +50,8 @@ public class Import: NSObject, SourceryModelWithoutDescription, Diffable { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.kind) diff --git a/SourceryRuntime/Sources/AST/Modifier.swift b/SourceryRuntime/Sources/Common/AST/Modifier.swift similarity index 98% rename from SourceryRuntime/Sources/AST/Modifier.swift rename to SourceryRuntime/Sources/Common/AST/Modifier.swift index 3d8d68380..dddc359c5 100644 --- a/SourceryRuntime/Sources/AST/Modifier.swift +++ b/SourceryRuntime/Sources/Common/AST/Modifier.swift @@ -38,6 +38,8 @@ public class Modifier: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJS return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) diff --git a/SourceryRuntime/Sources/AST/PhantomProtocols.swift b/SourceryRuntime/Sources/Common/AST/PhantomProtocols.swift similarity index 100% rename from SourceryRuntime/Sources/AST/PhantomProtocols.swift rename to SourceryRuntime/Sources/Common/AST/PhantomProtocols.swift diff --git a/SourceryRuntime/Sources/AST/Protocol.swift b/SourceryRuntime/Sources/Common/AST/Protocol.swift similarity index 93% rename from SourceryRuntime/Sources/AST/Protocol.swift rename to SourceryRuntime/Sources/Common/AST/Protocol.swift index 1b82f6b88..7b2354f57 100644 --- a/SourceryRuntime/Sources/AST/Protocol.swift +++ b/SourceryRuntime/Sources/Common/AST/Protocol.swift @@ -27,6 +27,7 @@ public final class Protocol: Type { } } + // sourcery: skipCoding /// list of generic requirements public override var genericRequirements: [GenericRequirement] { didSet { @@ -75,11 +76,12 @@ public final class Protocol: Type { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = super.description - string += ", " - string += "kind = \(String(describing: self.kind)), " - string += "associatedTypes = \(String(describing: self.associatedTypes)), " + string.append(", ") + string.append("kind = \(String(describing: self.kind)), ") + string.append("associatedTypes = \(String(describing: self.associatedTypes)), ") return string } @@ -94,6 +96,8 @@ public final class Protocol: Type { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.associatedTypes) diff --git a/SourceryRuntime/Sources/AST/ProtocolComposition.swift b/SourceryRuntime/Sources/Common/AST/ProtocolComposition.swift similarity index 98% rename from SourceryRuntime/Sources/AST/ProtocolComposition.swift rename to SourceryRuntime/Sources/Common/AST/ProtocolComposition.swift index 24fce2faa..a3fea9cc1 100644 --- a/SourceryRuntime/Sources/AST/ProtocolComposition.swift +++ b/SourceryRuntime/Sources/Common/AST/ProtocolComposition.swift @@ -56,6 +56,7 @@ public final class ProtocolComposition: Type { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = super.description string += ", " @@ -75,6 +76,8 @@ public final class ProtocolComposition: Type { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.composedTypeNames) diff --git a/SourceryRuntime/Sources/AST/Struct.swift b/SourceryRuntime/Sources/Common/AST/Struct.swift similarity index 97% rename from SourceryRuntime/Sources/AST/Struct.swift rename to SourceryRuntime/Sources/Common/AST/Struct.swift index c3ff36855..4560abd0e 100644 --- a/SourceryRuntime/Sources/AST/Struct.swift +++ b/SourceryRuntime/Sources/Common/AST/Struct.swift @@ -58,6 +58,7 @@ public final class Struct: Type { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = super.description string += ", " @@ -75,6 +76,8 @@ public final class Struct: Type { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(super.hash) diff --git a/SourceryRuntime/Sources/AST/TypeName/Array.swift b/SourceryRuntime/Sources/Common/AST/TypeName/Array.swift similarity index 89% rename from SourceryRuntime/Sources/AST/TypeName/Array.swift rename to SourceryRuntime/Sources/Common/AST/TypeName/Array.swift index 9b8c25e98..2a35e7467 100644 --- a/SourceryRuntime/Sources/AST/TypeName/Array.swift +++ b/SourceryRuntime/Sources/Common/AST/TypeName/Array.swift @@ -34,12 +34,13 @@ public final class ArrayType: NSObject, SourceryModel, Diffable { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "name = \(String(describing: self.name)), " - string += "elementTypeName = \(String(describing: self.elementTypeName)), " - string += "asGeneric = \(String(describing: self.asGeneric)), " - string += "asSource = \(String(describing: self.asSource))" + string.append("name = \(String(describing: self.name)), ") + string.append("elementTypeName = \(String(describing: self.elementTypeName)), ") + string.append("asGeneric = \(String(describing: self.asGeneric)), ") + string.append("asSource = \(String(describing: self.asSource))") return string } @@ -54,6 +55,8 @@ public final class ArrayType: NSObject, SourceryModel, Diffable { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) diff --git a/SourceryRuntime/Sources/AST/TypeName/Dictionary.swift b/SourceryRuntime/Sources/Common/AST/TypeName/Dictionary.swift similarity index 90% rename from SourceryRuntime/Sources/AST/TypeName/Dictionary.swift rename to SourceryRuntime/Sources/Common/AST/TypeName/Dictionary.swift index 126657120..f3044d868 100644 --- a/SourceryRuntime/Sources/AST/TypeName/Dictionary.swift +++ b/SourceryRuntime/Sources/Common/AST/TypeName/Dictionary.swift @@ -44,13 +44,14 @@ public final class DictionaryType: NSObject, SourceryModel, Diffable { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "name = \(String(describing: self.name)), " - string += "valueTypeName = \(String(describing: self.valueTypeName)), " - string += "keyTypeName = \(String(describing: self.keyTypeName)), " - string += "asGeneric = \(String(describing: self.asGeneric)), " - string += "asSource = \(String(describing: self.asSource))" + string.append("name = \(String(describing: self.name)), ") + string.append("valueTypeName = \(String(describing: self.valueTypeName)), ") + string.append("keyTypeName = \(String(describing: self.keyTypeName)), ") + string.append("asGeneric = \(String(describing: self.asGeneric)), ") + string.append("asSource = \(String(describing: self.asSource))") return string } @@ -66,6 +67,8 @@ public final class DictionaryType: NSObject, SourceryModel, Diffable { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) diff --git a/SourceryRuntime/Sources/AST/TypeName/Generic.swift b/SourceryRuntime/Sources/Common/AST/TypeName/Generic.swift similarity index 98% rename from SourceryRuntime/Sources/AST/TypeName/Generic.swift rename to SourceryRuntime/Sources/Common/AST/TypeName/Generic.swift index c38c8511f..96ff26e78 100644 --- a/SourceryRuntime/Sources/AST/TypeName/Generic.swift +++ b/SourceryRuntime/Sources/Common/AST/TypeName/Generic.swift @@ -39,6 +39,8 @@ public final class GenericType: NSObject, SourceryModelWithoutDescription, Diffa return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) diff --git a/SourceryRuntime/Sources/AST/TypeName/Set.swift b/SourceryRuntime/Sources/Common/AST/TypeName/Set.swift similarity index 88% rename from SourceryRuntime/Sources/AST/TypeName/Set.swift rename to SourceryRuntime/Sources/Common/AST/TypeName/Set.swift index 927776a12..6f5c1d637 100644 --- a/SourceryRuntime/Sources/AST/TypeName/Set.swift +++ b/SourceryRuntime/Sources/Common/AST/TypeName/Set.swift @@ -34,12 +34,13 @@ public final class SetType: NSObject, SourceryModel, Diffable { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "name = \(String(describing: self.name)), " - string += "elementTypeName = \(String(describing: self.elementTypeName)), " - string += "asGeneric = \(String(describing: self.asGeneric)), " - string += "asSource = \(String(describing: self.asSource))" + string.append("name = \(String(describing: self.name)), ") + string.append("elementTypeName = \(String(describing: self.elementTypeName)), ") + string.append("asGeneric = \(String(describing: self.asGeneric)), ") + string.append("asSource = \(String(describing: self.asSource))") return string } @@ -54,6 +55,8 @@ public final class SetType: NSObject, SourceryModel, Diffable { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) @@ -73,13 +76,13 @@ public final class SetType: NSObject, SourceryModel, Diffable { /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { + guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name - guard let elementTypeName: TypeName = aDecoder.decode(forKey: "elementTypeName") else { + guard let elementTypeName: TypeName = aDecoder.decode(forKey: "elementTypeName") else { withVaList(["elementTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } diff --git a/SourceryRuntime/Sources/AST/TypeName/Typed.swift b/SourceryRuntime/Sources/Common/AST/TypeName/Typed.swift similarity index 100% rename from SourceryRuntime/Sources/AST/TypeName/Typed.swift rename to SourceryRuntime/Sources/Common/AST/TypeName/Typed.swift diff --git a/SourceryRuntime/Sources/AST/Typealias.swift b/SourceryRuntime/Sources/Common/AST/Typealias.swift similarity index 90% rename from SourceryRuntime/Sources/AST/Typealias.swift rename to SourceryRuntime/Sources/Common/AST/Typealias.swift index 6278113b5..702b66840 100644 --- a/SourceryRuntime/Sources/AST/Typealias.swift +++ b/SourceryRuntime/Sources/Common/AST/Typealias.swift @@ -55,16 +55,17 @@ public final class Typealias: NSObject, Typed, SourceryModel, Diffable { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "aliasName = \(String(describing: self.aliasName)), " - string += "typeName = \(String(describing: self.typeName)), " - string += "module = \(String(describing: self.module)), " - string += "accessLevel = \(String(describing: self.accessLevel)), " - string += "parentName = \(String(describing: self.parentName)), " - string += "name = \(String(describing: self.name)), " - string += "annotations = \(String(describing: self.annotations)), " - string += "documentation = \(String(describing: self.documentation)), " + string.append("aliasName = \(String(describing: self.aliasName)), ") + string.append("typeName = \(String(describing: self.typeName)), ") + string.append("module = \(String(describing: self.module)), ") + string.append("accessLevel = \(String(describing: self.accessLevel)), ") + string.append("parentName = \(String(describing: self.parentName)), ") + string.append("name = \(String(describing: self.name)), ") + string.append("annotations = \(String(describing: self.annotations)), ") + string.append("documentation = \(String(describing: self.documentation)), ") return string } @@ -84,6 +85,8 @@ public final class Typealias: NSObject, Typed, SourceryModel, Diffable { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.aliasName) @@ -127,25 +130,25 @@ public final class Typealias: NSObject, Typed, SourceryModel, Diffable { }; self.typeName = typeName self.type = aDecoder.decode(forKey: "type") self.module = aDecoder.decode(forKey: "module") - self.parent = aDecoder.decode(forKey: "parent") - guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { - withVaList(["accessLevel"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.accessLevel = accessLevel - guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { + guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations - guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { + guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation + self.parent = aDecoder.decode(forKey: "parent") + guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { + withVaList(["accessLevel"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.accessLevel = accessLevel self.parentName = aDecoder.decode(forKey: "parentName") } @@ -155,11 +158,11 @@ public final class Typealias: NSObject, Typed, SourceryModel, Diffable { aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") aCoder.encode(self.module, forKey: "module") + aCoder.encode(self.annotations, forKey: "annotations") + aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.parent, forKey: "parent") aCoder.encode(self.accessLevel, forKey: "accessLevel") aCoder.encode(self.parentName, forKey: "parentName") - aCoder.encode(self.documentation, forKey: "documentation") - aCoder.encode(self.annotations, forKey: "annotations") } // sourcery:end } diff --git a/SourceryRuntime/Sources/Array+Parallel.swift b/SourceryRuntime/Sources/Common/Array+Parallel.swift similarity index 100% rename from SourceryRuntime/Sources/Array+Parallel.swift rename to SourceryRuntime/Sources/Common/Array+Parallel.swift diff --git a/SourceryRuntime/Sources/BytesRange.swift b/SourceryRuntime/Sources/Common/BytesRange.swift similarity index 96% rename from SourceryRuntime/Sources/BytesRange.swift rename to SourceryRuntime/Sources/Common/BytesRange.swift index c0e45b2bc..554fe86e5 100644 --- a/SourceryRuntime/Sources/BytesRange.swift +++ b/SourceryRuntime/Sources/Common/BytesRange.swift @@ -24,6 +24,7 @@ public final class BytesRange: NSObject, SourceryModel, Diffable { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string += "offset = \(String(describing: self.offset)), " @@ -42,6 +43,8 @@ public final class BytesRange: NSObject, SourceryModel, Diffable { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.offset) diff --git a/SourceryRuntime/Sources/Composer/Composer.swift b/SourceryRuntime/Sources/Common/Composer/Composer.swift similarity index 100% rename from SourceryRuntime/Sources/Composer/Composer.swift rename to SourceryRuntime/Sources/Common/Composer/Composer.swift diff --git a/SourceryRuntime/Sources/Composer/ParserResultsComposed.swift b/SourceryRuntime/Sources/Common/Composer/ParserResultsComposed.swift similarity index 96% rename from SourceryRuntime/Sources/Composer/ParserResultsComposed.swift rename to SourceryRuntime/Sources/Common/Composer/ParserResultsComposed.swift index 351063ed8..16cb2f1b7 100644 --- a/SourceryRuntime/Sources/Composer/ParserResultsComposed.swift +++ b/SourceryRuntime/Sources/Common/Composer/ParserResultsComposed.swift @@ -75,37 +75,42 @@ internal struct ParserResultsComposed { } } + // if it had contained types, they might have been fully defined and so their name has to be noted in uniques + private mutating func rewriteChildren(of type: Type) { + // child is never an extension so no need to check + for child in type.containedTypes { + typeMap[child.globalName] = child + rewriteChildren(of: child) + } + } + private mutating func unifyTypes() -> [Type] { /// Resolve actual names of extensions, as they could have been done on typealias and note updated child names in uniques if needed parsedTypes .filter { $0.isExtension } - .forEach { - let oldName = $0.globalName + .forEach { (type: Type) in + let oldName = type.globalName - if $0.parent == nil, $0.localName.contains(".") { - resolveExtensionOfNestedType($0) + let hasDotInLocalName = type.localName.contains(".") as Bool + if let _ = type.parent, hasDotInLocalName { + resolveExtensionOfNestedType(type) } - if let resolved = resolveGlobalName(for: oldName, containingType: $0.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases)?.name { - $0.localName = resolved.replacingOccurrences(of: "\($0.module != nil ? "\($0.module!)." : "")", with: "") + if let resolved = resolveGlobalName(for: oldName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases)?.name { + var moduleName: String = "" + if let module = type.module { + moduleName = "\(module)." + } + type.localName = resolved.replacingOccurrences(of: moduleName, with: "") } else { return } // nothing left to do - guard oldName != $0.globalName else { + guard oldName != type.globalName else { return } - - // if it had contained types, they might have been fully defined and so their name has to be noted in uniques - func rewriteChildren(of type: Type) { - // child is never an extension so no need to check - for child in type.containedTypes { - typeMap[child.globalName] = child - rewriteChildren(of: child) - } - } - rewriteChildren(of: $0) + rewriteChildren(of: type) } // extend all types with their extensions diff --git a/SourceryRuntime/Sources/Diffable.swift b/SourceryRuntime/Sources/Common/Diffable.swift similarity index 95% rename from SourceryRuntime/Sources/Diffable.swift rename to SourceryRuntime/Sources/Common/Diffable.swift index 749fdd540..3671ac9d7 100644 --- a/SourceryRuntime/Sources/Diffable.swift +++ b/SourceryRuntime/Sources/Common/Diffable.swift @@ -61,6 +61,8 @@ public class DiffableResult: NSObject, AutoEquatable { var isEmpty: Bool { return results.isEmpty } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.identifier) @@ -76,7 +78,9 @@ public class DiffableResult: NSObject, AutoEquatable { public override var description: String { guard !results.isEmpty else { return "" } - return "\(identifier.flatMap { "\($0) " } ?? "")" + results.joined(separator: "\n") + var description = "\(identifier.flatMap { "\($0) " } ?? "")" + description.append(results.joined(separator: "\n")) + return description } } @@ -97,7 +101,9 @@ public extension DiffableResult { /// :nodoc: @discardableResult func trackDifference(actual: T?, expected: T?) -> DiffableResult { if actual != expected { - let result = DiffableResult(results: [""]) + let expected = expected.map({ "\($0)" }) ?? "nil" + let actual = actual.map({ "\($0)" }) ?? "nil" + let result = DiffableResult(results: [""]) append(contentsOf: result) } return self diff --git a/SourceryRuntime/Sources/Extensions.swift b/SourceryRuntime/Sources/Common/Extensions.swift similarity index 86% rename from SourceryRuntime/Sources/Extensions.swift rename to SourceryRuntime/Sources/Common/Extensions.swift index 607c625f6..dc23f3598 100644 --- a/SourceryRuntime/Sources/Extensions.swift +++ b/SourceryRuntime/Sources/Common/Extensions.swift @@ -189,29 +189,37 @@ public extension String { defer { i = self.index(i, offsetBy: offset) } - let currentlyScanned = self[i..<(self.index(i, offsetBy: delimiter.count, limitedBy: self.endIndex) ?? self.endIndex)] - if let openString = between.open.first(where: { String(self[i...]).starts(with: $0) }) { - if !(boundingCharactersCount == 0 && String(self[i]) == delimiter) { + var currentlyScannedEnd: Index = self.endIndex + if let endIndex = self.index(i, offsetBy: delimiter.count, limitedBy: self.endIndex) { + currentlyScannedEnd = endIndex + } + let currentlyScanned: String = String(self[i..` - if !(self[i] == ">" && item.last == "-") { + if !((self[i] == ">") as Bool && (item.last == "-") as Bool) { boundingCharactersCount = max(0, boundingCharactersCount - 1) } offset = closeString.count } - if self[i] == "\"" { + if (self[i] == "\"") as Bool { quotesCount += 1 } - if currentlyScanned == delimiter && boundingCharactersCount == 0 && quotesCount % 2 == 0 { + let currentIsDelimiter = (currentlyScanned == delimiter) as Bool + let boundingCountIsZero = (boundingCharactersCount == 0) as Bool + let hasEvenQuotes = (quotesCount % 2 == 0) as Bool + if currentIsDelimiter && boundingCountIsZero && hasEvenQuotes { items.append(item) item = "" i = self.index(i, offsetBy: delimiter.count - 1) } else { - item += self[i.. Any? { switch member { case "name": @@ -38,10 +34,11 @@ public final class AssociatedType: NSObject, SourceryModel, DynamicMemberLookup } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "name = \(String(describing: self.name)), " - string += "typeName = \(String(describing: self.typeName))" + string.append("name = \(String(describing: self.name)), ") + string.append("typeName = \(String(describing: self.typeName))") return string } @@ -56,6 +53,8 @@ public final class AssociatedType: NSObject, SourceryModel, DynamicMemberLookup return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) @@ -75,7 +74,7 @@ public final class AssociatedType: NSObject, SourceryModel, DynamicMemberLookup /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { + guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } diff --git a/SourceryRuntime/Sources/AST/AssociatedValue_Linux.swift b/SourceryRuntime/Sources/Linux/AST/AssociatedValue_Linux.swift similarity index 90% rename from SourceryRuntime/Sources/AST/AssociatedValue_Linux.swift rename to SourceryRuntime/Sources/Linux/AST/AssociatedValue_Linux.swift index 8eea4491a..195d78a4e 100644 --- a/SourceryRuntime/Sources/AST/AssociatedValue_Linux.swift +++ b/SourceryRuntime/Sources/Linux/AST/AssociatedValue_Linux.swift @@ -4,13 +4,9 @@ // #if !canImport(ObjectiveC) import Foundation -// For DynamicMemberLookup we need to import Stencil, -// however, this is different from SourceryRuntime.content.generated.swift, because -// it cannot reference Stencil -import Stencil /// Defines enum case associated value -public final class AssociatedValue: NSObject, SourceryModel, AutoDescription, Typed, Annotated, Diffable, DynamicMemberLookup { +public final class AssociatedValue: NSObject, SourceryModel, AutoDescription, Typed, Annotated, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "externalName": @@ -66,13 +62,14 @@ public final class AssociatedValue: NSObject, SourceryModel, AutoDescription, Ty } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "localName = \(String(describing: self.localName)), " - string += "externalName = \(String(describing: self.externalName)), " - string += "typeName = \(String(describing: self.typeName)), " - string += "defaultValue = \(String(describing: self.defaultValue)), " - string += "annotations = \(String(describing: self.annotations))" + string.append("localName = \(String(describing: self.localName)), ") + string.append("externalName = \(String(describing: self.externalName)), ") + string.append("typeName = \(String(describing: self.typeName)), ") + string.append("defaultValue = \(String(describing: self.defaultValue)), ") + string.append("annotations = \(String(describing: self.annotations))") return string } @@ -90,6 +87,8 @@ public final class AssociatedValue: NSObject, SourceryModel, AutoDescription, Ty return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.localName) diff --git a/SourceryRuntime/Sources/AST/ClosureParameter_Linux.swift b/SourceryRuntime/Sources/Linux/AST/ClosureParameter_Linux.swift similarity index 88% rename from SourceryRuntime/Sources/AST/ClosureParameter_Linux.swift rename to SourceryRuntime/Sources/Linux/AST/ClosureParameter_Linux.swift index c5a89a38c..30be9be65 100644 --- a/SourceryRuntime/Sources/AST/ClosureParameter_Linux.swift +++ b/SourceryRuntime/Sources/Linux/AST/ClosureParameter_Linux.swift @@ -1,12 +1,8 @@ #if !canImport(ObjectiveC) import Foundation -// For DynamicMemberLookup we need to import Stencil, -// however, this is different from SourceryRuntime.content.generated.swift, because -// it cannot reference Stencil -import Stencil // sourcery: skipDiffing -public final class ClosureParameter: NSObject, SourceryModel, Typed, Annotated, DynamicMemberLookup { +public final class ClosureParameter: NSObject, SourceryModel, Typed, Annotated, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "argumentLabel": @@ -89,6 +85,8 @@ public final class ClosureParameter: NSObject, SourceryModel, Typed, Annotated, return (labels.nilIfEmpty ?? "_") + typeSuffix } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.argumentLabel) @@ -102,16 +100,17 @@ public final class ClosureParameter: NSObject, SourceryModel, Typed, Annotated, } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "argumentLabel = \(String(describing: self.argumentLabel)), " - string += "name = \(String(describing: self.name)), " - string += "typeName = \(String(describing: self.typeName)), " - string += "`inout` = \(String(describing: self.`inout`)), " - string += "typeAttributes = \(String(describing: self.typeAttributes)), " - string += "defaultValue = \(String(describing: self.defaultValue)), " - string += "annotations = \(String(describing: self.annotations)), " - string += "asSource = \(String(describing: self.asSource))" + string.append("argumentLabel = \(String(describing: self.argumentLabel)), ") + string.append("name = \(String(describing: self.name)), ") + string.append("typeName = \(String(describing: self.typeName)), ") + string.append("`inout` = \(String(describing: self.`inout`)), ") + string.append("typeAttributes = \(String(describing: self.typeAttributes)), ") + string.append("defaultValue = \(String(describing: self.defaultValue)), ") + string.append("annotations = \(String(describing: self.annotations)), ") + string.append("asSource = \(String(describing: self.asSource))") return string } @@ -141,8 +140,8 @@ public final class ClosureParameter: NSObject, SourceryModel, Typed, Annotated, fatalError() }; self.typeName = typeName self.`inout` = aDecoder.decode(forKey: "`inout`") - self.isVariadic = aDecoder.decode(forKey: "isVariadic") self.type = aDecoder.decode(forKey: "type") + self.isVariadic = aDecoder.decode(forKey: "isVariadic") self.defaultValue = aDecoder.decode(forKey: "defaultValue") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in @@ -158,8 +157,8 @@ public final class ClosureParameter: NSObject, SourceryModel, Typed, Annotated, aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.`inout`, forKey: "`inout`") - aCoder.encode(self.isVariadic, forKey: "isVariadic") aCoder.encode(self.type, forKey: "type") + aCoder.encode(self.isVariadic, forKey: "isVariadic") aCoder.encode(self.defaultValue, forKey: "defaultValue") aCoder.encode(self.annotations, forKey: "annotations") } diff --git a/SourceryRuntime/Sources/AST/EnumCase_Linux.swift b/SourceryRuntime/Sources/Linux/AST/EnumCase_Linux.swift similarity index 89% rename from SourceryRuntime/Sources/AST/EnumCase_Linux.swift rename to SourceryRuntime/Sources/Linux/AST/EnumCase_Linux.swift index fa3349aa8..c8577ca7a 100644 --- a/SourceryRuntime/Sources/AST/EnumCase_Linux.swift +++ b/SourceryRuntime/Sources/Linux/AST/EnumCase_Linux.swift @@ -4,13 +4,9 @@ // #if !canImport(ObjectiveC) import Foundation -// For DynamicMemberLookup we need to import Stencil, -// however, this is different from SourceryRuntime.content.generated.swift, because -// it cannot reference Stencil -import Stencil /// Defines enum case -public final class EnumCase: NSObject, SourceryModel, AutoDescription, Annotated, Documented, Diffable, DynamicMemberLookup { +public final class EnumCase: NSObject, SourceryModel, AutoDescription, Annotated, Documented, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "name": @@ -67,15 +63,16 @@ public final class EnumCase: NSObject, SourceryModel, AutoDescription, Annotated } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "name = \(String(describing: self.name)), " - string += "rawValue = \(String(describing: self.rawValue)), " - string += "associatedValues = \(String(describing: self.associatedValues)), " - string += "annotations = \(String(describing: self.annotations)), " - string += "documentation = \(String(describing: self.documentation)), " - string += "indirect = \(String(describing: self.indirect)), " - string += "hasAssociatedValue = \(String(describing: self.hasAssociatedValue))" + string.append("name = \(String(describing: self.name)), ") + string.append("rawValue = \(String(describing: self.rawValue)), ") + string.append("associatedValues = \(String(describing: self.associatedValues)), ") + string.append("annotations = \(String(describing: self.annotations)), ") + string.append("documentation = \(String(describing: self.documentation)), ") + string.append("indirect = \(String(describing: self.indirect)), ") + string.append("hasAssociatedValue = \(String(describing: self.hasAssociatedValue))") return string } @@ -94,6 +91,8 @@ public final class EnumCase: NSObject, SourceryModel, AutoDescription, Annotated return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) diff --git a/SourceryRuntime/Sources/AST/Enum_Linux.swift b/SourceryRuntime/Sources/Linux/AST/Enum_Linux.swift similarity index 94% rename from SourceryRuntime/Sources/AST/Enum_Linux.swift rename to SourceryRuntime/Sources/Linux/AST/Enum_Linux.swift index 3c9935e20..5bd2f6e2d 100644 --- a/SourceryRuntime/Sources/AST/Enum_Linux.swift +++ b/SourceryRuntime/Sources/Linux/AST/Enum_Linux.swift @@ -101,12 +101,13 @@ public final class Enum: Type { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = super.description - string += ", " - string += "cases = \(String(describing: self.cases)), " - string += "rawTypeName = \(String(describing: self.rawTypeName)), " - string += "hasAssociatedValues = \(String(describing: self.hasAssociatedValues))" + string.append(", ") + string.append("cases = \(String(describing: self.cases)), ") + string.append("rawTypeName = \(String(describing: self.rawTypeName)), ") + string.append("hasAssociatedValues = \(String(describing: self.hasAssociatedValues))") return string } @@ -122,6 +123,8 @@ public final class Enum: Type { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.cases) diff --git a/SourceryRuntime/Sources/AST/GenericParameter_Linux.swift b/SourceryRuntime/Sources/Linux/AST/GenericParameter_Linux.swift similarity index 88% rename from SourceryRuntime/Sources/AST/GenericParameter_Linux.swift rename to SourceryRuntime/Sources/Linux/AST/GenericParameter_Linux.swift index a058edd03..86ef566b4 100644 --- a/SourceryRuntime/Sources/AST/GenericParameter_Linux.swift +++ b/SourceryRuntime/Sources/Linux/AST/GenericParameter_Linux.swift @@ -1,12 +1,8 @@ #if !canImport(ObjectiveC) import Foundation -// For DynamicMemberLookup we need to import Stencil, -// however, this is different from SourceryRuntime.content.generated.swift, because -// it cannot reference Stencil -import Stencil /// Descibes Swift generic parameter -public final class GenericParameter: NSObject, SourceryModel, Diffable, DynamicMemberLookup { +public final class GenericParameter: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "name": @@ -31,10 +27,11 @@ public final class GenericParameter: NSObject, SourceryModel, Diffable, DynamicM } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "name = \(String(describing: self.name)), " - string += "inheritedTypeName = \(String(describing: self.inheritedTypeName))" + string.append("name = \(String(describing: self.name)), ") + string.append("inheritedTypeName = \(String(describing: self.inheritedTypeName))") return string } @@ -49,6 +46,8 @@ public final class GenericParameter: NSObject, SourceryModel, Diffable, DynamicM return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) @@ -68,7 +67,7 @@ public final class GenericParameter: NSObject, SourceryModel, Diffable, DynamicM /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { + guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } diff --git a/SourceryRuntime/Sources/AST/GenericRequirement_Linux.swift b/SourceryRuntime/Sources/Linux/AST/GenericRequirement_Linux.swift similarity index 88% rename from SourceryRuntime/Sources/AST/GenericRequirement_Linux.swift rename to SourceryRuntime/Sources/Linux/AST/GenericRequirement_Linux.swift index 394252c52..bd1ae461f 100644 --- a/SourceryRuntime/Sources/AST/GenericRequirement_Linux.swift +++ b/SourceryRuntime/Sources/Linux/AST/GenericRequirement_Linux.swift @@ -1,12 +1,8 @@ #if !canImport(ObjectiveC) import Foundation -// For DynamicMemberLookup we need to import Stencil, -// however, this is different from SourceryRuntime.content.generated.swift, because -// it cannot reference Stencil -import Stencil /// Descibes Swift generic requirement -public class GenericRequirement: NSObject, SourceryModel, Diffable, DynamicMemberLookup { +public class GenericRequirement: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "leftType": @@ -53,12 +49,13 @@ public class GenericRequirement: NSObject, SourceryModel, Diffable, DynamicMembe } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "leftType = \(String(describing: self.leftType)), " - string += "rightType = \(String(describing: self.rightType)), " - string += "relationship = \(String(describing: self.relationship)), " - string += "relationshipSyntax = \(String(describing: self.relationshipSyntax))" + string.append("leftType = \(String(describing: self.leftType)), ") + string.append("rightType = \(String(describing: self.rightType)), ") + string.append("relationship = \(String(describing: self.relationship)), ") + string.append("relationshipSyntax = \(String(describing: self.relationshipSyntax))") return string } @@ -75,6 +72,8 @@ public class GenericRequirement: NSObject, SourceryModel, Diffable, DynamicMembe return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.leftType) @@ -98,25 +97,25 @@ public class GenericRequirement: NSObject, SourceryModel, Diffable, DynamicMembe /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let leftType: AssociatedType = aDecoder.decode(forKey: "leftType") else { + guard let leftType: AssociatedType = aDecoder.decode(forKey: "leftType") else { withVaList(["leftType"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.leftType = leftType - guard let rightType: GenericTypeParameter = aDecoder.decode(forKey: "rightType") else { + guard let rightType: GenericTypeParameter = aDecoder.decode(forKey: "rightType") else { withVaList(["rightType"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.rightType = rightType - guard let relationship: String = aDecoder.decode(forKey: "relationship") else { + guard let relationship: String = aDecoder.decode(forKey: "relationship") else { withVaList(["relationship"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.relationship = relationship - guard let relationshipSyntax: String = aDecoder.decode(forKey: "relationshipSyntax") else { + guard let relationshipSyntax: String = aDecoder.decode(forKey: "relationshipSyntax") else { withVaList(["relationshipSyntax"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } diff --git a/SourceryRuntime/Sources/AST/MethodParameter_Linux.swift b/SourceryRuntime/Sources/Linux/AST/MethodParameter_Linux.swift similarity index 90% rename from SourceryRuntime/Sources/AST/MethodParameter_Linux.swift rename to SourceryRuntime/Sources/Linux/AST/MethodParameter_Linux.swift index 3b7d3dd6a..496c232b5 100644 --- a/SourceryRuntime/Sources/AST/MethodParameter_Linux.swift +++ b/SourceryRuntime/Sources/Linux/AST/MethodParameter_Linux.swift @@ -1,12 +1,8 @@ #if !canImport(ObjectiveC) import Foundation -// For DynamicMemberLookup we need to import Stencil, -// however, this is different from SourceryRuntime.content.generated.swift, because -// it cannot reference Stencil -import Stencil /// Describes method parameter -public class MethodParameter: NSObject, SourceryModel, Typed, Annotated, Diffable, DynamicMemberLookup { +public class MethodParameter: NSObject, SourceryModel, Typed, Annotated, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "argumentLabel": @@ -97,17 +93,18 @@ public class MethodParameter: NSObject, SourceryModel, Typed, Annotated, Diffabl } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "argumentLabel = \(String(describing: self.argumentLabel)), " - string += "name = \(String(describing: self.name)), " - string += "typeName = \(String(describing: self.typeName)), " - string += "`inout` = \(String(describing: self.`inout`)), " - string += "isVariadic = \(String(describing: self.isVariadic)), " - string += "typeAttributes = \(String(describing: self.typeAttributes)), " - string += "defaultValue = \(String(describing: self.defaultValue)), " - string += "annotations = \(String(describing: self.annotations)), " - string += "asSource = \(String(describing: self.asSource))" + string.append("argumentLabel = \(String(describing: self.argumentLabel)), ") + string.append("name = \(String(describing: self.name)), ") + string.append("typeName = \(String(describing: self.typeName)), ") + string.append("`inout` = \(String(describing: self.`inout`)), ") + string.append("isVariadic = \(String(describing: self.isVariadic)), ") + string.append("typeAttributes = \(String(describing: self.typeAttributes)), ") + string.append("defaultValue = \(String(describing: self.defaultValue)), ") + string.append("annotations = \(String(describing: self.annotations)), ") + string.append("asSource = \(String(describing: self.asSource))") return string } @@ -127,6 +124,8 @@ public class MethodParameter: NSObject, SourceryModel, Typed, Annotated, Diffabl return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.argumentLabel) diff --git a/SourceryRuntime/Sources/AST/Method_Linux.swift b/SourceryRuntime/Sources/Linux/AST/Method_Linux.swift similarity index 92% rename from SourceryRuntime/Sources/AST/Method_Linux.swift rename to SourceryRuntime/Sources/Linux/AST/Method_Linux.swift index 0a46d4f7c..1181215ac 100644 --- a/SourceryRuntime/Sources/AST/Method_Linux.swift +++ b/SourceryRuntime/Sources/Linux/AST/Method_Linux.swift @@ -1,15 +1,11 @@ #if !canImport(ObjectiveC) import Foundation -// For DynamicMemberLookup we need to import Stencil, -// however, this is different from SourceryRuntime.content.generated.swift, because -// it cannot reference Stencil -import Stencil /// :nodoc: public typealias SourceryMethod = Method /// Describes method -public final class Method: NSObject, SourceryModel, Annotated, Documented, Definition, Diffable, DynamicMemberLookup { +public final class Method: NSObject, SourceryModel, Annotated, Documented, Definition, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "definedInType": @@ -256,25 +252,26 @@ public final class Method: NSObject, SourceryModel, Annotated, Documented, Defin } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "name = \(String(describing: self.name)), " - string += "selectorName = \(String(describing: self.selectorName)), " - string += "parameters = \(String(describing: self.parameters)), " - string += "returnTypeName = \(String(describing: self.returnTypeName)), " - string += "isAsync = \(String(describing: self.isAsync)), " - string += "`throws` = \(String(describing: self.`throws`)), " - string += "`rethrows` = \(String(describing: self.`rethrows`)), " - string += "accessLevel = \(String(describing: self.accessLevel)), " - string += "isStatic = \(String(describing: self.isStatic)), " - string += "isClass = \(String(describing: self.isClass)), " - string += "isFailableInitializer = \(String(describing: self.isFailableInitializer)), " - string += "annotations = \(String(describing: self.annotations)), " - string += "documentation = \(String(describing: self.documentation)), " - string += "definedInTypeName = \(String(describing: self.definedInTypeName)), " - string += "attributes = \(String(describing: self.attributes)), " - string += "modifiers = \(String(describing: self.modifiers))" - string += "genericRequirements = \(String(describing: self.genericRequirements))" + string.append("name = \(String(describing: self.name)), ") + string.append("selectorName = \(String(describing: self.selectorName)), ") + string.append("parameters = \(String(describing: self.parameters)), ") + string.append("returnTypeName = \(String(describing: self.returnTypeName)), ") + string.append("isAsync = \(String(describing: self.isAsync)), ") + string.append("`throws` = \(String(describing: self.`throws`)), ") + string.append("`rethrows` = \(String(describing: self.`rethrows`)), ") + string.append("accessLevel = \(String(describing: self.accessLevel)), ") + string.append("isStatic = \(String(describing: self.isStatic)), ") + string.append("isClass = \(String(describing: self.isClass)), ") + string.append("isFailableInitializer = \(String(describing: self.isFailableInitializer)), ") + string.append("annotations = \(String(describing: self.annotations)), ") + string.append("documentation = \(String(describing: self.documentation)), ") + string.append("definedInTypeName = \(String(describing: self.definedInTypeName)), ") + string.append("attributes = \(String(describing: self.attributes)), ") + string.append("modifiers = \(String(describing: self.modifiers))") + string.append("genericRequirements = \(String(describing: self.genericRequirements))") return string } @@ -304,6 +301,8 @@ public final class Method: NSObject, SourceryModel, Annotated, Documented, Defin return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) @@ -416,7 +415,7 @@ public final class Method: NSObject, SourceryModel, Annotated, Documented, Defin } fatalError() }; self.modifiers = modifiers - guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { + guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { withVaList(["genericRequirements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } diff --git a/SourceryRuntime/Sources/AST/Subscript_Linux.swift b/SourceryRuntime/Sources/Linux/AST/Subscript_Linux.swift similarity index 88% rename from SourceryRuntime/Sources/AST/Subscript_Linux.swift rename to SourceryRuntime/Sources/Linux/AST/Subscript_Linux.swift index c65241fe1..bb3ebcf31 100644 --- a/SourceryRuntime/Sources/AST/Subscript_Linux.swift +++ b/SourceryRuntime/Sources/Linux/AST/Subscript_Linux.swift @@ -1,12 +1,8 @@ #if !canImport(ObjectiveC) import Foundation -// For DynamicMemberLookup we need to import Stencil, -// however, this is different from SourceryRuntime.content.generated.swift, because -// it cannot reference Stencil -import Stencil /// Describes subscript -public final class Subscript: NSObject, SourceryModel, Annotated, Documented, Definition, Diffable, DynamicMemberLookup { +public final class Subscript: NSObject, SourceryModel, Annotated, Documented, Definition, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { @@ -186,26 +182,27 @@ public final class Subscript: NSObject, SourceryModel, Annotated, Documented, De } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "parameters = \(String(describing: self.parameters)), " - string += "returnTypeName = \(String(describing: self.returnTypeName)), " - string += "actualReturnTypeName = \(String(describing: self.actualReturnTypeName)), " - string += "isFinal = \(String(describing: self.isFinal)), " - string += "readAccess = \(String(describing: self.readAccess)), " - string += "writeAccess = \(String(describing: self.writeAccess)), " - string += "isAsync = \(String(describing: self.isAsync)), " - string += "`throws` = \(String(describing: self.throws)), " - string += "isMutable = \(String(describing: self.isMutable)), " - string += "annotations = \(String(describing: self.annotations)), " - string += "documentation = \(String(describing: self.documentation)), " - string += "definedInTypeName = \(String(describing: self.definedInTypeName)), " - string += "actualDefinedInTypeName = \(String(describing: self.actualDefinedInTypeName)), " - string += "genericParameters = \(String(describing: self.genericParameters)), " - string += "genericRequirements = \(String(describing: self.genericRequirements)), " - string += "isGeneric = \(String(describing: self.isGeneric)), " - string += "attributes = \(String(describing: self.attributes)), " - string += "modifiers = \(String(describing: self.modifiers))" + string.append("parameters = \(String(describing: self.parameters)), ") + string.append("returnTypeName = \(String(describing: self.returnTypeName)), ") + string.append("actualReturnTypeName = \(String(describing: self.actualReturnTypeName)), ") + string.append("isFinal = \(String(describing: self.isFinal)), ") + string.append("readAccess = \(String(describing: self.readAccess)), ") + string.append("writeAccess = \(String(describing: self.writeAccess)), ") + string.append("isAsync = \(String(describing: self.isAsync)), ") + string.append("`throws` = \(String(describing: self.throws)), ") + string.append("isMutable = \(String(describing: self.isMutable)), ") + string.append("annotations = \(String(describing: self.annotations)), ") + string.append("documentation = \(String(describing: self.documentation)), ") + string.append("definedInTypeName = \(String(describing: self.definedInTypeName)), ") + string.append("actualDefinedInTypeName = \(String(describing: self.actualDefinedInTypeName)), ") + string.append("genericParameters = \(String(describing: self.genericParameters)), ") + string.append("genericRequirements = \(String(describing: self.genericRequirements)), ") + string.append("isGeneric = \(String(describing: self.isGeneric)), ") + string.append("attributes = \(String(describing: self.attributes)), ") + string.append("modifiers = \(String(describing: self.modifiers))") return string } @@ -231,6 +228,8 @@ public final class Subscript: NSObject, SourceryModel, Annotated, Documented, De return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.parameters) @@ -272,71 +271,71 @@ public final class Subscript: NSObject, SourceryModel, Annotated, Documented, De /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let parameters: [MethodParameter] = aDecoder.decode(forKey: "parameters") else { + guard let parameters: [MethodParameter] = aDecoder.decode(forKey: "parameters") else { withVaList(["parameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.parameters = parameters - guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { + guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { withVaList(["returnTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.returnTypeName = returnTypeName self.returnType = aDecoder.decode(forKey: "returnType") - guard let readAccess: String = aDecoder.decode(forKey: "readAccess") else { + guard let readAccess: String = aDecoder.decode(forKey: "readAccess") else { withVaList(["readAccess"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.readAccess = readAccess - guard let writeAccess: String = aDecoder.decode(forKey: "writeAccess") else { + guard let writeAccess: String = aDecoder.decode(forKey: "writeAccess") else { withVaList(["writeAccess"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.writeAccess = writeAccess - guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { + self.isAsync = aDecoder.decode(forKey: "isAsync") + self.`throws` = aDecoder.decode(forKey: "`throws`") + guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations - guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { + guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation - self.isAsync = aDecoder.decode(forKey: "isAsync") - self.`throws` = aDecoder.decode(forKey: "`throws`") self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") self.definedInType = aDecoder.decode(forKey: "definedInType") - guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { + guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes - guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { + guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers - guard let genericParameters: [GenericParameter] = aDecoder.decode(forKey: "genericParameters") else { + guard let genericParameters: [GenericParameter] = aDecoder.decode(forKey: "genericParameters") else { withVaList(["genericParameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.genericParameters = genericParameters - guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { + }; self.genericParameters = genericParameters + guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { withVaList(["genericRequirements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.genericRequirements = genericRequirements + }; self.genericRequirements = genericRequirements } /// :nodoc: @@ -352,10 +351,10 @@ public final class Subscript: NSObject, SourceryModel, Annotated, Documented, De aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") aCoder.encode(self.definedInType, forKey: "definedInType") - aCoder.encode(self.genericParameters, forKey: "genericParameters") - aCoder.encode(self.genericRequirements, forKey: "genericRequirements") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") + aCoder.encode(self.genericParameters, forKey: "genericParameters") + aCoder.encode(self.genericRequirements, forKey: "genericRequirements") } // sourcery:end diff --git a/SourceryRuntime/Sources/AST/TypeName/Closure_Linux.swift b/SourceryRuntime/Sources/Linux/AST/TypeName/Closure_Linux.swift similarity index 90% rename from SourceryRuntime/Sources/AST/TypeName/Closure_Linux.swift rename to SourceryRuntime/Sources/Linux/AST/TypeName/Closure_Linux.swift index bbdfae16d..651a6f96c 100644 --- a/SourceryRuntime/Sources/AST/TypeName/Closure_Linux.swift +++ b/SourceryRuntime/Sources/Linux/AST/TypeName/Closure_Linux.swift @@ -1,12 +1,8 @@ #if !canImport(ObjectiveC) import Foundation -// For DynamicMemberLookup we need to import Stencil, -// however, this is different from SourceryRuntime.content.generated.swift, because -// it cannot reference Stencil -import Stencil -/// Describes closure type -public final class ClosureType: NSObject, SourceryModel, Diffable, DynamicMemberLookup { +/// Describes closure type +public final class ClosureType: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "name": @@ -102,17 +98,18 @@ public final class ClosureType: NSObject, SourceryModel, Diffable, DynamicMember } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "name = \(String(describing: self.name)), " - string += "parameters = \(String(describing: self.parameters)), " - string += "returnTypeName = \(String(describing: self.returnTypeName)), " - string += "actualReturnTypeName = \(String(describing: self.actualReturnTypeName)), " - string += "isAsync = \(String(describing: self.isAsync)), " - string += "asyncKeyword = \(String(describing: self.asyncKeyword)), " - string += "`throws` = \(String(describing: self.`throws`)), " - string += "throwsOrRethrowsKeyword = \(String(describing: self.throwsOrRethrowsKeyword)), " - string += "asSource = \(String(describing: self.asSource))" + string.append("name = \(String(describing: self.name)), ") + string.append("parameters = \(String(describing: self.parameters)), ") + string.append("returnTypeName = \(String(describing: self.returnTypeName)), ") + string.append("actualReturnTypeName = \(String(describing: self.actualReturnTypeName)), ") + string.append("isAsync = \(String(describing: self.isAsync)), ") + string.append("asyncKeyword = \(String(describing: self.asyncKeyword)), ") + string.append("`throws` = \(String(describing: self.`throws`)), ") + string.append("throwsOrRethrowsKeyword = \(String(describing: self.throwsOrRethrowsKeyword)), ") + string.append("asSource = \(String(describing: self.asSource))") return string } @@ -132,6 +129,8 @@ public final class ClosureType: NSObject, SourceryModel, Diffable, DynamicMember return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) diff --git a/SourceryRuntime/Sources/AST/TypeName/GenericTypeParameter_Linux.swift b/SourceryRuntime/Sources/Linux/AST/TypeName/GenericTypeParameter_Linux.swift similarity index 89% rename from SourceryRuntime/Sources/AST/TypeName/GenericTypeParameter_Linux.swift rename to SourceryRuntime/Sources/Linux/AST/TypeName/GenericTypeParameter_Linux.swift index 4cc8badb6..0fc1e881f 100644 --- a/SourceryRuntime/Sources/AST/TypeName/GenericTypeParameter_Linux.swift +++ b/SourceryRuntime/Sources/Linux/AST/TypeName/GenericTypeParameter_Linux.swift @@ -1,12 +1,8 @@ #if !canImport(ObjectiveC) import Foundation -// For DynamicMemberLookup we need to import Stencil, -// however, this is different from SourceryRuntime.content.generated.swift, because -// it cannot reference Stencil -import Stencil /// Descibes Swift generic type parameter -public final class GenericTypeParameter: NSObject, SourceryModel, Diffable, DynamicMemberLookup { +public final class GenericTypeParameter: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "typeName": @@ -32,9 +28,10 @@ public final class GenericTypeParameter: NSObject, SourceryModel, Diffable, Dyna } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "typeName = \(String(describing: self.typeName))" + string.append("typeName = \(String(describing: self.typeName))") return string } @@ -48,6 +45,8 @@ public final class GenericTypeParameter: NSObject, SourceryModel, Diffable, Dyna return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.typeName) @@ -65,7 +64,7 @@ public final class GenericTypeParameter: NSObject, SourceryModel, Diffable, Dyna /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { + guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } diff --git a/SourceryRuntime/Sources/AST/TypeName/Tuple_Linux.swift b/SourceryRuntime/Sources/Linux/AST/TypeName/Tuple_Linux.swift similarity index 91% rename from SourceryRuntime/Sources/AST/TypeName/Tuple_Linux.swift rename to SourceryRuntime/Sources/Linux/AST/TypeName/Tuple_Linux.swift index e1ed0fd8d..eb3fbe225 100644 --- a/SourceryRuntime/Sources/AST/TypeName/Tuple_Linux.swift +++ b/SourceryRuntime/Sources/Linux/AST/TypeName/Tuple_Linux.swift @@ -1,12 +1,8 @@ #if !canImport(ObjectiveC) import Foundation -// For DynamicMemberLookup we need to import Stencil, -// however, this is different from SourceryRuntime.content.generated.swift, because -// it cannot reference Stencil -import Stencil /// Describes tuple type -public final class TupleType: NSObject, SourceryModel, Diffable, DynamicMemberLookup { +public final class TupleType: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "elements": @@ -35,10 +31,11 @@ public final class TupleType: NSObject, SourceryModel, Diffable, DynamicMemberLo } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "name = \(String(describing: self.name)), " - string += "elements = \(String(describing: self.elements))" + string.append("name = \(String(describing: self.name)), ") + string.append("elements = \(String(describing: self.elements))") return string } @@ -53,6 +50,8 @@ public final class TupleType: NSObject, SourceryModel, Diffable, DynamicMemberLo return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) @@ -95,7 +94,7 @@ public final class TupleType: NSObject, SourceryModel, Diffable, DynamicMemberLo } /// Describes tuple type element -public final class TupleElement: NSObject, SourceryModel, Typed, Diffable, DynamicMemberLookup { +public final class TupleElement: NSObject, SourceryModel, Typed, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "name": @@ -132,11 +131,12 @@ public final class TupleElement: NSObject, SourceryModel, Typed, Diffable, Dynam } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "name = \(String(describing: self.name)), " - string += "typeName = \(String(describing: self.typeName)), " - string += "asSource = \(String(describing: self.asSource))" + string.append("name = \(String(describing: self.name)), ") + string.append("typeName = \(String(describing: self.typeName)), ") + string.append("asSource = \(String(describing: self.asSource))") return string } @@ -151,6 +151,8 @@ public final class TupleElement: NSObject, SourceryModel, Typed, Diffable, Dynam return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) diff --git a/SourceryRuntime/Sources/AST/TypeName/TypeName_Linux.swift b/SourceryRuntime/Sources/Linux/AST/TypeName/TypeName_Linux.swift similarity index 98% rename from SourceryRuntime/Sources/AST/TypeName/TypeName_Linux.swift rename to SourceryRuntime/Sources/Linux/AST/TypeName/TypeName_Linux.swift index 46adab4e1..1b7308ae4 100644 --- a/SourceryRuntime/Sources/AST/TypeName/TypeName_Linux.swift +++ b/SourceryRuntime/Sources/Linux/AST/TypeName/TypeName_Linux.swift @@ -4,13 +4,9 @@ // #if !canImport(ObjectiveC) import Foundation -// For DynamicMemberLookup we need to import Stencil, -// however, this is different from SourceryRuntime.content.generated.swift, because -// it cannot reference Stencil -import Stencil /// Describes name of the type used in typed declaration (variable, method parameter or return value etc.) -public final class TypeName: NSObject, SourceryModelWithoutDescription, LosslessStringConvertible, Diffable, DynamicMemberLookup { +public final class TypeName: NSObject, SourceryModelWithoutDescription, LosslessStringConvertible, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "tuple": @@ -225,6 +221,8 @@ public final class TypeName: NSObject, SourceryModelWithoutDescription, Lossless return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) diff --git a/SourceryRuntime/Sources/AST/Type_Linux.swift b/SourceryRuntime/Sources/Linux/AST/Type_Linux.swift similarity index 92% rename from SourceryRuntime/Sources/AST/Type_Linux.swift rename to SourceryRuntime/Sources/Linux/AST/Type_Linux.swift index 620a5a674..e007a4f2d 100644 --- a/SourceryRuntime/Sources/AST/Type_Linux.swift +++ b/SourceryRuntime/Sources/Linux/AST/Type_Linux.swift @@ -4,16 +4,12 @@ // #if !canImport(ObjectiveC) import Foundation -// For DynamicMemberLookup we need to import Stencil, -// however, this is different from SourceryRuntime.content.generated.swift, because -// it cannot reference Stencil -import Stencil /// :nodoc: public typealias AttributeList = [String: [Attribute]] /// Defines Swift type -public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable, DynamicMemberLookup { +public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "implements": @@ -473,41 +469,42 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable, Dyn } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "module = \(String(describing: self.module)), " - string += "imports = \(String(describing: self.imports)), " - string += "allImports = \(String(describing: self.allImports)), " - string += "typealiases = \(String(describing: self.typealiases)), " - string += "isExtension = \(String(describing: self.isExtension)), " - string += "kind = \(String(describing: self.kind)), " - string += "accessLevel = \(String(describing: self.accessLevel)), " - string += "name = \(String(describing: self.name)), " - string += "isUnknownExtension = \(String(describing: self.isUnknownExtension)), " - string += "isGeneric = \(String(describing: self.isGeneric)), " - string += "localName = \(String(describing: self.localName)), " - string += "rawVariables = \(String(describing: self.rawVariables)), " - string += "rawMethods = \(String(describing: self.rawMethods)), " - string += "rawSubscripts = \(String(describing: self.rawSubscripts)), " - string += "initializers = \(String(describing: self.initializers)), " - string += "annotations = \(String(describing: self.annotations)), " - string += "documentation = \(String(describing: self.documentation)), " - string += "staticVariables = \(String(describing: self.staticVariables)), " - string += "staticMethods = \(String(describing: self.staticMethods)), " - string += "classMethods = \(String(describing: self.classMethods)), " - string += "instanceVariables = \(String(describing: self.instanceVariables)), " - string += "instanceMethods = \(String(describing: self.instanceMethods)), " - string += "computedVariables = \(String(describing: self.computedVariables)), " - string += "storedVariables = \(String(describing: self.storedVariables)), " - string += "inheritedTypes = \(String(describing: self.inheritedTypes)), " - string += "inherits = \(String(describing: self.inherits)), " - string += "containedTypes = \(String(describing: self.containedTypes)), " - string += "parentName = \(String(describing: self.parentName)), " - string += "parentTypes = \(String(describing: self.parentTypes)), " - string += "attributes = \(String(describing: self.attributes)), " - string += "modifiers = \(String(describing: self.modifiers)), " - string += "fileName = \(String(describing: self.fileName)), " - string += "genericRequirements = \(String(describing: self.genericRequirements))" + string.append("module = \(String(describing: self.module)), ") + string.append("imports = \(String(describing: self.imports)), ") + string.append("allImports = \(String(describing: self.allImports)), ") + string.append("typealiases = \(String(describing: self.typealiases)), ") + string.append("isExtension = \(String(describing: self.isExtension)), ") + string.append("kind = \(String(describing: self.kind)), ") + string.append("accessLevel = \(String(describing: self.accessLevel)), ") + string.append("name = \(String(describing: self.name)), ") + string.append("isUnknownExtension = \(String(describing: self.isUnknownExtension)), ") + string.append("isGeneric = \(String(describing: self.isGeneric)), ") + string.append("localName = \(String(describing: self.localName)), ") + string.append("rawVariables = \(String(describing: self.rawVariables)), ") + string.append("rawMethods = \(String(describing: self.rawMethods)), ") + string.append("rawSubscripts = \(String(describing: self.rawSubscripts)), ") + string.append("initializers = \(String(describing: self.initializers)), ") + string.append("annotations = \(String(describing: self.annotations)), ") + string.append("documentation = \(String(describing: self.documentation)), ") + string.append("staticVariables = \(String(describing: self.staticVariables)), ") + string.append("staticMethods = \(String(describing: self.staticMethods)), ") + string.append("classMethods = \(String(describing: self.classMethods)), ") + string.append("instanceVariables = \(String(describing: self.instanceVariables)), ") + string.append("instanceMethods = \(String(describing: self.instanceMethods)), ") + string.append("computedVariables = \(String(describing: self.computedVariables)), ") + string.append("storedVariables = \(String(describing: self.storedVariables)), ") + string.append("inheritedTypes = \(String(describing: self.inheritedTypes)), ") + string.append("inherits = \(String(describing: self.inherits)), ") + string.append("containedTypes = \(String(describing: self.containedTypes)), ") + string.append("parentName = \(String(describing: self.parentName)), ") + string.append("parentTypes = \(String(describing: self.parentTypes)), ") + string.append("attributes = \(String(describing: self.attributes)), ") + string.append("modifiers = \(String(describing: self.modifiers)), ") + string.append("fileName = \(String(describing: self.fileName)), ") + string.append("genericRequirements = \(String(describing: self.genericRequirements))") return string } @@ -541,6 +538,8 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable, Dyn return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.module) @@ -621,13 +620,7 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable, Dyn fatalError() }; self.accessLevel = accessLevel self.isGeneric = aDecoder.decode(forKey: "isGeneric") - guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { - withVaList(["genericRequirements"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.genericRequirements = genericRequirements - guard let localName: String = aDecoder.decode(forKey: "localName") else { + guard let localName: String = aDecoder.decode(forKey: "localName") else { withVaList(["localName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } @@ -723,6 +716,12 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable, Dyn fatalError() }; self.modifiers = modifiers self.path = aDecoder.decode(forKey: "path") + guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { + withVaList(["genericRequirements"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.genericRequirements = genericRequirements self.fileName = aDecoder.decode(forKey: "fileName") } @@ -755,8 +754,8 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable, Dyn aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.path, forKey: "path") - aCoder.encode(self.fileName, forKey: "fileName") aCoder.encode(self.genericRequirements, forKey: "genericRequirements") + aCoder.encode(self.fileName, forKey: "fileName") } // sourcery:end diff --git a/SourceryRuntime/Sources/AST/Variable_Linux.swift b/SourceryRuntime/Sources/Linux/AST/Variable_Linux.swift similarity index 89% rename from SourceryRuntime/Sources/AST/Variable_Linux.swift rename to SourceryRuntime/Sources/Linux/AST/Variable_Linux.swift index 95a899d5c..a3924997d 100644 --- a/SourceryRuntime/Sources/AST/Variable_Linux.swift +++ b/SourceryRuntime/Sources/Linux/AST/Variable_Linux.swift @@ -4,16 +4,12 @@ // #if !canImport(ObjectiveC) import Foundation -// For DynamicMemberLookup we need to import Stencil, -// however, this is different from SourceryRuntime.content.generated.swift, because -// it cannot reference Stencil -import Stencil /// :nodoc: public typealias SourceryVariable = Variable /// Defines variable -public final class Variable: NSObject, SourceryModel, Typed, Annotated, Documented, Definition, Diffable, DynamicMemberLookup { +public final class Variable: NSObject, SourceryModel, Typed, Annotated, Documented, Definition, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "readAccess": @@ -165,28 +161,29 @@ public final class Variable: NSObject, SourceryModel, Typed, Annotated, Document } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "name = \(String(describing: self.name)), " - string += "typeName = \(String(describing: self.typeName)), " - string += "isComputed = \(String(describing: self.isComputed)), " - string += "isAsync = \(String(describing: self.isAsync)), " - string += "`throws` = \(String(describing: self.`throws`)), " - string += "isStatic = \(String(describing: self.isStatic)), " - string += "readAccess = \(String(describing: self.readAccess)), " - string += "writeAccess = \(String(describing: self.writeAccess)), " - string += "accessLevel = \(String(describing: self.accessLevel)), " - string += "isMutable = \(String(describing: self.isMutable)), " - string += "defaultValue = \(String(describing: self.defaultValue)), " - string += "annotations = \(String(describing: self.annotations)), " - string += "documentation = \(String(describing: self.documentation)), " - string += "attributes = \(String(describing: self.attributes)), " - string += "modifiers = \(String(describing: self.modifiers)), " - string += "isFinal = \(String(describing: self.isFinal)), " - string += "isLazy = \(String(describing: self.isLazy)), " - string += "isDynamic = \(String(describing: self.isDynamic)), " - string += "definedInTypeName = \(String(describing: self.definedInTypeName)), " - string += "actualDefinedInTypeName = \(String(describing: self.actualDefinedInTypeName))" + string.append("name = \(String(describing: self.name)), ") + string.append("typeName = \(String(describing: self.typeName)), ") + string.append("isComputed = \(String(describing: self.isComputed)), ") + string.append("isAsync = \(String(describing: self.isAsync)), ") + string.append("`throws` = \(String(describing: self.`throws`)), ") + string.append("isStatic = \(String(describing: self.isStatic)), ") + string.append("readAccess = \(String(describing: self.readAccess)), ") + string.append("writeAccess = \(String(describing: self.writeAccess)), ") + string.append("accessLevel = \(String(describing: self.accessLevel)), ") + string.append("isMutable = \(String(describing: self.isMutable)), ") + string.append("defaultValue = \(String(describing: self.defaultValue)), ") + string.append("annotations = \(String(describing: self.annotations)), ") + string.append("documentation = \(String(describing: self.documentation)), ") + string.append("attributes = \(String(describing: self.attributes)), ") + string.append("modifiers = \(String(describing: self.modifiers)), ") + string.append("isFinal = \(String(describing: self.isFinal)), ") + string.append("isLazy = \(String(describing: self.isLazy)), ") + string.append("isDynamic = \(String(describing: self.isDynamic)), ") + string.append("definedInTypeName = \(String(describing: self.definedInTypeName)), ") + string.append("actualDefinedInTypeName = \(String(describing: self.actualDefinedInTypeName))") return string } @@ -213,6 +210,8 @@ public final class Variable: NSObject, SourceryModel, Typed, Annotated, Document return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) diff --git a/SourceryRuntime/Sources/Linux/DynamicMemberLookup_Linux.swift b/SourceryRuntime/Sources/Linux/DynamicMemberLookup_Linux.swift new file mode 100644 index 000000000..4b0865126 --- /dev/null +++ b/SourceryRuntime/Sources/Linux/DynamicMemberLookup_Linux.swift @@ -0,0 +1,37 @@ +// +// Stencil +// Copyright © 2022 Stencil +// MIT Licence +// + +#if !canImport(ObjectiveC) +#if canImport(Stencil) +import Stencil +#else +// This is not supposed to work at all, since in Stencil there is a protocol conformance check against `DynamicMemberLookup`, +// and, of course, a substitute with the "same name" but in `Sourcery` will never satisfy that check. +// Here, we are just mimicking `Stencil.DynamicMemberLookup` to showcase what is happening within the `Sourcery` during runtime. + +/// Marker protocol so we can know which types support `@dynamicMemberLookup`. Add this to your own types that support +/// lookup by String. +public protocol DynamicMemberLookup { + /// Get a value for a given `String` key + subscript(dynamicMember member: String) -> Any? { get } +} + +public extension DynamicMemberLookup where Self: RawRepresentable { + /// Get a value for a given `String` key + subscript(dynamicMember member: String) -> Any? { + switch member { + case "rawValue": + return rawValue + default: + return nil + } + } +} +#endif + +public protocol SourceryDynamicMemberLookup: DynamicMemberLookup {} + +#endif diff --git a/SourceryRuntime/Sources/AST/NSException_Linux.swift b/SourceryRuntime/Sources/Linux/NSException_Linux.swift similarity index 100% rename from SourceryRuntime/Sources/AST/NSException_Linux.swift rename to SourceryRuntime/Sources/Linux/NSException_Linux.swift diff --git a/SourceryRuntime/Sources/TypesCollection_Linux.swift b/SourceryRuntime/Sources/Linux/TypesCollection_Linux.swift similarity index 89% rename from SourceryRuntime/Sources/TypesCollection_Linux.swift rename to SourceryRuntime/Sources/Linux/TypesCollection_Linux.swift index d1a7b3710..a5ff674b0 100644 --- a/SourceryRuntime/Sources/TypesCollection_Linux.swift +++ b/SourceryRuntime/Sources/Linux/TypesCollection_Linux.swift @@ -4,13 +4,9 @@ // #if !canImport(ObjectiveC) import Foundation -// For DynamicMemberLookup we need to import Stencil, -// however, this is different from SourceryRuntime.content.generated.swift, because -// it cannot reference Stencil -import Stencil /// :nodoc: -public class TypesCollection: NSObject, AutoJSExport, DynamicMemberLookup { +public class TypesCollection: NSObject, AutoJSExport, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { return try? types(forKey: member) } diff --git a/SourceryRuntime/Sources/Types_Linux.swift b/SourceryRuntime/Sources/Linux/Types_Linux.swift similarity index 94% rename from SourceryRuntime/Sources/Types_Linux.swift rename to SourceryRuntime/Sources/Linux/Types_Linux.swift index fd5b1b45b..b5d93c267 100644 --- a/SourceryRuntime/Sources/Types_Linux.swift +++ b/SourceryRuntime/Sources/Linux/Types_Linux.swift @@ -4,14 +4,10 @@ // #if !canImport(ObjectiveC) import Foundation -// For DynamicMemberLookup we need to import Stencil, -// however, this is different from SourceryRuntime.content.generated.swift, because -// it cannot reference Stencil -import Stencil // sourcery: skipJSExport /// Collection of scanned types for accessing in templates -public final class Types: NSObject, SourceryModel, Diffable, DynamicMemberLookup { +public final class Types: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "types": @@ -52,10 +48,11 @@ public final class Types: NSObject, SourceryModel, Diffable, DynamicMemberLookup } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "types = \(String(describing: self.types)), " - string += "typealiases = \(String(describing: self.typealiases))" + string.append("types = \(String(describing: self.types)), ") + string.append("typealiases = \(String(describing: self.typealiases))") return string } @@ -70,6 +67,8 @@ public final class Types: NSObject, SourceryModel, Diffable, DynamicMemberLookup return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.types) diff --git a/SourceryRuntime/Sources/AST/AssociatedType.swift b/SourceryRuntime/Sources/macOS/AST/AssociatedType.swift similarity index 92% rename from SourceryRuntime/Sources/AST/AssociatedType.swift rename to SourceryRuntime/Sources/macOS/AST/AssociatedType.swift index 0f485d41b..51c5ade9b 100644 --- a/SourceryRuntime/Sources/AST/AssociatedType.swift +++ b/SourceryRuntime/Sources/macOS/AST/AssociatedType.swift @@ -22,10 +22,11 @@ public final class AssociatedType: NSObject, SourceryModel { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "name = \(String(describing: self.name)), " - string += "typeName = \(String(describing: self.typeName))" + string.append("name = \(String(describing: self.name)), ") + string.append("typeName = \(String(describing: self.typeName))") return string } @@ -40,6 +41,8 @@ public final class AssociatedType: NSObject, SourceryModel { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) diff --git a/SourceryRuntime/Sources/AST/AssociatedValue.swift b/SourceryRuntime/Sources/macOS/AST/AssociatedValue.swift similarity index 91% rename from SourceryRuntime/Sources/AST/AssociatedValue.swift rename to SourceryRuntime/Sources/macOS/AST/AssociatedValue.swift index be66733e0..1fcb2915b 100644 --- a/SourceryRuntime/Sources/AST/AssociatedValue.swift +++ b/SourceryRuntime/Sources/macOS/AST/AssociatedValue.swift @@ -45,13 +45,14 @@ public final class AssociatedValue: NSObject, SourceryModel, AutoDescription, Ty } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "localName = \(String(describing: self.localName)), " - string += "externalName = \(String(describing: self.externalName)), " - string += "typeName = \(String(describing: self.typeName)), " - string += "defaultValue = \(String(describing: self.defaultValue)), " - string += "annotations = \(String(describing: self.annotations))" + string.append("localName = \(String(describing: self.localName)), ") + string.append("externalName = \(String(describing: self.externalName)), ") + string.append("typeName = \(String(describing: self.typeName)), ") + string.append("defaultValue = \(String(describing: self.defaultValue)), ") + string.append("annotations = \(String(describing: self.annotations))") return string } @@ -69,6 +70,8 @@ public final class AssociatedValue: NSObject, SourceryModel, AutoDescription, Ty return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.localName) diff --git a/SourceryRuntime/Sources/AST/ClosureParameter.swift b/SourceryRuntime/Sources/macOS/AST/ClosureParameter.swift similarity index 88% rename from SourceryRuntime/Sources/AST/ClosureParameter.swift rename to SourceryRuntime/Sources/macOS/AST/ClosureParameter.swift index 5cf194151..57e4203b5 100644 --- a/SourceryRuntime/Sources/AST/ClosureParameter.swift +++ b/SourceryRuntime/Sources/macOS/AST/ClosureParameter.swift @@ -66,6 +66,8 @@ public final class ClosureParameter: NSObject, SourceryModel, Typed, Annotated { return (labels.nilIfEmpty ?? "_") + typeSuffix } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.argumentLabel) @@ -79,16 +81,17 @@ public final class ClosureParameter: NSObject, SourceryModel, Typed, Annotated { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "argumentLabel = \(String(describing: self.argumentLabel)), " - string += "name = \(String(describing: self.name)), " - string += "typeName = \(String(describing: self.typeName)), " - string += "`inout` = \(String(describing: self.`inout`)), " - string += "typeAttributes = \(String(describing: self.typeAttributes)), " - string += "defaultValue = \(String(describing: self.defaultValue)), " - string += "annotations = \(String(describing: self.annotations)), " - string += "asSource = \(String(describing: self.asSource))" + string.append("argumentLabel = \(String(describing: self.argumentLabel)), ") + string.append("name = \(String(describing: self.name)), ") + string.append("typeName = \(String(describing: self.typeName)), ") + string.append("`inout` = \(String(describing: self.`inout`)), ") + string.append("typeAttributes = \(String(describing: self.typeAttributes)), ") + string.append("defaultValue = \(String(describing: self.defaultValue)), ") + string.append("annotations = \(String(describing: self.annotations)), ") + string.append("asSource = \(String(describing: self.asSource))") return string } @@ -118,8 +121,8 @@ public final class ClosureParameter: NSObject, SourceryModel, Typed, Annotated { fatalError() }; self.typeName = typeName self.`inout` = aDecoder.decode(forKey: "`inout`") - self.isVariadic = aDecoder.decode(forKey: "isVariadic") self.type = aDecoder.decode(forKey: "type") + self.isVariadic = aDecoder.decode(forKey: "isVariadic") self.defaultValue = aDecoder.decode(forKey: "defaultValue") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in @@ -135,8 +138,8 @@ public final class ClosureParameter: NSObject, SourceryModel, Typed, Annotated { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.`inout`, forKey: "`inout`") - aCoder.encode(self.isVariadic, forKey: "isVariadic") aCoder.encode(self.type, forKey: "type") + aCoder.encode(self.isVariadic, forKey: "isVariadic") aCoder.encode(self.defaultValue, forKey: "defaultValue") aCoder.encode(self.annotations, forKey: "annotations") } diff --git a/SourceryRuntime/Sources/AST/Enum.swift b/SourceryRuntime/Sources/macOS/AST/Enum.swift similarity index 94% rename from SourceryRuntime/Sources/AST/Enum.swift rename to SourceryRuntime/Sources/macOS/AST/Enum.swift index 10b59c0d2..da43ffa11 100644 --- a/SourceryRuntime/Sources/AST/Enum.swift +++ b/SourceryRuntime/Sources/macOS/AST/Enum.swift @@ -91,12 +91,13 @@ public final class Enum: Type { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = super.description - string += ", " - string += "cases = \(String(describing: self.cases)), " - string += "rawTypeName = \(String(describing: self.rawTypeName)), " - string += "hasAssociatedValues = \(String(describing: self.hasAssociatedValues))" + string.append(", ") + string.append("cases = \(String(describing: self.cases)), ") + string.append("rawTypeName = \(String(describing: self.rawTypeName)), ") + string.append("hasAssociatedValues = \(String(describing: self.hasAssociatedValues))") return string } @@ -112,6 +113,8 @@ public final class Enum: Type { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.cases) diff --git a/SourceryRuntime/Sources/AST/EnumCase.swift b/SourceryRuntime/Sources/macOS/AST/EnumCase.swift similarity index 90% rename from SourceryRuntime/Sources/AST/EnumCase.swift rename to SourceryRuntime/Sources/macOS/AST/EnumCase.swift index b8d4ffd9b..8b522ea29 100644 --- a/SourceryRuntime/Sources/AST/EnumCase.swift +++ b/SourceryRuntime/Sources/macOS/AST/EnumCase.swift @@ -47,15 +47,16 @@ public final class EnumCase: NSObject, SourceryModel, AutoDescription, Annotated } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "name = \(String(describing: self.name)), " - string += "rawValue = \(String(describing: self.rawValue)), " - string += "associatedValues = \(String(describing: self.associatedValues)), " - string += "annotations = \(String(describing: self.annotations)), " - string += "documentation = \(String(describing: self.documentation)), " - string += "indirect = \(String(describing: self.indirect)), " - string += "hasAssociatedValue = \(String(describing: self.hasAssociatedValue))" + string.append("name = \(String(describing: self.name)), ") + string.append("rawValue = \(String(describing: self.rawValue)), ") + string.append("associatedValues = \(String(describing: self.associatedValues)), ") + string.append("annotations = \(String(describing: self.annotations)), ") + string.append("documentation = \(String(describing: self.documentation)), ") + string.append("indirect = \(String(describing: self.indirect)), ") + string.append("hasAssociatedValue = \(String(describing: self.hasAssociatedValue))") return string } @@ -74,6 +75,8 @@ public final class EnumCase: NSObject, SourceryModel, AutoDescription, Annotated return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) diff --git a/SourceryRuntime/Sources/AST/GenericParameter.swift b/SourceryRuntime/Sources/macOS/AST/GenericParameter.swift similarity index 91% rename from SourceryRuntime/Sources/AST/GenericParameter.swift rename to SourceryRuntime/Sources/macOS/AST/GenericParameter.swift index 457fb6bdd..d1a1aa73b 100644 --- a/SourceryRuntime/Sources/AST/GenericParameter.swift +++ b/SourceryRuntime/Sources/macOS/AST/GenericParameter.swift @@ -18,10 +18,11 @@ public final class GenericParameter: NSObject, SourceryModel, Diffable { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "name = \(String(describing: self.name)), " - string += "inheritedTypeName = \(String(describing: self.inheritedTypeName))" + string.append("name = \(String(describing: self.name)), ") + string.append("inheritedTypeName = \(String(describing: self.inheritedTypeName))") return string } @@ -36,6 +37,8 @@ public final class GenericParameter: NSObject, SourceryModel, Diffable { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) @@ -55,7 +58,7 @@ public final class GenericParameter: NSObject, SourceryModel, Diffable { /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { + guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } diff --git a/SourceryRuntime/Sources/AST/GenericRequirement.swift b/SourceryRuntime/Sources/macOS/AST/GenericRequirement.swift similarity index 92% rename from SourceryRuntime/Sources/AST/GenericRequirement.swift rename to SourceryRuntime/Sources/macOS/AST/GenericRequirement.swift index 97fa99fdd..9507e210d 100644 --- a/SourceryRuntime/Sources/AST/GenericRequirement.swift +++ b/SourceryRuntime/Sources/macOS/AST/GenericRequirement.swift @@ -36,12 +36,13 @@ public class GenericRequirement: NSObject, SourceryModel, Diffable { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "leftType = \(String(describing: self.leftType)), " - string += "rightType = \(String(describing: self.rightType)), " - string += "relationship = \(String(describing: self.relationship)), " - string += "relationshipSyntax = \(String(describing: self.relationshipSyntax))" + string.append("leftType = \(String(describing: self.leftType)), ") + string.append("rightType = \(String(describing: self.rightType)), ") + string.append("relationship = \(String(describing: self.relationship)), ") + string.append("relationshipSyntax = \(String(describing: self.relationshipSyntax))") return string } @@ -58,6 +59,8 @@ public class GenericRequirement: NSObject, SourceryModel, Diffable { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.leftType) diff --git a/SourceryRuntime/Sources/AST/Method.swift b/SourceryRuntime/Sources/macOS/AST/Method.swift similarity index 92% rename from SourceryRuntime/Sources/AST/Method.swift rename to SourceryRuntime/Sources/macOS/AST/Method.swift index 28f0a9d35..068cf8c9e 100644 --- a/SourceryRuntime/Sources/AST/Method.swift +++ b/SourceryRuntime/Sources/macOS/AST/Method.swift @@ -213,25 +213,26 @@ public final class Method: NSObject, SourceryModel, Annotated, Documented, Defin } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "name = \(String(describing: self.name)), " - string += "selectorName = \(String(describing: self.selectorName)), " - string += "parameters = \(String(describing: self.parameters)), " - string += "returnTypeName = \(String(describing: self.returnTypeName)), " - string += "isAsync = \(String(describing: self.isAsync)), " - string += "`throws` = \(String(describing: self.`throws`)), " - string += "`rethrows` = \(String(describing: self.`rethrows`)), " - string += "accessLevel = \(String(describing: self.accessLevel)), " - string += "isStatic = \(String(describing: self.isStatic)), " - string += "isClass = \(String(describing: self.isClass)), " - string += "isFailableInitializer = \(String(describing: self.isFailableInitializer)), " - string += "annotations = \(String(describing: self.annotations)), " - string += "documentation = \(String(describing: self.documentation)), " - string += "definedInTypeName = \(String(describing: self.definedInTypeName)), " - string += "attributes = \(String(describing: self.attributes)), " - string += "modifiers = \(String(describing: self.modifiers)), " - string += "genericRequirements = \(String(describing: self.genericRequirements))" + string.append("name = \(String(describing: self.name)), ") + string.append("selectorName = \(String(describing: self.selectorName)), ") + string.append("parameters = \(String(describing: self.parameters)), ") + string.append("returnTypeName = \(String(describing: self.returnTypeName)), ") + string.append("isAsync = \(String(describing: self.isAsync)), ") + string.append("`throws` = \(String(describing: self.`throws`)), ") + string.append("`rethrows` = \(String(describing: self.`rethrows`)), ") + string.append("accessLevel = \(String(describing: self.accessLevel)), ") + string.append("isStatic = \(String(describing: self.isStatic)), ") + string.append("isClass = \(String(describing: self.isClass)), ") + string.append("isFailableInitializer = \(String(describing: self.isFailableInitializer)), ") + string.append("annotations = \(String(describing: self.annotations)), ") + string.append("documentation = \(String(describing: self.documentation)), ") + string.append("definedInTypeName = \(String(describing: self.definedInTypeName)), ") + string.append("attributes = \(String(describing: self.attributes)), ") + string.append("modifiers = \(String(describing: self.modifiers)), ") + string.append("genericRequirements = \(String(describing: self.genericRequirements))") return string } @@ -261,6 +262,8 @@ public final class Method: NSObject, SourceryModel, Annotated, Documented, Defin return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) @@ -373,7 +376,7 @@ public final class Method: NSObject, SourceryModel, Annotated, Documented, Defin } fatalError() }; self.modifiers = modifiers - guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { + guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { withVaList(["genericRequirements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } diff --git a/SourceryRuntime/Sources/AST/MethodParameter.swift b/SourceryRuntime/Sources/macOS/AST/MethodParameter.swift similarity index 87% rename from SourceryRuntime/Sources/AST/MethodParameter.swift rename to SourceryRuntime/Sources/macOS/AST/MethodParameter.swift index 0ddaa1729..6f15b3776 100644 --- a/SourceryRuntime/Sources/AST/MethodParameter.swift +++ b/SourceryRuntime/Sources/macOS/AST/MethodParameter.swift @@ -61,7 +61,10 @@ public class MethodParameter: NSObject, SourceryModel, Typed, Annotated, Diffabl } public var asSource: String { - let typeSuffix = ": \(`inout` ? "inout " : "")\(typeName.asSource)\(defaultValue.map { " = \($0)" } ?? "")" + (isVariadic ? "..." : "") + let values: String = defaultValue.map { " = \($0)" } ?? "" + let variadicity: String = isVariadic ? "..." : "" + let inoutness: String = `inout` ? "inout " : "" + let typeSuffix = ": \(inoutness)\(typeName.asSource)\(values)\(variadicity)" guard argumentLabel != name else { return name + typeSuffix } @@ -74,17 +77,18 @@ public class MethodParameter: NSObject, SourceryModel, Typed, Annotated, Diffabl } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "argumentLabel = \(String(describing: self.argumentLabel)), " - string += "name = \(String(describing: self.name)), " - string += "typeName = \(String(describing: self.typeName)), " - string += "`inout` = \(String(describing: self.`inout`)), " - string += "isVariadic = \(String(describing: self.isVariadic)), " - string += "typeAttributes = \(String(describing: self.typeAttributes)), " - string += "defaultValue = \(String(describing: self.defaultValue)), " - string += "annotations = \(String(describing: self.annotations)), " - string += "asSource = \(String(describing: self.asSource))" + string.append("argumentLabel = \(String(describing: self.argumentLabel)), ") + string.append("name = \(String(describing: self.name)), ") + string.append("typeName = \(String(describing: self.typeName)), ") + string.append("`inout` = \(String(describing: self.`inout`)), ") + string.append("isVariadic = \(String(describing: self.isVariadic)), ") + string.append("typeAttributes = \(String(describing: self.typeAttributes)), ") + string.append("defaultValue = \(String(describing: self.defaultValue)), ") + string.append("annotations = \(String(describing: self.annotations)), ") + string.append("asSource = \(String(describing: self.asSource))") return string } @@ -104,6 +108,8 @@ public class MethodParameter: NSObject, SourceryModel, Typed, Annotated, Diffabl return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.argumentLabel) diff --git a/SourceryRuntime/Sources/AST/Subscript.swift b/SourceryRuntime/Sources/macOS/AST/Subscript.swift similarity index 87% rename from SourceryRuntime/Sources/AST/Subscript.swift rename to SourceryRuntime/Sources/macOS/AST/Subscript.swift index 3eb29ab3f..658bab6e3 100644 --- a/SourceryRuntime/Sources/AST/Subscript.swift +++ b/SourceryRuntime/Sources/macOS/AST/Subscript.swift @@ -131,26 +131,27 @@ public final class Subscript: NSObject, SourceryModel, Annotated, Documented, De } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "parameters = \(String(describing: self.parameters)), " - string += "returnTypeName = \(String(describing: self.returnTypeName)), " - string += "actualReturnTypeName = \(String(describing: self.actualReturnTypeName)), " - string += "isFinal = \(String(describing: self.isFinal)), " - string += "readAccess = \(String(describing: self.readAccess)), " - string += "writeAccess = \(String(describing: self.writeAccess)), " - string += "isAsync = \(String(describing: self.isAsync)), " - string += "`throws` = \(String(describing: self.throws)), " - string += "isMutable = \(String(describing: self.isMutable)), " - string += "annotations = \(String(describing: self.annotations)), " - string += "documentation = \(String(describing: self.documentation)), " - string += "definedInTypeName = \(String(describing: self.definedInTypeName)), " - string += "actualDefinedInTypeName = \(String(describing: self.actualDefinedInTypeName)), " - string += "genericParameters = \(String(describing: self.genericParameters)), " - string += "genericRequirements = \(String(describing: self.genericRequirements)), " - string += "isGeneric = \(String(describing: self.isGeneric)), " - string += "attributes = \(String(describing: self.attributes)), " - string += "modifiers = \(String(describing: self.modifiers))" + string.append("parameters = \(String(describing: self.parameters)), ") + string.append("returnTypeName = \(String(describing: self.returnTypeName)), ") + string.append("actualReturnTypeName = \(String(describing: self.actualReturnTypeName)), ") + string.append("isFinal = \(String(describing: self.isFinal)), ") + string.append("readAccess = \(String(describing: self.readAccess)), ") + string.append("writeAccess = \(String(describing: self.writeAccess)), ") + string.append("isAsync = \(String(describing: self.isAsync)), ") + string.append("`throws` = \(String(describing: self.throws)), ") + string.append("isMutable = \(String(describing: self.isMutable)), ") + string.append("annotations = \(String(describing: self.annotations)), ") + string.append("documentation = \(String(describing: self.documentation)), ") + string.append("definedInTypeName = \(String(describing: self.definedInTypeName)), ") + string.append("actualDefinedInTypeName = \(String(describing: self.actualDefinedInTypeName)), ") + string.append("genericParameters = \(String(describing: self.genericParameters)), ") + string.append("genericRequirements = \(String(describing: self.genericRequirements)), ") + string.append("isGeneric = \(String(describing: self.isGeneric)), ") + string.append("attributes = \(String(describing: self.attributes)), ") + string.append("modifiers = \(String(describing: self.modifiers))") return string } @@ -176,6 +177,8 @@ public final class Subscript: NSObject, SourceryModel, Annotated, Documented, De return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.parameters) @@ -217,71 +220,71 @@ public final class Subscript: NSObject, SourceryModel, Annotated, Documented, De /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let parameters: [MethodParameter] = aDecoder.decode(forKey: "parameters") else { + guard let parameters: [MethodParameter] = aDecoder.decode(forKey: "parameters") else { withVaList(["parameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.parameters = parameters - guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { + guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { withVaList(["returnTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.returnTypeName = returnTypeName self.returnType = aDecoder.decode(forKey: "returnType") - guard let readAccess: String = aDecoder.decode(forKey: "readAccess") else { + guard let readAccess: String = aDecoder.decode(forKey: "readAccess") else { withVaList(["readAccess"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.readAccess = readAccess - guard let writeAccess: String = aDecoder.decode(forKey: "writeAccess") else { + guard let writeAccess: String = aDecoder.decode(forKey: "writeAccess") else { withVaList(["writeAccess"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.writeAccess = writeAccess - guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { + self.isAsync = aDecoder.decode(forKey: "isAsync") + self.`throws` = aDecoder.decode(forKey: "`throws`") + guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations - guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { + guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation - self.isAsync = aDecoder.decode(forKey: "isAsync") - self.`throws` = aDecoder.decode(forKey: "`throws`") self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") self.definedInType = aDecoder.decode(forKey: "definedInType") - guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { + guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes - guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { + guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers - guard let genericParameters: [GenericParameter] = aDecoder.decode(forKey: "genericParameters") else { + guard let genericParameters: [GenericParameter] = aDecoder.decode(forKey: "genericParameters") else { withVaList(["genericParameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.genericParameters = genericParameters - guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { + }; self.genericParameters = genericParameters + guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { withVaList(["genericRequirements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.genericRequirements = genericRequirements + }; self.genericRequirements = genericRequirements } /// :nodoc: @@ -297,10 +300,10 @@ public final class Subscript: NSObject, SourceryModel, Annotated, Documented, De aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") aCoder.encode(self.definedInType, forKey: "definedInType") - aCoder.encode(self.genericParameters, forKey: "genericParameters") - aCoder.encode(self.genericRequirements, forKey: "genericRequirements") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") + aCoder.encode(self.genericParameters, forKey: "genericParameters") + aCoder.encode(self.genericRequirements, forKey: "genericRequirements") } // sourcery:end diff --git a/SourceryRuntime/Sources/AST/Type.swift b/SourceryRuntime/Sources/macOS/AST/Type.swift similarity index 91% rename from SourceryRuntime/Sources/AST/Type.swift rename to SourceryRuntime/Sources/macOS/AST/Type.swift index 2ad38cee2..adf292bd6 100644 --- a/SourceryRuntime/Sources/AST/Type.swift +++ b/SourceryRuntime/Sources/macOS/AST/Type.swift @@ -4,7 +4,6 @@ // #if canImport(ObjectiveC) import Foundation -import Stencil /// :nodoc: public typealias AttributeList = [String: [Attribute]] @@ -426,41 +425,43 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { - var string = "\(Swift.type(of: self)): " - string += "module = \(String(describing: self.module)), " - string += "imports = \(String(describing: self.imports)), " - string += "allImports = \(String(describing: self.allImports)), " - string += "typealiases = \(String(describing: self.typealiases)), " - string += "isExtension = \(String(describing: self.isExtension)), " - string += "kind = \(String(describing: self.kind)), " - string += "accessLevel = \(String(describing: self.accessLevel)), " - string += "name = \(String(describing: self.name)), " - string += "isUnknownExtension = \(String(describing: self.isUnknownExtension)), " - string += "isGeneric = \(String(describing: self.isGeneric)), " - string += "localName = \(String(describing: self.localName)), " - string += "rawVariables = \(String(describing: self.rawVariables)), " - string += "rawMethods = \(String(describing: self.rawMethods)), " - string += "rawSubscripts = \(String(describing: self.rawSubscripts)), " - string += "initializers = \(String(describing: self.initializers)), " - string += "annotations = \(String(describing: self.annotations)), " - string += "documentation = \(String(describing: self.documentation)), " - string += "staticVariables = \(String(describing: self.staticVariables)), " - string += "staticMethods = \(String(describing: self.staticMethods)), " - string += "classMethods = \(String(describing: self.classMethods)), " - string += "instanceVariables = \(String(describing: self.instanceVariables)), " - string += "instanceMethods = \(String(describing: self.instanceMethods)), " - string += "computedVariables = \(String(describing: self.computedVariables)), " - string += "storedVariables = \(String(describing: self.storedVariables)), " - string += "inheritedTypes = \(String(describing: self.inheritedTypes)), " - string += "inherits = \(String(describing: self.inherits)), " - string += "containedTypes = \(String(describing: self.containedTypes)), " - string += "parentName = \(String(describing: self.parentName)), " - string += "parentTypes = \(String(describing: self.parentTypes)), " - string += "attributes = \(String(describing: self.attributes)), " - string += "modifiers = \(String(describing: self.modifiers)), " - string += "fileName = \(String(describing: self.fileName)), " - string += "genericRequirements = \(String(describing: self.genericRequirements))" + let type: Type.Type = Swift.type(of: self) + var string = "\(type): " + string.append("module = \(String(describing: self.module)), ") + string.append("imports = \(String(describing: self.imports)), ") + string.append("allImports = \(String(describing: self.allImports)), ") + string.append("typealiases = \(String(describing: self.typealiases)), ") + string.append("isExtension = \(String(describing: self.isExtension)), ") + string.append("kind = \(String(describing: self.kind)), ") + string.append("accessLevel = \(String(describing: self.accessLevel)), ") + string.append("name = \(String(describing: self.name)), ") + string.append("isUnknownExtension = \(String(describing: self.isUnknownExtension)), ") + string.append("isGeneric = \(String(describing: self.isGeneric)), ") + string.append("localName = \(String(describing: self.localName)), ") + string.append("rawVariables = \(String(describing: self.rawVariables)), ") + string.append("rawMethods = \(String(describing: self.rawMethods)), ") + string.append("rawSubscripts = \(String(describing: self.rawSubscripts)), ") + string.append("initializers = \(String(describing: self.initializers)), ") + string.append("annotations = \(String(describing: self.annotations)), ") + string.append("documentation = \(String(describing: self.documentation)), ") + string.append("staticVariables = \(String(describing: self.staticVariables)), ") + string.append("staticMethods = \(String(describing: self.staticMethods)), ") + string.append("classMethods = \(String(describing: self.classMethods)), ") + string.append("instanceVariables = \(String(describing: self.instanceVariables)), ") + string.append("instanceMethods = \(String(describing: self.instanceMethods)), ") + string.append("computedVariables = \(String(describing: self.computedVariables)), ") + string.append("storedVariables = \(String(describing: self.storedVariables)), ") + string.append("inheritedTypes = \(String(describing: self.inheritedTypes)), ") + string.append("inherits = \(String(describing: self.inherits)), ") + string.append("containedTypes = \(String(describing: self.containedTypes)), ") + string.append("parentName = \(String(describing: self.parentName)), ") + string.append("parentTypes = \(String(describing: self.parentTypes)), ") + string.append("attributes = \(String(describing: self.attributes)), ") + string.append("modifiers = \(String(describing: self.modifiers)), ") + string.append("fileName = \(String(describing: self.fileName)), ") + string.append("genericRequirements = \(String(describing: self.genericRequirements))") return string } @@ -494,6 +495,8 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.module) @@ -574,13 +577,7 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable { fatalError() }; self.accessLevel = accessLevel self.isGeneric = aDecoder.decode(forKey: "isGeneric") - guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { - withVaList(["genericRequirements"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.genericRequirements = genericRequirements - guard let localName: String = aDecoder.decode(forKey: "localName") else { + guard let localName: String = aDecoder.decode(forKey: "localName") else { withVaList(["localName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } @@ -676,6 +673,12 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable { fatalError() }; self.modifiers = modifiers self.path = aDecoder.decode(forKey: "path") + guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { + withVaList(["genericRequirements"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.genericRequirements = genericRequirements self.fileName = aDecoder.decode(forKey: "fileName") } @@ -708,8 +711,8 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable { aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.path, forKey: "path") - aCoder.encode(self.fileName, forKey: "fileName") aCoder.encode(self.genericRequirements, forKey: "genericRequirements") + aCoder.encode(self.fileName, forKey: "fileName") } // sourcery:end diff --git a/SourceryRuntime/Sources/AST/TypeName/Closure.swift b/SourceryRuntime/Sources/macOS/AST/TypeName/Closure.swift similarity index 89% rename from SourceryRuntime/Sources/AST/TypeName/Closure.swift rename to SourceryRuntime/Sources/macOS/AST/TypeName/Closure.swift index d01e97705..af6bd0b64 100644 --- a/SourceryRuntime/Sources/AST/TypeName/Closure.swift +++ b/SourceryRuntime/Sources/macOS/AST/TypeName/Closure.swift @@ -70,17 +70,18 @@ public final class ClosureType: NSObject, SourceryModel, Diffable { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "name = \(String(describing: self.name)), " - string += "parameters = \(String(describing: self.parameters)), " - string += "returnTypeName = \(String(describing: self.returnTypeName)), " - string += "actualReturnTypeName = \(String(describing: self.actualReturnTypeName)), " - string += "isAsync = \(String(describing: self.isAsync)), " - string += "asyncKeyword = \(String(describing: self.asyncKeyword)), " - string += "`throws` = \(String(describing: self.`throws`)), " - string += "throwsOrRethrowsKeyword = \(String(describing: self.throwsOrRethrowsKeyword)), " - string += "asSource = \(String(describing: self.asSource))" + string.append("name = \(String(describing: self.name)), ") + string.append("parameters = \(String(describing: self.parameters)), ") + string.append("returnTypeName = \(String(describing: self.returnTypeName)), ") + string.append("actualReturnTypeName = \(String(describing: self.actualReturnTypeName)), ") + string.append("isAsync = \(String(describing: self.isAsync)), ") + string.append("asyncKeyword = \(String(describing: self.asyncKeyword)), ") + string.append("`throws` = \(String(describing: self.`throws`)), ") + string.append("throwsOrRethrowsKeyword = \(String(describing: self.throwsOrRethrowsKeyword)), ") + string.append("asSource = \(String(describing: self.asSource))") return string } @@ -100,6 +101,8 @@ public final class ClosureType: NSObject, SourceryModel, Diffable { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) diff --git a/SourceryRuntime/Sources/AST/TypeName/GenericTypeParameter.swift b/SourceryRuntime/Sources/macOS/AST/TypeName/GenericTypeParameter.swift similarity index 92% rename from SourceryRuntime/Sources/AST/TypeName/GenericTypeParameter.swift rename to SourceryRuntime/Sources/macOS/AST/TypeName/GenericTypeParameter.swift index 03839dc07..ea822a6ac 100644 --- a/SourceryRuntime/Sources/AST/TypeName/GenericTypeParameter.swift +++ b/SourceryRuntime/Sources/macOS/AST/TypeName/GenericTypeParameter.swift @@ -19,9 +19,10 @@ public final class GenericTypeParameter: NSObject, SourceryModel, Diffable { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "typeName = \(String(describing: self.typeName))" + string.append("typeName = \(String(describing: self.typeName))") return string } @@ -35,6 +36,8 @@ public final class GenericTypeParameter: NSObject, SourceryModel, Diffable { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.typeName) @@ -52,7 +55,7 @@ public final class GenericTypeParameter: NSObject, SourceryModel, Diffable { /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { + guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } diff --git a/SourceryRuntime/Sources/AST/TypeName/Tuple.swift b/SourceryRuntime/Sources/macOS/AST/TypeName/Tuple.swift similarity index 92% rename from SourceryRuntime/Sources/AST/TypeName/Tuple.swift rename to SourceryRuntime/Sources/macOS/AST/TypeName/Tuple.swift index 7db544efb..996709bd4 100644 --- a/SourceryRuntime/Sources/AST/TypeName/Tuple.swift +++ b/SourceryRuntime/Sources/macOS/AST/TypeName/Tuple.swift @@ -24,10 +24,11 @@ public final class TupleType: NSObject, SourceryModel, Diffable { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "name = \(String(describing: self.name)), " - string += "elements = \(String(describing: self.elements))" + string.append("name = \(String(describing: self.name)), ") + string.append("elements = \(String(describing: self.elements))") return string } @@ -42,6 +43,8 @@ public final class TupleType: NSObject, SourceryModel, Diffable { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) @@ -110,11 +113,12 @@ public final class TupleElement: NSObject, SourceryModel, Typed, Diffable { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "name = \(String(describing: self.name)), " - string += "typeName = \(String(describing: self.typeName)), " - string += "asSource = \(String(describing: self.asSource))" + string.append("name = \(String(describing: self.name)), ") + string.append("typeName = \(String(describing: self.typeName)), ") + string.append("asSource = \(String(describing: self.asSource))") return string } @@ -129,6 +133,8 @@ public final class TupleElement: NSObject, SourceryModel, Typed, Diffable { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) diff --git a/SourceryRuntime/Sources/AST/TypeName/TypeName.swift b/SourceryRuntime/Sources/macOS/AST/TypeName/TypeName.swift similarity index 91% rename from SourceryRuntime/Sources/AST/TypeName/TypeName.swift rename to SourceryRuntime/Sources/macOS/AST/TypeName/TypeName.swift index 5a7d0f824..9f386ec6b 100644 --- a/SourceryRuntime/Sources/AST/TypeName/TypeName.swift +++ b/SourceryRuntime/Sources/macOS/AST/TypeName/TypeName.swift @@ -25,7 +25,9 @@ public final class TypeName: NSObject, SourceryModelWithoutDescription, Lossless let optionalSuffix: String // TODO: TBR - if !name.hasPrefix("Optional<") && !name.contains(" where ") { + let hasPrefix: Bool = name.hasPrefix("Optional<") as Bool + let containsName: Bool = name.contains(" where ") as Bool + if !hasPrefix && !containsName { if isOptional { optionalSuffix = "?" } else if isImplicitlyUnwrappedOptional { @@ -139,24 +141,25 @@ public final class TypeName: NSObject, SourceryModelWithoutDescription, Lossless /// Prints typename as it would appear on definition public var asSource: String { // TODO: TBR special treatment - let specialTreatment = isOptional && name.hasPrefix("Optional<") + let specialTreatment: Bool = isOptional && name.hasPrefix("Optional<") - var description = ( - attributes.flatMap({ $0.value }).map({ $0.asSource }).sorted() + - modifiers.map({ $0.asSource }) + - [specialTreatment ? name : unwrappedTypeName] - ).joined(separator: " ") + let attributeValues: [Attribute] = attributes.flatMap { $0.value } + let attributeValuesUnsorted: [String] = attributeValues.map { $0.asSource } + var attributes: [String] = attributeValuesUnsorted.sorted() + attributes.append(contentsOf: modifiers.map({ $0.asSource })) + attributes.append(contentsOf: [specialTreatment ? name : unwrappedTypeName]) + var description = attributes.joined(separator: " ") - if let _ = self.dictionary { // array and dictionary cases are covered by the unwrapped type name +// if let _ = self.dictionary { // array and dictionary cases are covered by the unwrapped type name // description.append(dictionary.asSource) - } else if let _ = self.array { +// } else if let _ = self.array { // description.append(array.asSource) - } else if let _ = self.generic { +// } else if let _ = self.generic { // let arguments = generic.typeParameters // .map({ $0.typeName.asSource }) // .joined(separator: ", ") // description.append("<\(arguments)>") - } +// } if !specialTreatment { if isImplicitlyUnwrappedOptional { description.append("!") @@ -169,11 +172,10 @@ public final class TypeName: NSObject, SourceryModelWithoutDescription, Lossless } public override var description: String { - ( - attributes.flatMap({ $0.value }).map({ $0.asSource }).sorted() + - modifiers.map({ $0.asSource }) + - [name] - ).joined(separator: " ") + var description: [String] = attributes.flatMap({ $0.value }).map({ $0.asSource }).sorted() + description.append(contentsOf: modifiers.map({ $0.asSource })) + description.append(contentsOf: [name]) + return description.joined(separator: " ") } public func diffAgainst(_ object: Any?) -> DiffableResult { @@ -195,6 +197,7 @@ public final class TypeName: NSObject, SourceryModelWithoutDescription, Lossless return results } + public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) diff --git a/SourceryRuntime/Sources/AST/Variable.swift b/SourceryRuntime/Sources/macOS/AST/Variable.swift similarity index 89% rename from SourceryRuntime/Sources/AST/Variable.swift rename to SourceryRuntime/Sources/macOS/AST/Variable.swift index 5f20146ff..c20333a97 100644 --- a/SourceryRuntime/Sources/AST/Variable.swift +++ b/SourceryRuntime/Sources/macOS/AST/Variable.swift @@ -4,7 +4,6 @@ // #if canImport(ObjectiveC) import Foundation -import Stencil /// :nodoc: public typealias SourceryVariable = Variable @@ -131,28 +130,29 @@ public final class Variable: NSObject, SourceryModel, Typed, Annotated, Document } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "name = \(String(describing: self.name)), " - string += "typeName = \(String(describing: self.typeName)), " - string += "isComputed = \(String(describing: self.isComputed)), " - string += "isAsync = \(String(describing: self.isAsync)), " - string += "`throws` = \(String(describing: self.`throws`)), " - string += "isStatic = \(String(describing: self.isStatic)), " - string += "readAccess = \(String(describing: self.readAccess)), " - string += "writeAccess = \(String(describing: self.writeAccess)), " - string += "accessLevel = \(String(describing: self.accessLevel)), " - string += "isMutable = \(String(describing: self.isMutable)), " - string += "defaultValue = \(String(describing: self.defaultValue)), " - string += "annotations = \(String(describing: self.annotations)), " - string += "documentation = \(String(describing: self.documentation)), " - string += "attributes = \(String(describing: self.attributes)), " - string += "modifiers = \(String(describing: self.modifiers)), " - string += "isFinal = \(String(describing: self.isFinal)), " - string += "isLazy = \(String(describing: self.isLazy)), " - string += "isDynamic = \(String(describing: self.isDynamic)), " - string += "definedInTypeName = \(String(describing: self.definedInTypeName)), " - string += "actualDefinedInTypeName = \(String(describing: self.actualDefinedInTypeName))" + string.append("name = \(String(describing: self.name)), ") + string.append("typeName = \(String(describing: self.typeName)), ") + string.append("isComputed = \(String(describing: self.isComputed)), ") + string.append("isAsync = \(String(describing: self.isAsync)), ") + string.append("`throws` = \(String(describing: self.`throws`)), ") + string.append("isStatic = \(String(describing: self.isStatic)), ") + string.append("readAccess = \(String(describing: self.readAccess)), ") + string.append("writeAccess = \(String(describing: self.writeAccess)), ") + string.append("accessLevel = \(String(describing: self.accessLevel)), ") + string.append("isMutable = \(String(describing: self.isMutable)), ") + string.append("defaultValue = \(String(describing: self.defaultValue)), ") + string.append("annotations = \(String(describing: self.annotations)), ") + string.append("documentation = \(String(describing: self.documentation)), ") + string.append("attributes = \(String(describing: self.attributes)), ") + string.append("modifiers = \(String(describing: self.modifiers)), ") + string.append("isFinal = \(String(describing: self.isFinal)), ") + string.append("isLazy = \(String(describing: self.isLazy)), ") + string.append("isDynamic = \(String(describing: self.isDynamic)), ") + string.append("definedInTypeName = \(String(describing: self.definedInTypeName)), ") + string.append("actualDefinedInTypeName = \(String(describing: self.actualDefinedInTypeName))") return string } @@ -180,6 +180,8 @@ public final class Variable: NSObject, SourceryModel, Typed, Annotated, Document return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) diff --git a/SourceryRuntime/Sources/Types.swift b/SourceryRuntime/Sources/macOS/Types.swift similarity index 96% rename from SourceryRuntime/Sources/Types.swift rename to SourceryRuntime/Sources/macOS/Types.swift index 32bced8cd..e10ccb7bb 100644 --- a/SourceryRuntime/Sources/Types.swift +++ b/SourceryRuntime/Sources/macOS/Types.swift @@ -24,10 +24,11 @@ public final class Types: NSObject, SourceryModel, Diffable { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " - string += "types = \(String(describing: self.types)), " - string += "typealiases = \(String(describing: self.typealiases))" + string.append("types = \(String(describing: self.types)), ") + string.append("typealiases = \(String(describing: self.typealiases))") return string } @@ -42,6 +43,8 @@ public final class Types: NSObject, SourceryModel, Diffable { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.types) diff --git a/SourceryRuntime/Sources/TypesCollection.swift b/SourceryRuntime/Sources/macOS/TypesCollection.swift similarity index 100% rename from SourceryRuntime/Sources/TypesCollection.swift rename to SourceryRuntime/Sources/macOS/TypesCollection.swift diff --git a/SourcerySwift/Sources/SourceryRuntime.content.generated.swift b/SourcerySwift/Sources/SourceryRuntime.content.generated.swift index 6bb49314b..9a250ba83 100644 --- a/SourcerySwift/Sources/SourceryRuntime.content.generated.swift +++ b/SourcerySwift/Sources/SourceryRuntime.content.generated.swift @@ -11,6 +11,7 @@ import Foundation /// :nodoc: public enum AccessLevel: String { + case `package` = "package" case `internal` = "internal" case `private` = "private" case `fileprivate` = "fileprivate" @@ -19,82 +20,6 @@ public enum AccessLevel: String { case none = "" } -"""), - .init(name: "GenericParameter.swift", content: -""" -import Foundation - -/// Descibes Swift generic parameter -@objcMembers -public final class GenericParameter: NSObject, SourceryModel, Diffable { - - /// Generic parameter name - public var name: String - - /// Generic parameter inherited type - public var inheritedTypeName: TypeName? - - /// :nodoc: - public init(name: String, inheritedTypeName: TypeName? = nil) { - self.name = name - self.inheritedTypeName = inheritedTypeName - } - - /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "name = \\(String(describing: self.name)), " - string += "inheritedTypeName = \\(String(describing: self.inheritedTypeName))" - return string - } - - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? GenericParameter else { - results.append("Incorrect type ") - return results - } - results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "inheritedTypeName").trackDifference(actual: self.inheritedTypeName, expected: castObject.inheritedTypeName)) - return results - } - - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.name) - hasher.combine(self.inheritedTypeName) - return hasher.finalize() - } - - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? GenericParameter else { return false } - if self.name != rhs.name { return false } - if self.inheritedTypeName != rhs.inheritedTypeName { return false } - return true - } - -// sourcery:inline:GenericParameter.AutoCoding - - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { - withVaList(["name"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.name = name - self.inheritedTypeName = aDecoder.decode(forKey: "inheritedTypeName") - } - - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.inheritedTypeName, forKey: "inheritedTypeName") - } - -// sourcery:end -} """), .init(name: "Actor.swift", content: """ @@ -102,14 +27,16 @@ import Foundation // sourcery: skipDescription /// Descibes Swift actor +#if canImport(ObjectiveC) @objc(SwiftActor) @objcMembers +#endif public final class Actor: Type { /// Returns "actor" public override var kind: String { return "actor" } /// Whether type is final public var isFinal: Bool { - return modifiers.contains { $0.name == "final" } + modifiers.contains { $0.name == "final" } } /// :nodoc: @@ -152,11 +79,12 @@ public final class Actor: Type { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = super.description - string += ", " - string += "kind = \\(String(describing: self.kind)), " - string += "isFinal = \\(String(describing: self.isFinal))" + string.append(", ") + string.append("kind = \\(String(describing: self.kind)), ") + string.append("isFinal = \\(String(describing: self.isFinal))") return string } @@ -170,6 +98,8 @@ public final class Actor: Type { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(super.hash) @@ -194,7 +124,7 @@ public final class Actor: Type { super.encode(with: aCoder) } // sourcery:end - + } """), @@ -263,112 +193,15 @@ public extension Array { } } -"""), - .init(name: "Set.swift", content: -""" -import Foundation - -/// Describes set type -public final class SetType: NSObject, SourceryModel, Diffable { - /// Type name used in declaration - public var name: String - - /// Array element type name - public var elementTypeName: TypeName - - // sourcery: skipEquality, skipDescription - /// Array element type, if known - public var elementType: Type? - - /// :nodoc: - public init(name: String, elementTypeName: TypeName, elementType: Type? = nil) { - self.name = name - self.elementTypeName = elementTypeName - self.elementType = elementType - } - - /// Returns array as generic type - public var asGeneric: GenericType { - GenericType(name: "Set", typeParameters: [ - .init(typeName: elementTypeName) - ]) - } - - public var asSource: String { - "[\\(elementTypeName.asSource)]" - } - - /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "name = \\(String(describing: self.name)), " - string += "elementTypeName = \\(String(describing: self.elementTypeName)), " - string += "asGeneric = \\(String(describing: self.asGeneric)), " - string += "asSource = \\(String(describing: self.asSource))" - return string - } - - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? SetType else { - results.append("Incorrect type ") - return results - } - results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "elementTypeName").trackDifference(actual: self.elementTypeName, expected: castObject.elementTypeName)) - return results - } - - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.name) - hasher.combine(self.elementTypeName) - return hasher.finalize() - } - - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? SetType else { return false } - if self.name != rhs.name { return false } - if self.elementTypeName != rhs.elementTypeName { return false } - return true - } - -// sourcery:inline:SetType.AutoCoding - - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { - withVaList(["name"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.name = name - guard let elementTypeName: TypeName = aDecoder.decode(forKey: "elementTypeName") else { - withVaList(["elementTypeName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.elementTypeName = elementTypeName - self.elementType = aDecoder.decode(forKey: "elementType") - } - - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.elementTypeName, forKey: "elementTypeName") - aCoder.encode(self.elementType, forKey: "elementType") - } -// sourcery:end -} - """), .init(name: "Array.swift", content: """ import Foundation /// Describes array type -@objcMembers +#if canImport(ObjectiveC) +@objcMembers +#endif public final class ArrayType: NSObject, SourceryModel, Diffable { /// Type name used in declaration public var name: String @@ -399,12 +232,13 @@ public final class ArrayType: NSObject, SourceryModel, Diffable { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " - string += "name = \\(String(describing: self.name)), " - string += "elementTypeName = \\(String(describing: self.elementTypeName)), " - string += "asGeneric = \\(String(describing: self.asGeneric)), " - string += "asSource = \\(String(describing: self.asSource))" + string.append("name = \\(String(describing: self.name)), ") + string.append("elementTypeName = \\(String(describing: self.elementTypeName)), ") + string.append("asGeneric = \\(String(describing: self.asGeneric)), ") + string.append("asSource = \\(String(describing: self.asSource))") return string } @@ -419,6 +253,8 @@ public final class ArrayType: NSObject, SourceryModel, Diffable { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) @@ -438,13 +274,13 @@ public final class ArrayType: NSObject, SourceryModel, Diffable { /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { + guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name - guard let elementTypeName: TypeName = aDecoder.decode(forKey: "elementTypeName") else { + guard let elementTypeName: TypeName = aDecoder.decode(forKey: "elementTypeName") else { withVaList(["elementTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } @@ -463,124 +299,44 @@ public final class ArrayType: NSObject, SourceryModel, Diffable { } """), - .init(name: "AssociatedType.swift", content: + .init(name: "Attribute.swift", content: """ import Foundation -/// Describes Swift AssociatedType +/// Describes Swift attribute +#if canImport(ObjectiveC) @objcMembers -public final class AssociatedType: NSObject, SourceryModel { - /// Associated type name +#endif +public class Attribute: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJSExport, Diffable { + + /// Attribute name public let name: String - /// Associated type type constraint name, if specified - public let typeName: TypeName? + /// Attribute arguments + public let arguments: [String: NSObject] - // sourcery: skipEquality, skipDescription - /// Associated type constrained type, if known, i.e. if the type is declared in the scanned sources. - public var type: Type? + // sourcery: skipJSExport + let _description: String + // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: - public init(name: String, typeName: TypeName? = nil, type: Type? = nil) { - self.name = name - self.typeName = typeName - self.type = type - } + public var __parserData: Any? /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "name = \\(String(describing: self.name)), " - string += "typeName = \\(String(describing: self.typeName))" - return string + public init(name: String, arguments: [String: NSObject] = [:], description: String? = nil) { + self.name = name + self.arguments = arguments + self._description = description ?? "@\\(name)" } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? AssociatedType else { - results.append("Incorrect type ") - return results - } - results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) - return results + /// TODO: unify `asSource` / `description`? + public var asSource: String { + description } - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.name) - hasher.combine(self.typeName) - return hasher.finalize() - } - - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? AssociatedType else { return false } - if self.name != rhs.name { return false } - if self.typeName != rhs.typeName { return false } - return true - } - -// sourcery:inline:AssociatedType.AutoCoding - - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { - withVaList(["name"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.name = name - self.typeName = aDecoder.decode(forKey: "typeName") - self.type = aDecoder.decode(forKey: "type") - } - - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.typeName, forKey: "typeName") - aCoder.encode(self.type, forKey: "type") - } -// sourcery:end -} - -"""), - .init(name: "Attribute.swift", content: -""" -import Foundation - -/// Describes Swift attribute -@objcMembers -public class Attribute: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJSExport, Diffable { - - /// Attribute name - public let name: String - - /// Attribute arguments - public let arguments: [String: NSObject] - - // sourcery: skipJSExport - let _description: String - - // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport - /// :nodoc: - public var __parserData: Any? - - /// :nodoc: - public init(name: String, arguments: [String: NSObject] = [:], description: String? = nil) { - self.name = name - self.arguments = arguments - self._description = description ?? "@\\(name)" - } - - /// TODO: unify `asSource` / `description`? - public var asSource: String { - description - } - - /// Attribute description that can be used in a template. - public override var description: String { - return _description + /// Attribute description that can be used in a template. + public override var description: String { + return _description } /// :nodoc: @@ -609,6 +365,7 @@ public class Attribute: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJ case final case open case lazy + case `package` = "package" case `public` = "public" case `internal` = "internal" case `private` = "private" @@ -712,6 +469,8 @@ public class Attribute: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJ return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) @@ -733,19 +492,19 @@ public class Attribute: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJ /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { + guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name - guard let arguments: [String: NSObject] = aDecoder.decode(forKey: "arguments") else { + guard let arguments: [String: NSObject] = aDecoder.decode(forKey: "arguments") else { withVaList(["arguments"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.arguments = arguments - guard let _description: String = aDecoder.decode(forKey: "_description") else { + guard let _description: String = aDecoder.decode(forKey: "_description") else { withVaList(["_description"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } @@ -763,18 +522,6 @@ public class Attribute: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJ } -"""), - .init(name: "AutoHashable.generated.swift", content: -""" -// Generated using Sourcery 1.3.1 — https://github.com/krzysztofzablocki/Sourcery -// DO NOT EDIT -// swiftlint:disable all - - -// MARK: - AutoHashable for classes, protocols, structs - -// MARK: - AutoHashable for Enums - """), .init(name: "BytesRange.swift", content: """ @@ -786,7 +533,9 @@ public class Attribute: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJ import Foundation /// :nodoc: +#if canImport(ObjectiveC) @objcMembers +#endif public final class BytesRange: NSObject, SourceryModel, Diffable { public let offset: Int64 @@ -802,6 +551,7 @@ public final class BytesRange: NSObject, SourceryModel, Diffable { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string += "offset = \\(String(describing: self.offset)), " @@ -820,6 +570,8 @@ public final class BytesRange: NSObject, SourceryModel, Diffable { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.offset) @@ -857,14 +609,16 @@ public final class BytesRange: NSObject, SourceryModel, Diffable { import Foundation // sourcery: skipDescription /// Descibes Swift class +#if canImport(ObjectiveC) @objc(SwiftClass) @objcMembers +#endif public final class Class: Type { /// Returns "class" public override var kind: String { return "class" } - /// Whether type is final + /// Whether type is final public var isFinal: Bool { - return modifiers.contains { $0.name == "final" } + modifiers.contains { $0.name == "final" } } /// :nodoc: @@ -907,11 +661,12 @@ public final class Class: Type { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = super.description - string += ", " - string += "kind = \\(String(describing: self.kind)), " - string += "isFinal = \\(String(describing: self.isFinal))" + string.append(", ") + string.append("kind = \\(String(describing: self.kind)), ") + string.append("isFinal = \\(String(describing: self.isFinal))") return string } @@ -925,6 +680,8 @@ public final class Class: Type { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(super.hash) @@ -953,387 +710,117 @@ public final class Class: Type { } """), - .init(name: "Closure.swift", content: + .init(name: "Composer.swift", content: """ +// +// Created by Krzysztof Zablocki on 31/12/2016. +// Copyright (c) 2016 Pixle. All rights reserved. +// + import Foundation -/// Describes closure type -@objcMembers -public final class ClosureType: NSObject, SourceryModel, Diffable { +private func currentTimestamp() -> TimeInterval { + return Date().timeIntervalSince1970 +} - /// Type name used in declaration with stripped whitespaces and new lines - public let name: String +/// Responsible for composing results of `FileParser`. +public enum Composer { - /// List of closure parameters - public let parameters: [ClosureParameter] + /// Performs final processing of discovered types: + /// - extends types with their corresponding extensions; + /// - replaces typealiases with actual types + /// - finds actual types for variables and enums raw values + /// - filters out any private types and extensions + /// + /// - Parameter parserResult: Result of parsing source code. + /// - Returns: Final types and extensions of unknown types. + public static func uniqueTypesAndFunctions(_ parserResult: FileParserResult) -> (types: [Type], functions: [SourceryMethod], typealiases: [Typealias]) { + let composed = ParserResultsComposed(parserResult: parserResult) - /// Return value type name - public let returnTypeName: TypeName + let resolveType = { (typeName: TypeName, containingType: Type?) -> Type? in + return composed.resolveType(typeName: typeName, containingType: containingType) + } - /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` - public var actualReturnTypeName: TypeName { - return returnTypeName.actualTypeName ?? returnTypeName - } + let methodResolveType = { (typeName: TypeName, containingType: Type?, method: Method) -> Type? in + return composed.resolveType(typeName: typeName, containingType: containingType, method: method) + } - // sourcery: skipEquality, skipDescription - /// Actual return value type, if known - public var returnType: Type? + composed.types.parallelPerform { type in + type.variables.forEach { + resolveVariableTypes($0, of: type, resolve: resolveType) + } + type.methods.forEach { + resolveMethodTypes($0, of: type, resolve: methodResolveType) + } + type.subscripts.forEach { + resolveSubscriptTypes($0, of: type, resolve: resolveType) + } - // sourcery: skipEquality, skipDescription - /// Whether return value type is optional - public var isOptionalReturnType: Bool { - return returnTypeName.isOptional - } + if let enumeration = type as? Enum { + resolveEnumTypes(enumeration, types: composed.typeMap, resolve: resolveType) + } - // sourcery: skipEquality, skipDescription - /// Whether return value type is implicitly unwrapped optional - public var isImplicitlyUnwrappedOptionalReturnType: Bool { - return returnTypeName.isImplicitlyUnwrappedOptional - } + if let composition = type as? ProtocolComposition { + resolveProtocolCompositionTypes(composition, resolve: resolveType) + } - // sourcery: skipEquality, skipDescription - /// Return value type name without attributes and optional type information - public var unwrappedReturnTypeName: String { - return returnTypeName.unwrappedTypeName - } + if let sourceryProtocol = type as? SourceryProtocol { + resolveProtocolTypes(sourceryProtocol, resolve: resolveType) + } + } - /// Whether method is async method - public let isAsync: Bool + composed.functions.parallelPerform { function in + resolveMethodTypes(function, of: nil, resolve: methodResolveType) + } - /// async keyword - public let asyncKeyword: String? + updateTypeRelationships(types: composed.types) - /// Whether closure throws - public let `throws`: Bool + return ( + types: composed.types.sorted { $0.globalName < $1.globalName }, + functions: composed.functions.sorted { $0.name < $1.name }, + typealiases: composed.unresolvedTypealiases.values.sorted(by: { $0.name < $1.name }) + ) + } - /// throws or rethrows keyword - public let throwsOrRethrowsKeyword: String? + typealias TypeResolver = (TypeName, Type?) -> Type? + typealias MethodArgumentTypeResolver = (TypeName, Type?, Method) -> Type? - /// :nodoc: - public init(name: String, parameters: [ClosureParameter], returnTypeName: TypeName, returnType: Type? = nil, asyncKeyword: String? = nil, throwsOrRethrowsKeyword: String? = nil) { - self.name = name - self.parameters = parameters - self.returnTypeName = returnTypeName - self.returnType = returnType - self.asyncKeyword = asyncKeyword - self.isAsync = asyncKeyword != nil - self.throwsOrRethrowsKeyword = throwsOrRethrowsKeyword - self.`throws` = throwsOrRethrowsKeyword != nil - } + private static func resolveVariableTypes(_ variable: Variable, of type: Type, resolve: TypeResolver) { + variable.type = resolve(variable.typeName, type) - public var asSource: String { - "\\(parameters.asSource)\\(asyncKeyword != nil ? " \\(asyncKeyword!)" : "")\\(throwsOrRethrowsKeyword != nil ? " \\(throwsOrRethrowsKeyword!)" : "") -> \\(returnTypeName.asSource)" + /// The actual `definedInType` is assigned in `uniqueTypes` but we still + /// need to resolve the type to correctly parse typealiases + /// @see https://github.com/krzysztofzablocki/Sourcery/pull/374 + if let definedInTypeName = variable.definedInTypeName { + _ = resolve(definedInTypeName, type) + } } - /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "name = \\(String(describing: self.name)), " - string += "parameters = \\(String(describing: self.parameters)), " - string += "returnTypeName = \\(String(describing: self.returnTypeName)), " - string += "actualReturnTypeName = \\(String(describing: self.actualReturnTypeName)), " - string += "isAsync = \\(String(describing: self.isAsync)), " - string += "asyncKeyword = \\(String(describing: self.asyncKeyword)), " - string += "`throws` = \\(String(describing: self.`throws`)), " - string += "throwsOrRethrowsKeyword = \\(String(describing: self.throwsOrRethrowsKeyword)), " - string += "asSource = \\(String(describing: self.asSource))" - return string - } + private static func resolveSubscriptTypes(_ subscript: Subscript, of type: Type, resolve: TypeResolver) { + `subscript`.parameters.forEach { (parameter) in + parameter.type = resolve(parameter.typeName, type) + } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? ClosureType else { - results.append("Incorrect type ") - return results + `subscript`.returnType = resolve(`subscript`.returnTypeName, type) + if let definedInTypeName = `subscript`.definedInTypeName { + _ = resolve(definedInTypeName, type) } - results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) - results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) - results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) - results.append(contentsOf: DiffableResult(identifier: "asyncKeyword").trackDifference(actual: self.asyncKeyword, expected: castObject.asyncKeyword)) - results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) - results.append(contentsOf: DiffableResult(identifier: "throwsOrRethrowsKeyword").trackDifference(actual: self.throwsOrRethrowsKeyword, expected: castObject.throwsOrRethrowsKeyword)) - return results } - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.name) - hasher.combine(self.parameters) - hasher.combine(self.returnTypeName) - hasher.combine(self.isAsync) - hasher.combine(self.asyncKeyword) - hasher.combine(self.`throws`) - hasher.combine(self.throwsOrRethrowsKeyword) - return hasher.finalize() - } + private static func resolveMethodTypes(_ method: SourceryMethod, of type: Type?, resolve: MethodArgumentTypeResolver) { + method.parameters.forEach { parameter in + parameter.type = resolve(parameter.typeName, type, method) + } - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? ClosureType else { return false } - if self.name != rhs.name { return false } - if self.parameters != rhs.parameters { return false } - if self.returnTypeName != rhs.returnTypeName { return false } - if self.isAsync != rhs.isAsync { return false } - if self.asyncKeyword != rhs.asyncKeyword { return false } - if self.`throws` != rhs.`throws` { return false } - if self.throwsOrRethrowsKeyword != rhs.throwsOrRethrowsKeyword { return false } - return true - } + /// The actual `definedInType` is assigned in `uniqueTypes` but we still + /// need to resolve the type to correctly parse typealiases + /// @see https://github.com/krzysztofzablocki/Sourcery/pull/374 + var definedInType: Type? + if let definedInTypeName = method.definedInTypeName { + definedInType = resolve(definedInTypeName, type, method) + } -// sourcery:inline:ClosureType.AutoCoding - - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { - withVaList(["name"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.name = name - guard let parameters: [ClosureParameter] = aDecoder.decode(forKey: "parameters") else { - withVaList(["parameters"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.parameters = parameters - guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { - withVaList(["returnTypeName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.returnTypeName = returnTypeName - self.returnType = aDecoder.decode(forKey: "returnType") - self.isAsync = aDecoder.decode(forKey: "isAsync") - self.asyncKeyword = aDecoder.decode(forKey: "asyncKeyword") - self.`throws` = aDecoder.decode(forKey: "`throws`") - self.throwsOrRethrowsKeyword = aDecoder.decode(forKey: "throwsOrRethrowsKeyword") - } - - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.parameters, forKey: "parameters") - aCoder.encode(self.returnTypeName, forKey: "returnTypeName") - aCoder.encode(self.returnType, forKey: "returnType") - aCoder.encode(self.isAsync, forKey: "isAsync") - aCoder.encode(self.asyncKeyword, forKey: "asyncKeyword") - aCoder.encode(self.`throws`, forKey: "`throws`") - aCoder.encode(self.throwsOrRethrowsKeyword, forKey: "throwsOrRethrowsKeyword") - } -// sourcery:end - -} - -"""), - .init(name: "Coding.generated.swift", content: -""" -// Generated using Sourcery 2.0.3 — https://github.com/krzysztofzablocki/Sourcery -// DO NOT EDIT -// swiftlint:disable vertical_whitespace trailing_newline - -import Foundation - - -extension NSCoder { - - @nonobjc func decode(forKey: String) -> String? { - return self.maybeDecode(forKey: forKey) as String? - } - - @nonobjc func decode(forKey: String) -> TypeName? { - return self.maybeDecode(forKey: forKey) as TypeName? - } - - @nonobjc func decode(forKey: String) -> AccessLevel? { - return self.maybeDecode(forKey: forKey) as AccessLevel? - } - - @nonobjc func decode(forKey: String) -> Bool { - return self.decodeBool(forKey: forKey) - } - - @nonobjc func decode(forKey: String) -> Int { - return self.decodeInteger(forKey: forKey) - } - - func decode(forKey: String) -> E? { - return maybeDecode(forKey: forKey) as E? - } - - fileprivate func maybeDecode(forKey: String) -> E? { - guard let object = self.decodeObject(forKey: forKey) else { - return nil - } - - return object as? E - } - -} - -extension ArrayType: NSCoding {} - -extension AssociatedType: NSCoding {} - -extension AssociatedValue: NSCoding {} - -extension Attribute: NSCoding {} - -extension BytesRange: NSCoding {} - - -extension ClosureParameter: NSCoding {} - -extension ClosureType: NSCoding {} - -extension DictionaryType: NSCoding {} - - -extension EnumCase: NSCoding {} - -extension FileParserResult: NSCoding {} - -extension GenericRequirement: NSCoding {} - -extension GenericType: NSCoding {} - -extension GenericTypeParameter: NSCoding {} - -extension Import: NSCoding {} - -extension Method: NSCoding {} - -extension MethodParameter: NSCoding {} - -extension Modifier: NSCoding {} - - - - -extension Subscript: NSCoding {} - -extension TupleElement: NSCoding {} - -extension TupleType: NSCoding {} - -extension Type: NSCoding {} - -extension TypeName: NSCoding {} - -extension Typealias: NSCoding {} - -extension Types: NSCoding {} - -extension Variable: NSCoding {} - - -"""), - .init(name: "Composer.swift", content: -""" -// -// Created by Krzysztof Zablocki on 31/12/2016. -// Copyright (c) 2016 Pixle. All rights reserved. -// - -import Foundation - -private func currentTimestamp() -> TimeInterval { - return Date().timeIntervalSince1970 -} - -/// Responsible for composing results of `FileParser`. -public enum Composer { - - /// Performs final processing of discovered types: - /// - extends types with their corresponding extensions; - /// - replaces typealiases with actual types - /// - finds actual types for variables and enums raw values - /// - filters out any private types and extensions - /// - /// - Parameter parserResult: Result of parsing source code. - /// - Returns: Final types and extensions of unknown types. - public static func uniqueTypesAndFunctions(_ parserResult: FileParserResult) -> (types: [Type], functions: [SourceryMethod], typealiases: [Typealias]) { - let composed = ParserResultsComposed(parserResult: parserResult) - - let resolveType = { (typeName: TypeName, containingType: Type?) -> Type? in - return composed.resolveType(typeName: typeName, containingType: containingType) - } - - composed.types.parallelPerform { type in - type.variables.forEach { - resolveVariableTypes($0, of: type, resolve: resolveType) - } - type.methods.forEach { - resolveMethodTypes($0, of: type, resolve: resolveType) - } - type.subscripts.forEach { - resolveSubscriptTypes($0, of: type, resolve: resolveType) - } - - if let enumeration = type as? Enum { - resolveEnumTypes(enumeration, types: composed.typeMap, resolve: resolveType) - } - - if let composition = type as? ProtocolComposition { - resolveProtocolCompositionTypes(composition, resolve: resolveType) - } - - if let sourceryProtocol = type as? SourceryProtocol { - resolveProtocolTypes(sourceryProtocol, resolve: resolveType) - } - } - - composed.functions.parallelPerform { function in - resolveMethodTypes(function, of: nil, resolve: resolveType) - } - - updateTypeRelationships(types: composed.types) - - return ( - types: composed.types.sorted { $0.globalName < $1.globalName }, - functions: composed.functions.sorted { $0.name < $1.name }, - typealiases: composed.unresolvedTypealiases.values.sorted(by: { $0.name < $1.name }) - ) - } - - typealias TypeResolver = (TypeName, Type?) -> Type? - - private static func resolveVariableTypes(_ variable: Variable, of type: Type, resolve: TypeResolver) { - variable.type = resolve(variable.typeName, type) - - /// The actual `definedInType` is assigned in `uniqueTypes` but we still - /// need to resolve the type to correctly parse typealiases - /// @see https://github.com/krzysztofzablocki/Sourcery/pull/374 - if let definedInTypeName = variable.definedInTypeName { - _ = resolve(definedInTypeName, type) - } - } - - private static func resolveSubscriptTypes(_ subscript: Subscript, of type: Type, resolve: TypeResolver) { - `subscript`.parameters.forEach { (parameter) in - parameter.type = resolve(parameter.typeName, type) - } - - `subscript`.returnType = resolve(`subscript`.returnTypeName, type) - if let definedInTypeName = `subscript`.definedInTypeName { - _ = resolve(definedInTypeName, type) - } - } - - private static func resolveMethodTypes(_ method: SourceryMethod, of type: Type?, resolve: TypeResolver) { - method.parameters.forEach { parameter in - parameter.type = resolve(parameter.typeName, type) - } - - /// The actual `definedInType` is assigned in `uniqueTypes` but we still - /// need to resolve the type to correctly parse typealiases - /// @see https://github.com/krzysztofzablocki/Sourcery/pull/374 - var definedInType: Type? - if let definedInTypeName = method.definedInTypeName { - definedInType = resolve(definedInTypeName, type) - } - - guard !method.returnTypeName.isVoid else { return } + guard !method.returnTypeName.isVoid else { return } if method.isInitializer || method.isFailableInitializer { method.returnType = definedInType @@ -1356,7 +843,7 @@ public enum Composer { } } } else { - method.returnType = resolve(method.returnTypeName, type) + method.returnType = resolve(method.returnTypeName, type, method) } } @@ -1429,6 +916,13 @@ public enum Composer { } private static func findBaseType(for type: Type, name: String, typesByName: [String: Type]) -> Type? { + // special case to check if the type is based on one of the recognized types + // and the superclass has a generic constraint in `name` part of the `TypeName` + var name = name + if name.contains("<") && name.contains(">") { + let parts = name.split(separator: "<") + name = String(parts.first!) + } if let baseType = typesByName[name] { return baseType } @@ -1504,7 +998,9 @@ public protocol Definition: AnyObject { import Foundation /// Describes dictionary type +#if canImport(ObjectiveC) @objcMembers +#endif public final class DictionaryType: NSObject, SourceryModel, Diffable { /// Type name used in declaration public var name: String @@ -1545,13 +1041,14 @@ public final class DictionaryType: NSObject, SourceryModel, Diffable { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " - string += "name = \\(String(describing: self.name)), " - string += "valueTypeName = \\(String(describing: self.valueTypeName)), " - string += "keyTypeName = \\(String(describing: self.keyTypeName)), " - string += "asGeneric = \\(String(describing: self.asGeneric)), " - string += "asSource = \\(String(describing: self.asSource))" + string.append("name = \\(String(describing: self.name)), ") + string.append("valueTypeName = \\(String(describing: self.valueTypeName)), ") + string.append("keyTypeName = \\(String(describing: self.keyTypeName)), ") + string.append("asGeneric = \\(String(describing: self.asGeneric)), ") + string.append("asSource = \\(String(describing: self.asSource))") return string } @@ -1567,6 +1064,8 @@ public final class DictionaryType: NSObject, SourceryModel, Diffable { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) @@ -1588,20 +1087,20 @@ public final class DictionaryType: NSObject, SourceryModel, Diffable { /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { + guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name - guard let valueTypeName: TypeName = aDecoder.decode(forKey: "valueTypeName") else { + guard let valueTypeName: TypeName = aDecoder.decode(forKey: "valueTypeName") else { withVaList(["valueTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.valueTypeName = valueTypeName self.valueType = aDecoder.decode(forKey: "valueType") - guard let keyTypeName: TypeName = aDecoder.decode(forKey: "keyTypeName") else { + guard let keyTypeName: TypeName = aDecoder.decode(forKey: "keyTypeName") else { withVaList(["keyTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } @@ -1662,7 +1161,9 @@ extension NSRange: Diffable { } } +#if canImport(ObjectiveC) @objcMembers +#endif public class DiffableResult: NSObject, AutoEquatable { // sourcery: skipEquality private var results: [String] @@ -1685,13 +1186,30 @@ public class DiffableResult: NSObject, AutoEquatable { var isEmpty: Bool { return results.isEmpty } - public override var description: String { - guard !results.isEmpty else { return "" } - return "\\(identifier.flatMap { "\\($0) " } ?? "")" + results.joined(separator: "\\n") + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.identifier) + return hasher.finalize() } -} - -public extension DiffableResult { + + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? DiffableResult else { return false } + if self.identifier != rhs.identifier { return false } + return true + } + + public override var description: String { + guard !results.isEmpty else { return "" } + var description = "\\(identifier.flatMap { "\\($0) " } ?? "")" + description.append(results.joined(separator: "\\n")) + return description + } +} + +public extension DiffableResult { #if swift(>=4.1) #else @@ -1708,7 +1226,9 @@ public extension DiffableResult { /// :nodoc: @discardableResult func trackDifference(actual: T?, expected: T?) -> DiffableResult { if actual != expected { - let result = DiffableResult(results: [""]) + let expected = expected.map({ "\\($0)" }) ?? "nil" + let actual = actual.map({ "\\($0)" }) ?? "nil" + let result = DiffableResult(results: [""]) append(contentsOf: result) } return self @@ -1846,3372 +1366,2836 @@ public protocol Documented { } """), - .init(name: "AssociatedValue.swift", content: + .init(name: "Extensions.swift", content: """ import Foundation -/// Defines enum case associated value -@objcMembers -public final class AssociatedValue: NSObject, SourceryModel, AutoDescription, Typed, Annotated, Diffable { +public extension StringProtocol { + /// Trimms leading and trailing whitespaces and newlines + var trimmed: String { + self.trimmingCharacters(in: .whitespacesAndNewlines) + } +} - /// Associated value local name. - /// This is a name to be used to construct enum case value - public let localName: String? +public extension String { - /// Associated value external name. - /// This is a name to be used to access value in value-bindig - public let externalName: String? + /// Returns nil if string is empty + var nilIfEmpty: String? { + if isEmpty { + return nil + } - /// Associated value type name - public let typeName: TypeName + return self + } - // sourcery: skipEquality, skipDescription - /// Associated value type, if known - public var type: Type? + /// Returns nil if string is empty or contains `_` character + var nilIfNotValidParameterName: String? { + if isEmpty { + return nil + } - /// Associated value default value - public let defaultValue: String? + if self == "_" { + return nil + } - /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 - public var annotations: Annotations = [:] + return self + } /// :nodoc: - public init(localName: String?, externalName: String?, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:]) { - self.localName = localName - self.externalName = externalName - self.typeName = typeName - self.type = type - self.defaultValue = defaultValue - self.annotations = annotations + /// - Parameter substring: Instance of a substring + /// - Returns: Returns number of times a substring appears in self + func countInstances(of substring: String) -> Int { + guard !substring.isEmpty else { return 0 } + var count = 0 + var searchRange: Range? + while let foundRange = range(of: substring, options: [], range: searchRange) { + count += 1 + searchRange = Range(uncheckedBounds: (lower: foundRange.upperBound, upper: endIndex)) + } + return count } - convenience init(name: String? = nil, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:]) { - self.init(localName: name, externalName: name, typeName: typeName, type: type, defaultValue: defaultValue, annotations: annotations) + /// :nodoc: + /// Removes leading and trailing whitespace from str. Returns false if str was not altered. + @discardableResult + mutating func strip() -> Bool { + let strippedString = stripped() + guard strippedString != self else { return false } + self = strippedString + return true } /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "localName = \\(String(describing: self.localName)), " - string += "externalName = \\(String(describing: self.externalName)), " - string += "typeName = \\(String(describing: self.typeName)), " - string += "defaultValue = \\(String(describing: self.defaultValue)), " - string += "annotations = \\(String(describing: self.annotations))" - return string + /// Returns a copy of str with leading and trailing whitespace removed. + func stripped() -> String { + return String(self.trimmingCharacters(in: .whitespaces)) } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? AssociatedValue else { - results.append("Incorrect type ") - return results - } - results.append(contentsOf: DiffableResult(identifier: "localName").trackDifference(actual: self.localName, expected: castObject.localName)) - results.append(contentsOf: DiffableResult(identifier: "externalName").trackDifference(actual: self.externalName, expected: castObject.externalName)) - results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) - results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) - results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) - return results + /// :nodoc: + @discardableResult + mutating func trimPrefix(_ prefix: String) -> Bool { + guard hasPrefix(prefix) else { return false } + self = String(self.suffix(self.count - prefix.count)) + return true } - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.localName) - hasher.combine(self.externalName) - hasher.combine(self.typeName) - hasher.combine(self.defaultValue) - hasher.combine(self.annotations) - return hasher.finalize() + /// :nodoc: + func trimmingPrefix(_ prefix: String) -> String { + guard hasPrefix(prefix) else { return self } + return String(self.suffix(self.count - prefix.count)) } /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? AssociatedValue else { return false } - if self.localName != rhs.localName { return false } - if self.externalName != rhs.externalName { return false } - if self.typeName != rhs.typeName { return false } - if self.defaultValue != rhs.defaultValue { return false } - if self.annotations != rhs.annotations { return false } + @discardableResult + mutating func trimSuffix(_ suffix: String) -> Bool { + guard hasSuffix(suffix) else { return false } + self = String(self.prefix(self.count - suffix.count)) return true } -// sourcery:inline:AssociatedValue.AutoCoding - - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - self.localName = aDecoder.decode(forKey: "localName") - self.externalName = aDecoder.decode(forKey: "externalName") - guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { - withVaList(["typeName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.typeName = typeName - self.type = aDecoder.decode(forKey: "type") - self.defaultValue = aDecoder.decode(forKey: "defaultValue") - guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { - withVaList(["annotations"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.annotations = annotations - } - - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.localName, forKey: "localName") - aCoder.encode(self.externalName, forKey: "externalName") - aCoder.encode(self.typeName, forKey: "typeName") - aCoder.encode(self.type, forKey: "type") - aCoder.encode(self.defaultValue, forKey: "defaultValue") - aCoder.encode(self.annotations, forKey: "annotations") - } -// sourcery:end - -} -"""), - .init(name: "EnumCase.swift", content: -""" -import Foundation - -/// Defines enum case -@objcMembers -public final class EnumCase: NSObject, SourceryModel, AutoDescription, Annotated, Documented, Diffable { - - /// Enum case name - public let name: String - - /// Enum case raw value, if any - public let rawValue: String? - - /// Enum case associated values - public let associatedValues: [AssociatedValue] - - /// Enum case annotations - public var annotations: Annotations = [:] - - public var documentation: Documentation = [] + /// :nodoc: + func trimmingSuffix(_ suffix: String) -> String { + guard hasSuffix(suffix) else { return self } + return String(self.prefix(self.count - suffix.count)) + } - /// Whether enum case is indirect - public let indirect: Bool + /// :nodoc: + func dropFirstAndLast(_ n: Int = 1) -> String { + return drop(first: n, last: n) + } - /// Whether enum case has associated value - public var hasAssociatedValue: Bool { - return !associatedValues.isEmpty + /// :nodoc: + func drop(first: Int, last: Int) -> String { + return String(self.dropFirst(first).dropLast(last)) } - // Underlying parser data, never to be used by anything else - // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: - public var __parserData: Any? + /// Wraps brackets if needed to make a valid type name + func bracketsBalancing() -> String { + if hasPrefix("(") && hasSuffix(")") { + let unwrapped = dropFirstAndLast() + return unwrapped.commaSeparated().count == 1 ? unwrapped.bracketsBalancing() : self + } else { + let wrapped = "(\\(self))" + return wrapped.isValidTupleName() || !isBracketsBalanced() ? wrapped : self + } + } /// :nodoc: - public init(name: String, rawValue: String? = nil, associatedValues: [AssociatedValue] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], indirect: Bool = false) { - self.name = name - self.rawValue = rawValue - self.associatedValues = associatedValues - self.annotations = annotations - self.documentation = documentation - self.indirect = indirect + /// Returns true if given string can represent a valid tuple type name + func isValidTupleName() -> Bool { + guard hasPrefix("(") && hasSuffix(")") else { return false } + let trimmedBracketsName = dropFirstAndLast() + return trimmedBracketsName.isBracketsBalanced() && trimmedBracketsName.commaSeparated().count > 1 } /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "name = \\(String(describing: self.name)), " - string += "rawValue = \\(String(describing: self.rawValue)), " - string += "associatedValues = \\(String(describing: self.associatedValues)), " - string += "annotations = \\(String(describing: self.annotations)), " - string += "documentation = \\(String(describing: self.documentation)), " - string += "indirect = \\(String(describing: self.indirect)), " - string += "hasAssociatedValue = \\(String(describing: self.hasAssociatedValue))" - return string + func isValidArrayName() -> Bool { + if hasPrefix("Array<") { return true } + if hasPrefix("[") && hasSuffix("]") { + return dropFirstAndLast().colonSeparated().count == 1 + } + return false } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? EnumCase else { - results.append("Incorrect type ") - return results + /// :nodoc: + func isValidDictionaryName() -> Bool { + if hasPrefix("Dictionary<") { return true } + if hasPrefix("[") && contains(":") && hasSuffix("]") { + return dropFirstAndLast().colonSeparated().count == 2 } - results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "rawValue").trackDifference(actual: self.rawValue, expected: castObject.rawValue)) - results.append(contentsOf: DiffableResult(identifier: "associatedValues").trackDifference(actual: self.associatedValues, expected: castObject.associatedValues)) - results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) - results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) - results.append(contentsOf: DiffableResult(identifier: "indirect").trackDifference(actual: self.indirect, expected: castObject.indirect)) - return results - } - - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.name) - hasher.combine(self.rawValue) - hasher.combine(self.associatedValues) - hasher.combine(self.annotations) - hasher.combine(self.documentation) - hasher.combine(self.indirect) - return hasher.finalize() + return false } /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? EnumCase else { return false } - if self.name != rhs.name { return false } - if self.rawValue != rhs.rawValue { return false } - if self.associatedValues != rhs.associatedValues { return false } - if self.annotations != rhs.annotations { return false } - if self.documentation != rhs.documentation { return false } - if self.indirect != rhs.indirect { return false } - return true + func isValidClosureName() -> Bool { + return components(separatedBy: "->", excludingDelimiterBetween: (["(", "<"], [")", ">"])).count > 1 } -// sourcery:inline:EnumCase.AutoCoding - - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { - withVaList(["name"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.name = name - self.rawValue = aDecoder.decode(forKey: "rawValue") - guard let associatedValues: [AssociatedValue] = aDecoder.decode(forKey: "associatedValues") else { - withVaList(["associatedValues"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.associatedValues = associatedValues - guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { - withVaList(["annotations"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.annotations = annotations - guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { - withVaList(["documentation"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.documentation = documentation - self.indirect = aDecoder.decode(forKey: "indirect") + /// :nodoc: + /// Returns true if all opening brackets are balanced with closed brackets. + func isBracketsBalanced() -> Bool { + var bracketsCount: Int = 0 + for char in self { + if char == "(" { bracketsCount += 1 } else if char == ")" { bracketsCount -= 1 } + if bracketsCount < 0 { return false } } + return bracketsCount == 0 + } - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.rawValue, forKey: "rawValue") - aCoder.encode(self.associatedValues, forKey: "associatedValues") - aCoder.encode(self.annotations, forKey: "annotations") - aCoder.encode(self.documentation, forKey: "documentation") - aCoder.encode(self.indirect, forKey: "indirect") - } -// sourcery:end -} -"""), - .init(name: "Enum.swift", content: -""" -// -// Created by Krzysztof Zablocki on 13/09/2016. -// Copyright (c) 2016 Pixle. All rights reserved. -// + /// :nodoc: + /// Returns components separated with a comma respecting nested types + func commaSeparated() -> [String] { + return components(separatedBy: ",", excludingDelimiterBetween: ("<[({", "})]>")) + } -import Foundation + /// :nodoc: + /// Returns components separated with colon respecting nested types + func colonSeparated() -> [String] { + return components(separatedBy: ":", excludingDelimiterBetween: ("<[({", "})]>")) + } -/// Defines Swift enum -@objcMembers -public final class Enum: Type { - // sourcery: skipDescription - /// Returns "enum" - public override var kind: String { return "enum" } + /// :nodoc: + /// Returns components separated with semicolon respecting nested contexts + func semicolonSeparated() -> [String] { + return components(separatedBy: ";", excludingDelimiterBetween: ("{", "}")) + } - /// Enum cases - public var cases: [EnumCase] + /// :nodoc: + func components(separatedBy delimiter: String, excludingDelimiterBetween between: (open: String, close: String)) -> [String] { + return self.components(separatedBy: delimiter, excludingDelimiterBetween: (between.open.map { String($0) }, between.close.map { String($0) })) + } - /** - Enum raw value type name, if any. This type is removed from enum's `based` and `inherited` types collections. + /// :nodoc: + func components(separatedBy delimiter: String, excludingDelimiterBetween between: (open: [String], close: [String])) -> [String] { + var boundingCharactersCount: Int = 0 + var quotesCount: Int = 0 + var item = "" + var items = [String]() - - important: Unless raw type is specified explicitly via type alias RawValue it will be set to the first type in the inheritance chain. - So if your enum does not have raw value but implements protocols you'll have to specify conformance to these protocols via extension to get enum with nil raw value type and all based and inherited types. - */ - public var rawTypeName: TypeName? { - didSet { - if let rawTypeName = rawTypeName { - hasRawType = true - if let index = inheritedTypes.firstIndex(of: rawTypeName.name) { - inheritedTypes.remove(at: index) + var i = self.startIndex + while i < self.endIndex { + var offset = 1 + defer { + i = self.index(i, offsetBy: offset) + } + var currentlyScannedEnd: Index = self.endIndex + if let endIndex = self.index(i, offsetBy: delimiter.count, limitedBy: self.endIndex) { + currentlyScannedEnd = endIndex + } + let currentlyScanned: String = String(self[i..` + if !((self[i] == ">") as Bool && (item.last == "-") as Bool) { + boundingCharactersCount = max(0, boundingCharactersCount - 1) } + offset = closeString.count + } + if (self[i] == "\\"") as Bool { + quotesCount += 1 + } + + let currentIsDelimiter = (currentlyScanned == delimiter) as Bool + let boundingCountIsZero = (boundingCharactersCount == 0) as Bool + let hasEvenQuotes = (quotesCount % 2 == 0) as Bool + if currentIsDelimiter && boundingCountIsZero && hasEvenQuotes { + items.append(item) + item = "" + i = self.index(i, offsetBy: delimiter.count - 1) } else { - hasRawType = false + let endIndex: Index = self.index(i, offsetBy: offset) + item += self[i.. DiffableResult { + public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() - guard let castObject = object as? Enum else { - results.append("Incorrect type ") + guard let castObject = object as? FileParserResult else { + results.append("Incorrect type ") return results } - results.append(contentsOf: DiffableResult(identifier: "cases").trackDifference(actual: self.cases, expected: castObject.cases)) - results.append(contentsOf: DiffableResult(identifier: "rawTypeName").trackDifference(actual: self.rawTypeName, expected: castObject.rawTypeName)) - results.append(contentsOf: super.diffAgainst(castObject)) + results.append(contentsOf: DiffableResult(identifier: "path").trackDifference(actual: self.path, expected: castObject.path)) + results.append(contentsOf: DiffableResult(identifier: "module").trackDifference(actual: self.module, expected: castObject.module)) + results.append(contentsOf: DiffableResult(identifier: "types").trackDifference(actual: self.types, expected: castObject.types)) + results.append(contentsOf: DiffableResult(identifier: "functions").trackDifference(actual: self.functions, expected: castObject.functions)) + results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) + results.append(contentsOf: DiffableResult(identifier: "inlineRanges").trackDifference(actual: self.inlineRanges, expected: castObject.inlineRanges)) + results.append(contentsOf: DiffableResult(identifier: "inlineIndentations").trackDifference(actual: self.inlineIndentations, expected: castObject.inlineIndentations)) + results.append(contentsOf: DiffableResult(identifier: "modifiedDate").trackDifference(actual: self.modifiedDate, expected: castObject.modifiedDate)) + results.append(contentsOf: DiffableResult(identifier: "sourceryVersion").trackDifference(actual: self.sourceryVersion, expected: castObject.sourceryVersion)) return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() - hasher.combine(self.cases) - hasher.combine(self.rawTypeName) - hasher.combine(super.hash) + hasher.combine(self.path) + hasher.combine(self.module) + hasher.combine(self.types) + hasher.combine(self.functions) + hasher.combine(self.typealiases) + hasher.combine(self.inlineRanges) + hasher.combine(self.inlineIndentations) + hasher.combine(self.modifiedDate) + hasher.combine(self.sourceryVersion) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? Enum else { return false } - if self.cases != rhs.cases { return false } - if self.rawTypeName != rhs.rawTypeName { return false } - return super.isEqual(rhs) + guard let rhs = object as? FileParserResult else { return false } + if self.path != rhs.path { return false } + if self.module != rhs.module { return false } + if self.types != rhs.types { return false } + if self.functions != rhs.functions { return false } + if self.typealiases != rhs.typealiases { return false } + if self.inlineRanges != rhs.inlineRanges { return false } + if self.inlineIndentations != rhs.inlineIndentations { return false } + if self.modifiedDate != rhs.modifiedDate { return false } + if self.sourceryVersion != rhs.sourceryVersion { return false } + return true } -// sourcery:inline:Enum.AutoCoding +// sourcery:inline:FileParserResult.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let cases: [EnumCase] = aDecoder.decode(forKey: "cases") else { - withVaList(["cases"]) { arguments in + self.path = aDecoder.decode(forKey: "path") + self.module = aDecoder.decode(forKey: "module") + guard let types: [Type] = aDecoder.decode(forKey: "types") else { + withVaList(["types"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.cases = cases - self.rawTypeName = aDecoder.decode(forKey: "rawTypeName") - self.hasRawType = aDecoder.decode(forKey: "hasRawType") - self.rawType = aDecoder.decode(forKey: "rawType") - super.init(coder: aDecoder) + }; self.types = types + guard let functions: [SourceryMethod] = aDecoder.decode(forKey: "functions") else { + withVaList(["functions"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.functions = functions + guard let typealiases: [Typealias] = aDecoder.decode(forKey: "typealiases") else { + withVaList(["typealiases"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.typealiases = typealiases + guard let inlineRanges: [String: NSRange] = aDecoder.decode(forKey: "inlineRanges") else { + withVaList(["inlineRanges"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.inlineRanges = inlineRanges + guard let inlineIndentations: [String: String] = aDecoder.decode(forKey: "inlineIndentations") else { + withVaList(["inlineIndentations"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.inlineIndentations = inlineIndentations + guard let modifiedDate: Date = aDecoder.decode(forKey: "modifiedDate") else { + withVaList(["modifiedDate"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.modifiedDate = modifiedDate + guard let sourceryVersion: String = aDecoder.decode(forKey: "sourceryVersion") else { + withVaList(["sourceryVersion"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.sourceryVersion = sourceryVersion } /// :nodoc: - override public func encode(with aCoder: NSCoder) { - super.encode(with: aCoder) - aCoder.encode(self.cases, forKey: "cases") - aCoder.encode(self.rawTypeName, forKey: "rawTypeName") - aCoder.encode(self.hasRawType, forKey: "hasRawType") - aCoder.encode(self.rawType, forKey: "rawType") + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.path, forKey: "path") + aCoder.encode(self.module, forKey: "module") + aCoder.encode(self.types, forKey: "types") + aCoder.encode(self.functions, forKey: "functions") + aCoder.encode(self.typealiases, forKey: "typealiases") + aCoder.encode(self.inlineRanges, forKey: "inlineRanges") + aCoder.encode(self.inlineIndentations, forKey: "inlineIndentations") + aCoder.encode(self.modifiedDate, forKey: "modifiedDate") + aCoder.encode(self.sourceryVersion, forKey: "sourceryVersion") } // sourcery:end } """), - .init(name: "Extensions.swift", content: + .init(name: "Generic.swift", content: """ import Foundation -public extension StringProtocol { - /// Trimms leading and trailing whitespaces and newlines - var trimmed: String { - self.trimmingCharacters(in: .whitespacesAndNewlines) - } -} +/// Descibes Swift generic type +#if canImport(ObjectiveC) +@objcMembers +#endif +public final class GenericType: NSObject, SourceryModelWithoutDescription, Diffable { + /// The name of the base type, i.e. `Array` for `Array` + public var name: String -public extension String { + /// This generic type parameters + public let typeParameters: [GenericTypeParameter] - /// Returns nil if string is empty - var nilIfEmpty: String? { - if isEmpty { - return nil - } + /// :nodoc: + public init(name: String, typeParameters: [GenericTypeParameter] = []) { + self.name = name + self.typeParameters = typeParameters + } - return self + public var asSource: String { + let arguments = typeParameters + .map({ $0.typeName.asSource }) + .joined(separator: ", ") + return "\\(name)<\\(arguments)>" } - /// Returns nil if string is empty or contains `_` character - var nilIfNotValidParameterName: String? { - if isEmpty { - return nil - } + public override var description: String { + asSource + } - if self == "_" { - return nil + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? GenericType else { + results.append("Incorrect type ") + return results } - - return self + results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) + results.append(contentsOf: DiffableResult(identifier: "typeParameters").trackDifference(actual: self.typeParameters, expected: castObject.typeParameters)) + return results } /// :nodoc: - /// - Parameter substring: Instance of a substring - /// - Returns: Returns number of times a substring appears in self - func countInstances(of substring: String) -> Int { - guard !substring.isEmpty else { return 0 } - var count = 0 - var searchRange: Range? - while let foundRange = range(of: substring, options: [], range: searchRange) { - count += 1 - searchRange = Range(uncheckedBounds: (lower: foundRange.upperBound, upper: endIndex)) - } - return count + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.name) + hasher.combine(self.typeParameters) + return hasher.finalize() } /// :nodoc: - /// Removes leading and trailing whitespace from str. Returns false if str was not altered. - @discardableResult - mutating func strip() -> Bool { - let strippedString = stripped() - guard strippedString != self else { return false } - self = strippedString + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? GenericType else { return false } + if self.name != rhs.name { return false } + if self.typeParameters != rhs.typeParameters { return false } return true - } + } - /// :nodoc: - /// Returns a copy of str with leading and trailing whitespace removed. - func stripped() -> String { - return String(self.trimmingCharacters(in: .whitespaces)) - } +// sourcery:inline:GenericType.AutoCoding - /// :nodoc: - @discardableResult - mutating func trimPrefix(_ prefix: String) -> Bool { - guard hasPrefix(prefix) else { return false } - self = String(self.suffix(self.count - prefix.count)) - return true - } + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let name: String = aDecoder.decode(forKey: "name") else { + withVaList(["name"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.name = name + guard let typeParameters: [GenericTypeParameter] = aDecoder.decode(forKey: "typeParameters") else { + withVaList(["typeParameters"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.typeParameters = typeParameters + } - /// :nodoc: - func trimmingPrefix(_ prefix: String) -> String { - guard hasPrefix(prefix) else { return self } - return String(self.suffix(self.count - prefix.count)) - } + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.typeParameters, forKey: "typeParameters") + } - /// :nodoc: - @discardableResult - mutating func trimSuffix(_ suffix: String) -> Bool { - guard hasSuffix(suffix) else { return false } - self = String(self.prefix(self.count - suffix.count)) - return true - } +// sourcery:end +} - /// :nodoc: - func trimmingSuffix(_ suffix: String) -> String { - guard hasSuffix(suffix) else { return self } - return String(self.prefix(self.count - suffix.count)) - } +"""), + .init(name: "Import.swift", content: +""" +import Foundation - /// :nodoc: - func dropFirstAndLast(_ n: Int = 1) -> String { - return drop(first: n, last: n) - } +/// Defines import type +#if canImport(ObjectiveC) +@objcMembers +#endif +public class Import: NSObject, SourceryModelWithoutDescription, Diffable { + /// Import kind, e.g. class, struct in `import class Module.ClassName` + public var kind: String? + + /// Import path + public var path: String /// :nodoc: - func drop(first: Int, last: Int) -> String { - return String(self.dropFirst(first).dropLast(last)) + public init(path: String, kind: String? = nil) { + self.path = path + self.kind = kind } - /// :nodoc: - /// Wraps brackets if needed to make a valid type name - func bracketsBalancing() -> String { - if hasPrefix("(") && hasSuffix(")") { - let unwrapped = dropFirstAndLast() - return unwrapped.commaSeparated().count == 1 ? unwrapped.bracketsBalancing() : self - } else { - let wrapped = "(\\(self))" - return wrapped.isValidTupleName() || !isBracketsBalanced() ? wrapped : self + /// Full import value e.g. `import struct Module.StructName` + public override var description: String { + if let kind = kind { + return "\\(kind) \\(path)" } + + return path } - /// :nodoc: - /// Returns true if given string can represent a valid tuple type name - func isValidTupleName() -> Bool { - guard hasPrefix("(") && hasSuffix(")") else { return false } - let trimmedBracketsName = dropFirstAndLast() - return trimmedBracketsName.isBracketsBalanced() && trimmedBracketsName.commaSeparated().count > 1 + /// Returns module name from a import, e.g. if you had `import struct Module.Submodule.Struct` it will return `Module.Submodule` + public var moduleName: String { + if kind != nil { + if let idx = path.lastIndex(of: ".") { + return String(path[.. Bool { - if hasPrefix("Array<") { return true } - if hasPrefix("[") && hasSuffix("]") { - return dropFirstAndLast().colonSeparated().count == 1 + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? Import else { + results.append("Incorrect type ") + return results } - return false + results.append(contentsOf: DiffableResult(identifier: "kind").trackDifference(actual: self.kind, expected: castObject.kind)) + results.append(contentsOf: DiffableResult(identifier: "path").trackDifference(actual: self.path, expected: castObject.path)) + return results } /// :nodoc: - func isValidDictionaryName() -> Bool { - if hasPrefix("Dictionary<") { return true } - if hasPrefix("[") && contains(":") && hasSuffix("]") { - return dropFirstAndLast().colonSeparated().count == 2 - } - return false + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.kind) + hasher.combine(self.path) + return hasher.finalize() } /// :nodoc: - func isValidClosureName() -> Bool { - return components(separatedBy: "->", excludingDelimiterBetween: (["(", "<"], [")", ">"])).count > 1 + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? Import else { return false } + if self.kind != rhs.kind { return false } + if self.path != rhs.path { return false } + return true } - /// :nodoc: - /// Returns true if all opening brackets are balanced with closed brackets. - func isBracketsBalanced() -> Bool { - var bracketsCount: Int = 0 - for char in self { - if char == "(" { bracketsCount += 1 } else if char == ")" { bracketsCount -= 1 } - if bracketsCount < 0 { return false } +// sourcery:inline:Import.AutoCoding + + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + self.kind = aDecoder.decode(forKey: "kind") + guard let path: String = aDecoder.decode(forKey: "path") else { + withVaList(["path"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.path = path } - return bracketsCount == 0 + + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.kind, forKey: "kind") + aCoder.encode(self.path, forKey: "path") + } + +// sourcery:end +} + +"""), + .init(name: "Log.swift", content: +""" +//import Darwin +import Foundation + +/// :nodoc: +public enum Log { + + public enum Level: Int { + case errors + case warnings + case info + case verbose } - /// :nodoc: - /// Returns components separated with a comma respecting nested types - func commaSeparated() -> [String] { - return components(separatedBy: ",", excludingDelimiterBetween: ("<[({", "})]>")) + public static var level: Level = .warnings + public static var logBenchmarks: Bool = false + public static var logAST: Bool = false + + public static var stackMessages: Bool = false + public private(set) static var messagesStack = [String]() + + public static func error(_ message: Any) { + log(level: .errors, "error: \\(message)") + // to return error when running swift templates which is done in a different process + if ProcessInfo.processInfo.processName != "Sourcery" { + fputs("\\(message)", stderr) + } } - /// :nodoc: - /// Returns components separated with colon respecting nested types - func colonSeparated() -> [String] { - return components(separatedBy: ":", excludingDelimiterBetween: ("<[({", "})]>")) + public static func warning(_ message: Any) { + log(level: .warnings, "warning: \\(message)") } - /// :nodoc: - /// Returns components separated with semicolon respecting nested contexts - func semicolonSeparated() -> [String] { - return components(separatedBy: ";", excludingDelimiterBetween: ("{", "}")) + public static func astWarning(_ message: Any) { + guard logAST else { return } + log(level: .warnings, "ast warning: \\(message)") } - /// :nodoc: - func components(separatedBy delimiter: String, excludingDelimiterBetween between: (open: String, close: String)) -> [String] { - return self.components(separatedBy: delimiter, excludingDelimiterBetween: (between.open.map { String($0) }, between.close.map { String($0) })) + public static func astError(_ message: Any) { + guard logAST else { return } + log(level: .errors, "ast error: \\(message)") } - /// :nodoc: - func components(separatedBy delimiter: String, excludingDelimiterBetween between: (open: [String], close: [String])) -> [String] { - var boundingCharactersCount: Int = 0 - var quotesCount: Int = 0 - var item = "" - var items = [String]() + public static func verbose(_ message: Any) { + log(level: .verbose, message) + } - var i = self.startIndex - while i < self.endIndex { - var offset = 1 - defer { - i = self.index(i, offsetBy: offset) - } - let currentlyScanned = self[i..<(self.index(i, offsetBy: delimiter.count, limitedBy: self.endIndex) ?? self.endIndex)] - if let openString = between.open.first(where: { String(self[i...]).starts(with: $0) }) { - if !(boundingCharactersCount == 0 && String(self[i]) == delimiter) { - boundingCharactersCount += 1 - } - offset = openString.count - } else if let closeString = between.close.first(where: { String(self[i...]).starts(with: $0) }) { - // do not count `->` - if !(self[i] == ">" && item.last == "-") { - boundingCharactersCount = max(0, boundingCharactersCount - 1) - } - offset = closeString.count - } - if self[i] == "\\"" { - quotesCount += 1 - } + public static func info(_ message: Any) { + log(level: .info, message) + } - if currentlyScanned == delimiter && boundingCharactersCount == 0 && quotesCount % 2 == 0 { - items.append(item) - item = "" - i = self.index(i, offsetBy: delimiter.count - 1) - } else { - item += self[i.. DiffableResult { let results = DiffableResult() - guard let castObject = object as? FileParserResult else { - results.append("Incorrect type ") + guard let castObject = object as? Modifier else { + results.append("Incorrect type ") return results } - results.append(contentsOf: DiffableResult(identifier: "path").trackDifference(actual: self.path, expected: castObject.path)) - results.append(contentsOf: DiffableResult(identifier: "module").trackDifference(actual: self.module, expected: castObject.module)) - results.append(contentsOf: DiffableResult(identifier: "types").trackDifference(actual: self.types, expected: castObject.types)) - results.append(contentsOf: DiffableResult(identifier: "functions").trackDifference(actual: self.functions, expected: castObject.functions)) - results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) - results.append(contentsOf: DiffableResult(identifier: "inlineRanges").trackDifference(actual: self.inlineRanges, expected: castObject.inlineRanges)) - results.append(contentsOf: DiffableResult(identifier: "inlineIndentations").trackDifference(actual: self.inlineIndentations, expected: castObject.inlineIndentations)) - results.append(contentsOf: DiffableResult(identifier: "modifiedDate").trackDifference(actual: self.modifiedDate, expected: castObject.modifiedDate)) - results.append(contentsOf: DiffableResult(identifier: "sourceryVersion").trackDifference(actual: self.sourceryVersion, expected: castObject.sourceryVersion)) + results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) + results.append(contentsOf: DiffableResult(identifier: "detail").trackDifference(actual: self.detail, expected: castObject.detail)) return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() - hasher.combine(self.path) - hasher.combine(self.module) - hasher.combine(self.types) - hasher.combine(self.functions) - hasher.combine(self.typealiases) - hasher.combine(self.inlineRanges) - hasher.combine(self.inlineIndentations) - hasher.combine(self.modifiedDate) - hasher.combine(self.sourceryVersion) + hasher.combine(self.name) + hasher.combine(self.detail) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? FileParserResult else { return false } - if self.path != rhs.path { return false } - if self.module != rhs.module { return false } - if self.types != rhs.types { return false } - if self.functions != rhs.functions { return false } - if self.typealiases != rhs.typealiases { return false } - if self.inlineRanges != rhs.inlineRanges { return false } - if self.inlineIndentations != rhs.inlineIndentations { return false } - if self.modifiedDate != rhs.modifiedDate { return false } - if self.sourceryVersion != rhs.sourceryVersion { return false } + guard let rhs = object as? Modifier else { return false } + if self.name != rhs.name { return false } + if self.detail != rhs.detail { return false } return true } -// sourcery:inline:FileParserResult.AutoCoding + // sourcery:inline:Modifier.AutoCoding - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - self.path = aDecoder.decode(forKey: "path") - self.module = aDecoder.decode(forKey: "module") - guard let types: [Type] = aDecoder.decode(forKey: "types") else { - withVaList(["types"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.types = types - guard let functions: [SourceryMethod] = aDecoder.decode(forKey: "functions") else { - withVaList(["functions"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.functions = functions - guard let typealiases: [Typealias] = aDecoder.decode(forKey: "typealiases") else { - withVaList(["typealiases"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.typealiases = typealiases - guard let inlineRanges: [String: NSRange] = aDecoder.decode(forKey: "inlineRanges") else { - withVaList(["inlineRanges"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.inlineRanges = inlineRanges - guard let inlineIndentations: [String: String] = aDecoder.decode(forKey: "inlineIndentations") else { - withVaList(["inlineIndentations"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.inlineIndentations = inlineIndentations - guard let modifiedDate: Date = aDecoder.decode(forKey: "modifiedDate") else { - withVaList(["modifiedDate"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.modifiedDate = modifiedDate - guard let sourceryVersion: String = aDecoder.decode(forKey: "sourceryVersion") else { - withVaList(["sourceryVersion"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.sourceryVersion = sourceryVersion - } + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let name: String = aDecoder.decode(forKey: "name") else { + withVaList(["name"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.name = name + self.detail = aDecoder.decode(forKey: "detail") + } - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.path, forKey: "path") - aCoder.encode(self.module, forKey: "module") - aCoder.encode(self.types, forKey: "types") - aCoder.encode(self.functions, forKey: "functions") - aCoder.encode(self.typealiases, forKey: "typealiases") - aCoder.encode(self.inlineRanges, forKey: "inlineRanges") - aCoder.encode(self.inlineIndentations, forKey: "inlineIndentations") - aCoder.encode(self.modifiedDate, forKey: "modifiedDate") - aCoder.encode(self.sourceryVersion, forKey: "sourceryVersion") - } -// sourcery:end + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.detail, forKey: "detail") + } + // sourcery:end } """), - .init(name: "Generic.swift", content: + .init(name: "ParserResultsComposed.swift", content: """ +// +// Created by Krzysztof Zablocki on 31/12/2016. +// Copyright (c) 2016 Pixle. All rights reserved. +// + import Foundation -/// Descibes Swift generic type -@objcMembers -public final class GenericType: NSObject, SourceryModelWithoutDescription, Diffable { - /// The name of the base type, i.e. `Array` for `Array` - public var name: String +internal struct ParserResultsComposed { + private(set) var typeMap = [String: Type]() + private(set) var modules = [String: [String: Type]]() + private(set) var types = [Type]() - /// This generic type parameters - public let typeParameters: [GenericTypeParameter] + let parsedTypes: [Type] + let functions: [SourceryMethod] + let resolvedTypealiases: [String: Typealias] + let unresolvedTypealiases: [String: Typealias] - /// :nodoc: - public init(name: String, typeParameters: [GenericTypeParameter] = []) { - self.name = name - self.typeParameters = typeParameters - } + init(parserResult: FileParserResult) { + // TODO: This logic should really be more complicated + // For any resolution we need to be looking at accessLevel and module boundaries + // e.g. there might be a typealias `private typealias Something = MyType` in one module and same name in another with public modifier, one could be accessed and the other could not + self.functions = parserResult.functions + let aliases = Self.typealiases(parserResult) + resolvedTypealiases = aliases.resolved + unresolvedTypealiases = aliases.unresolved + parsedTypes = parserResult.types - public var asSource: String { - let arguments = typeParameters - .map({ $0.typeName.asSource }) - .joined(separator: ", ") - return "\\(name)<\\(arguments)>" - } + // set definedInType for all methods and variables + parsedTypes + .forEach { type in + type.variables.forEach { $0.definedInType = type } + type.methods.forEach { $0.definedInType = type } + type.subscripts.forEach { $0.definedInType = type } + } - public override var description: String { - asSource - } + // map all known types to their names + parsedTypes + .filter { !$0.isExtension } + .forEach { + typeMap[$0.globalName] = $0 + if let module = $0.module { + var typesByModules = modules[module, default: [:]] + typesByModules[$0.name] = $0 + modules[module] = typesByModules + } + } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? GenericType else { - results.append("Incorrect type ") - return results + /// Resolve typealiases + let typealiases = Array(unresolvedTypealiases.values) + typealiases.forEach { alias in + alias.type = resolveType(typeName: alias.typeName, containingType: alias.parent) } - results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "typeParameters").trackDifference(actual: self.typeParameters, expected: castObject.typeParameters)) - return results + + types = unifyTypes() } - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.name) - hasher.combine(self.typeParameters) - return hasher.finalize() + private func resolveExtensionOfNestedType(_ type: Type) { + var components = type.localName.components(separatedBy: ".") + let rootName = type.module ?? components.removeFirst() // Module/parent name + if let moduleTypes = modules[rootName], let baseType = moduleTypes[components.joined(separator: ".")] ?? moduleTypes[type.localName] { + type.localName = baseType.localName + type.module = baseType.module + type.parent = baseType.parent + } else { + for _import in type.imports { + let parentKey = "\\(rootName).\\(components.joined(separator: "."))" + let parentKeyFull = "\\(_import.moduleName).\\(parentKey)" + if let moduleTypes = modules[_import.moduleName], let baseType = moduleTypes[parentKey] ?? moduleTypes[parentKeyFull] { + type.localName = baseType.localName + type.module = baseType.module + type.parent = baseType.parent + return + } + } + } } - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? GenericType else { return false } - if self.name != rhs.name { return false } - if self.typeParameters != rhs.typeParameters { return false } - return true + // if it had contained types, they might have been fully defined and so their name has to be noted in uniques + private mutating func rewriteChildren(of type: Type) { + // child is never an extension so no need to check + for child in type.containedTypes { + typeMap[child.globalName] = child + rewriteChildren(of: child) + } } -// sourcery:inline:GenericType.AutoCoding + private mutating func unifyTypes() -> [Type] { + /// Resolve actual names of extensions, as they could have been done on typealias and note updated child names in uniques if needed + parsedTypes + .filter { $0.isExtension } + .forEach { (type: Type) in + let oldName = type.globalName - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { - withVaList(["name"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + let hasDotInLocalName = type.localName.contains(".") as Bool + if let _ = type.parent, hasDotInLocalName { + resolveExtensionOfNestedType(type) } - fatalError() - }; self.name = name - guard let typeParameters: [GenericTypeParameter] = aDecoder.decode(forKey: "typeParameters") else { - withVaList(["typeParameters"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + + if let resolved = resolveGlobalName(for: oldName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases)?.name { + var moduleName: String = "" + if let module = type.module { + moduleName = "\\(module)." + } + type.localName = resolved.replacingOccurrences(of: moduleName, with: "") + } else { + return } - fatalError() - }; self.typeParameters = typeParameters - } - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.typeParameters, forKey: "typeParameters") - } + // nothing left to do + guard oldName != type.globalName else { + return + } + rewriteChildren(of: type) + } -// sourcery:end -} + // extend all types with their extensions + parsedTypes.forEach { type in + type.inheritedTypes = type.inheritedTypes.map { inheritedName in + resolveGlobalName(for: inheritedName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases)?.name ?? inheritedName + } -/// Descibes Swift generic type parameter -@objcMembers -public final class GenericTypeParameter: NSObject, SourceryModel, Diffable { + let uniqueType = typeMap[type.globalName] ?? // this check will only fail on an extension? + typeFromComposedName(type.name, modules: modules) ?? // this can happen for an extension on unknown type, this case should probably be handled by the inferTypeNameFromModules + (inferTypeNameFromModules(from: type.localName, containedInType: type.parent, uniqueTypes: typeMap, modules: modules).flatMap { typeMap[$0] }) - /// Generic parameter type name - public var typeName: TypeName + guard let current = uniqueType else { + assert(type.isExtension, "Type \\(type.globalName) should be extension") - // sourcery: skipEquality, skipDescription - /// Generic parameter type, if known - public var type: Type? + // for unknown types we still store their extensions but mark them as unknown + type.isUnknownExtension = true + if let existingType = typeMap[type.globalName] { + existingType.extend(type) + typeMap[type.globalName] = existingType + } else { + typeMap[type.globalName] = type + } - /// :nodoc: - public init(typeName: TypeName, type: Type? = nil) { - self.typeName = typeName - self.type = type - } + let inheritanceClause = type.inheritedTypes.isEmpty ? "" : + ": \\(type.inheritedTypes.joined(separator: ", "))" - /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "typeName = \\(String(describing: self.typeName))" - return string - } + Log.astWarning("Found \\"extension \\(type.name)\\(inheritanceClause)\\" of type for which there is no original type declaration information.") + return + } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? GenericTypeParameter else { - results.append("Incorrect type ") - return results + if current == type { return } + + current.extend(type) + typeMap[current.globalName] = current } - results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) - return results - } - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.typeName) - return hasher.finalize() + let values = typeMap.values + var processed = Set(minimumCapacity: values.count) + return typeMap.values.filter({ + let name = $0.globalName + let wasProcessed = processed.contains(name) + processed.insert(name) + return !wasProcessed + }) } - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? GenericTypeParameter else { return false } - if self.typeName != rhs.typeName { return false } - return true - } + /// returns typealiases map to their full names, with `resolved` removing intermediate + /// typealises and `unresolved` including typealiases that reference other typealiases. + private static func typealiases(_ parserResult: FileParserResult) -> (resolved: [String: Typealias], unresolved: [String: Typealias]) { + var typealiasesByNames = [String: Typealias]() + parserResult.typealiases.forEach { typealiasesByNames[$0.name] = $0 } + parserResult.types.forEach { type in + type.typealiases.forEach({ (_, alias) in + // TODO: should I deal with the fact that alias.name depends on type name but typenames might be updated later on + // maybe just handle non extension case here and extension aliases after resolving them? + typealiasesByNames[alias.name] = alias + }) + } -// sourcery:inline:GenericTypeParameter.AutoCoding + let unresolved = typealiasesByNames - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { - withVaList(["typeName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.typeName = typeName - self.type = aDecoder.decode(forKey: "type") - } + // ! if a typealias leads to another typealias, follow through and replace with final type + typealiasesByNames.forEach { _, alias in + var aliasNamesToReplace = [alias.name] + var finalAlias = alias + while let targetAlias = typealiasesByNames[finalAlias.typeName.name] { + aliasNamesToReplace.append(targetAlias.name) + finalAlias = targetAlias + } - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.typeName, forKey: "typeName") - aCoder.encode(self.type, forKey: "type") + // ! replace all keys + aliasNamesToReplace.forEach { typealiasesByNames[$0] = finalAlias } } -// sourcery:end -} + return (resolved: typealiasesByNames, unresolved: unresolved) + } -"""), - .init(name: "GenericRequirement.swift", content: -""" -import Foundation + /// Resolves type identifier for name + func resolveGlobalName(for type: String, + containingType: Type? = nil, + unique: [String: Type]? = nil, + modules: [String: [String: Type]], + typealiases: [String: Typealias]) -> (name: String, typealias: Typealias?)? { + // if the type exists for this name and isn't an extension just return it's name + // if it's extension we need to check if there aren't other options TODO: verify + if let realType = unique?[type], realType.isExtension == false { + return (name: realType.globalName, typealias: nil) + } -/// modifier can be thing like `private`, `class`, `nonmutating` -/// if a declaration has modifier like `private(set)` it's name will be `private` and detail will be `set` -@objcMembers -public class GenericRequirement: NSObject, SourceryModel, Diffable { + if let alias = typealiases[type] { + return (name: alias.type?.globalName ?? alias.typeName.name, typealias: alias) + } - public enum Relationship: String { - case equals - case conformsTo + if let containingType = containingType { + if type == "Self" { + return (name: containingType.globalName, typealias: nil) + } - var syntax: String { - switch self { - case .equals: - return "==" - case .conformsTo: - return ":" + var currentContainer: Type? = containingType + while currentContainer != nil, let parentName = currentContainer?.globalName { + /// TODO: no parent for sure? + /// manually walk the containment tree + if let name = resolveGlobalName(for: "\\(parentName).\\(type)", containingType: nil, unique: unique, modules: modules, typealiases: typealiases) { + return name + } + + currentContainer = currentContainer?.parent } - } - } - public var leftType: AssociatedType - public let rightType: GenericTypeParameter +// if let name = resolveGlobalName(for: "\\(containingType.globalName).\\(type)", containingType: containingType.parent, unique: unique, modules: modules, typealiases: typealiases) { +// return name +// } - /// relationship name - public let relationship: String +// last check it's via module +// if let module = containingType.module, let name = resolveGlobalName(for: "\\(module).\\(type)", containingType: nil, unique: unique, modules: modules, typealiases: typealiases) { +// return name +// } + } - /// Syntax e.g. `==` or `:` - public let relationshipSyntax: String + // TODO: is this needed? + if let inferred = inferTypeNameFromModules(from: type, containedInType: containingType, uniqueTypes: unique ?? [:], modules: modules) { + return (name: inferred, typealias: nil) + } - public init(leftType: AssociatedType, rightType: GenericTypeParameter, relationship: Relationship) { - self.leftType = leftType - self.rightType = rightType - self.relationship = relationship.rawValue - self.relationshipSyntax = relationship.syntax + return typeFromComposedName(type, modules: modules).map { (name: $0.globalName, typealias: nil) } } - /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "leftType = \\(String(describing: self.leftType)), " - string += "rightType = \\(String(describing: self.rightType)), " - string += "relationship = \\(String(describing: self.relationship)), " - string += "relationshipSyntax = \\(String(describing: self.relationshipSyntax))" - return string - } + private func inferTypeNameFromModules(from typeIdentifier: String, containedInType: Type?, uniqueTypes: [String: Type], modules: [String: [String: Type]]) -> String? { + func fullName(for module: String) -> String { + "\\(module).\\(typeIdentifier)" + } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? GenericRequirement else { - results.append("Incorrect type ") - return results + func type(for module: String) -> Type? { + return modules[module]?[typeIdentifier] } - results.append(contentsOf: DiffableResult(identifier: "leftType").trackDifference(actual: self.leftType, expected: castObject.leftType)) - results.append(contentsOf: DiffableResult(identifier: "rightType").trackDifference(actual: self.rightType, expected: castObject.rightType)) - results.append(contentsOf: DiffableResult(identifier: "relationship").trackDifference(actual: self.relationship, expected: castObject.relationship)) - results.append(contentsOf: DiffableResult(identifier: "relationshipSyntax").trackDifference(actual: self.relationshipSyntax, expected: castObject.relationshipSyntax)) - return results - } - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.leftType) - hasher.combine(self.rightType) - hasher.combine(self.relationship) - hasher.combine(self.relationshipSyntax) - return hasher.finalize() - } + func ambiguousErrorMessage(from types: [Type]) -> String? { + Log.astWarning("Ambiguous type \\(typeIdentifier), found \\(types.map { $0.globalName }.joined(separator: ", ")). Specify module name at declaration site to disambiguate.") + return nil + } - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? GenericRequirement else { return false } - if self.leftType != rhs.leftType { return false } - if self.rightType != rhs.rightType { return false } - if self.relationship != rhs.relationship { return false } - if self.relationshipSyntax != rhs.relationshipSyntax { return false } - return true - } + let explicitModulesAtDeclarationSite: [String] = [ + containedInType?.module.map { [$0] } ?? [], // main module for this typename + containedInType?.imports.map { $0.moduleName } ?? [] // imported modules + ] + .flatMap { $0 } - // sourcery:inline:GenericRequirement.AutoCoding + let remainingModules = Set(modules.keys).subtracting(explicitModulesAtDeclarationSite) - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let leftType: AssociatedType = aDecoder.decode(forKey: "leftType") else { - withVaList(["leftType"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.leftType = leftType - guard let rightType: GenericTypeParameter = aDecoder.decode(forKey: "rightType") else { - withVaList(["rightType"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.rightType = rightType - guard let relationship: String = aDecoder.decode(forKey: "relationship") else { - withVaList(["relationship"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.relationship = relationship - guard let relationshipSyntax: String = aDecoder.decode(forKey: "relationshipSyntax") else { - withVaList(["relationshipSyntax"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.relationshipSyntax = relationshipSyntax + /// We need to check whether we can find type in one of the modules but we need to be careful to avoid amibiguity + /// First checking explicit modules available at declaration site (so source module + all imported ones) + /// If there is no ambigiuity there we can assume that module will be resolved by the compiler + /// If that's not the case we look after remaining modules in the application and if the typename has no ambigiuity we use that + /// But if there is more than 1 typename duplication across modules we have no way to resolve what is the compiler going to use so we fail + let moduleSetsToCheck: [[String]] = [ + explicitModulesAtDeclarationSite, + Array(remainingModules) + ] + + for modules in moduleSetsToCheck { + let possibleTypes = modules + .compactMap { type(for: $0) } + + if possibleTypes.count > 1 { + return ambiguousErrorMessage(from: possibleTypes) } - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.leftType, forKey: "leftType") - aCoder.encode(self.rightType, forKey: "rightType") - aCoder.encode(self.relationship, forKey: "relationship") - aCoder.encode(self.relationshipSyntax, forKey: "relationshipSyntax") + if let type = possibleTypes.first { + return type.globalName } - // sourcery:end -} - -"""), - .init(name: "Import.swift", content: -""" -import Foundation - -/// Defines import type -@objcMembers -public class Import: NSObject, SourceryModelWithoutDescription, Diffable { - /// Import kind, e.g. class, struct in `import class Module.ClassName` - public var kind: String? - - /// Import path - public var path: String - - /// :nodoc: - public init(path: String, kind: String? = nil) { - self.path = path - self.kind = kind - } - - /// Full import value e.g. `import struct Module.StructName` - public override var description: String { - if let kind = kind { - return "\\(kind) \\(path)" } - return path + // as last result for unknown types / extensions + // try extracting type from unique array + if let module = containedInType?.module { + return uniqueTypes[fullName(for: module)]?.globalName + } + return nil } - /// Returns module name from a import, e.g. if you had `import struct Module.Submodule.Struct` it will return `Module.Submodule` - public var moduleName: String { - if kind != nil { - if let idx = path.lastIndex(of: ".") { - return String(path[.. Type? { + guard name.contains(".") else { return nil } + let nameComponents = name.components(separatedBy: ".") + let moduleName = nameComponents[0] + let typeName = nameComponents.suffix(from: 1).joined(separator: ".") + return modules[moduleName]?[typeName] } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? Import else { - results.append("Incorrect type ") - return results + func resolveType(typeName: TypeName, containingType: Type?, method: Method? = nil) -> Type? { + let resolveTypeWithName = { (typeName: TypeName) -> Type? in + return self.resolveType(typeName: typeName, containingType: containingType) } - results.append(contentsOf: DiffableResult(identifier: "kind").trackDifference(actual: self.kind, expected: castObject.kind)) - results.append(contentsOf: DiffableResult(identifier: "path").trackDifference(actual: self.path, expected: castObject.path)) - return results - } - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.kind) - hasher.combine(self.path) - return hasher.finalize() - } + let unique = typeMap - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? Import else { return false } - if self.kind != rhs.kind { return false } - if self.path != rhs.path { return false } - return true - } + if let name = typeName.actualTypeName { + let resolvedIdentifier = name.generic?.name ?? name.unwrappedTypeName + return unique[resolvedIdentifier] + } -// sourcery:inline:Import.AutoCoding + let retrievedName = actualTypeName(for: typeName, containingType: containingType) + let lookupName = retrievedName ?? typeName - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - self.kind = aDecoder.decode(forKey: "kind") - guard let path: String = aDecoder.decode(forKey: "path") else { - withVaList(["path"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + if let tuple = lookupName.tuple { + var needsUpdate = false + + tuple.elements.forEach { tupleElement in + tupleElement.type = resolveTypeWithName(tupleElement.typeName) + if tupleElement.typeName.actualTypeName != nil { + needsUpdate = true } - fatalError() - }; self.path = path - } + } - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.kind, forKey: "kind") - aCoder.encode(self.path, forKey: "path") - } + if needsUpdate || retrievedName != nil { + let tupleCopy = TupleType(name: tuple.name, elements: tuple.elements) + tupleCopy.elements.forEach { + $0.typeName = $0.actualTypeName ?? $0.typeName + $0.typeName.actualTypeName = nil + } + tupleCopy.name = tupleCopy.elements.asTypeName -// sourcery:end -} + typeName.tuple = tupleCopy // TODO: really don't like this old behaviour + typeName.actualTypeName = TypeName(name: tupleCopy.name, + isOptional: typeName.isOptional, + isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, + tuple: tupleCopy, + array: lookupName.array, + dictionary: lookupName.dictionary, + closure: lookupName.closure, + set: lookupName.set, + generic: lookupName.generic + ) + } + return nil + } else + if let array = lookupName.array { + array.elementType = resolveTypeWithName(array.elementTypeName) -"""), - .init(name: "JSExport.generated.swift", content: -""" -// Generated using Sourcery 2.0.3 — https://github.com/krzysztofzablocki/Sourcery -// DO NOT EDIT -// swiftlint:disable vertical_whitespace trailing_newline + if array.elementTypeName.actualTypeName != nil || retrievedName != nil { + let array = ArrayType(name: array.name, elementTypeName: array.elementTypeName, elementType: array.elementType) + array.elementTypeName = array.elementTypeName.actualTypeName ?? array.elementTypeName + array.elementTypeName.actualTypeName = nil + array.name = array.asSource + typeName.array = array // TODO: really don't like this old behaviour + typeName.generic = array.asGeneric // TODO: really don't like this old behaviour -import JavaScriptCore + typeName.actualTypeName = TypeName(name: array.name, + isOptional: typeName.isOptional, + isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, + tuple: lookupName.tuple, + array: array, + dictionary: lookupName.dictionary, + closure: lookupName.closure, + set: lookupName.set, + generic: typeName.generic + ) + } + } else + if let dictionary = lookupName.dictionary { + dictionary.keyType = resolveTypeWithName(dictionary.keyTypeName) + dictionary.valueType = resolveTypeWithName(dictionary.valueTypeName) -@objc protocol ActorAutoJSExport: JSExport { - var kind: String { get } - var isFinal: Bool { get } - var module: String? { get } - var imports: [Import] { get } - var allImports: [Import] { get } - var accessLevel: String { get } - var name: String { get } - var isUnknownExtension: Bool { get } - var globalName: String { get } - var isGeneric: Bool { get } - var localName: String { get } - var variables: [Variable] { get } - var rawVariables: [Variable] { get } - var allVariables: [Variable] { get } - var methods: [Method] { get } - var rawMethods: [Method] { get } - var allMethods: [Method] { get } - var subscripts: [Subscript] { get } - var rawSubscripts: [Subscript] { get } - var allSubscripts: [Subscript] { get } - var initializers: [Method] { get } - var annotations: Annotations { get } - var documentation: Documentation { get } - var staticVariables: [Variable] { get } - var staticMethods: [Method] { get } - var classMethods: [Method] { get } - var instanceVariables: [Variable] { get } - var instanceMethods: [Method] { get } - var computedVariables: [Variable] { get } - var storedVariables: [Variable] { get } - var inheritedTypes: [String] { get } - var based: [String: String] { get } - var basedTypes: [String: Type] { get } - var inherits: [String: Type] { get } - var implements: [String: Type] { get } - var containedTypes: [Type] { get } - var containedType: [String: Type] { get } - var parentName: String? { get } - var parent: Type? { get } - var supertype: Type? { get } - var attributes: AttributeList { get } - var modifiers: [SourceryModifier] { get } - var fileName: String? { get } -} + if dictionary.keyTypeName.actualTypeName != nil || dictionary.valueTypeName.actualTypeName != nil || retrievedName != nil { + let dictionary = DictionaryType(name: dictionary.name, valueTypeName: dictionary.valueTypeName, valueType: dictionary.valueType, keyTypeName: dictionary.keyTypeName, keyType: dictionary.keyType) + dictionary.keyTypeName = dictionary.keyTypeName.actualTypeName ?? dictionary.keyTypeName + dictionary.keyTypeName.actualTypeName = nil // TODO: really don't like this old behaviour + dictionary.valueTypeName = dictionary.valueTypeName.actualTypeName ?? dictionary.valueTypeName + dictionary.valueTypeName.actualTypeName = nil // TODO: really don't like this old behaviour -extension Actor: ActorAutoJSExport {} + dictionary.name = dictionary.asSource -@objc protocol ArrayTypeAutoJSExport: JSExport { - var name: String { get } - var elementTypeName: TypeName { get } - var elementType: Type? { get } - var asGeneric: GenericType { get } - var asSource: String { get } -} + typeName.dictionary = dictionary // TODO: really don't like this old behaviour + typeName.generic = dictionary.asGeneric // TODO: really don't like this old behaviour -extension ArrayType: ArrayTypeAutoJSExport {} + typeName.actualTypeName = TypeName(name: dictionary.asSource, + isOptional: typeName.isOptional, + isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, + tuple: lookupName.tuple, + array: lookupName.array, + dictionary: dictionary, + closure: lookupName.closure, + set: lookupName.set, + generic: dictionary.asGeneric + ) + } + } else + if let closure = lookupName.closure { + var needsUpdate = false -@objc protocol AssociatedTypeAutoJSExport: JSExport { - var name: String { get } - var typeName: TypeName? { get } - var type: Type? { get } -} + closure.returnType = resolveTypeWithName(closure.returnTypeName) + closure.parameters.forEach { parameter in + parameter.type = resolveTypeWithName(parameter.typeName) + if parameter.typeName.actualTypeName != nil { + needsUpdate = true + } + } -extension AssociatedType: AssociatedTypeAutoJSExport {} + if closure.returnTypeName.actualTypeName != nil || needsUpdate || retrievedName != nil { + typeName.closure = closure // TODO: really don't like this old behaviour -@objc protocol AssociatedValueAutoJSExport: JSExport { - var localName: String? { get } - var externalName: String? { get } - var typeName: TypeName { get } - var type: Type? { get } - var defaultValue: String? { get } - var annotations: Annotations { get } - var isOptional: Bool { get } - var isImplicitlyUnwrappedOptional: Bool { get } - var unwrappedTypeName: String { get } -} + typeName.actualTypeName = TypeName(name: closure.asSource, + isOptional: typeName.isOptional, + isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, + tuple: lookupName.tuple, + array: lookupName.array, + dictionary: lookupName.dictionary, + closure: closure, + set: lookupName.set, + generic: lookupName.generic + ) + } -extension AssociatedValue: AssociatedValueAutoJSExport {} + return nil + } else + if let generic = lookupName.generic { + var needsUpdate = false -@objc protocol AttributeAutoJSExport: JSExport { - var name: String { get } - var arguments: [String: NSObject] { get } - var asSource: String { get } - var description: String { get } -} + generic.typeParameters.forEach { parameter in + parameter.type = resolveTypeWithName(parameter.typeName) + if parameter.typeName.actualTypeName != nil { + needsUpdate = true + } + } -extension Attribute: AttributeAutoJSExport {} + if needsUpdate || retrievedName != nil { + let generic = GenericType(name: generic.name, typeParameters: generic.typeParameters) + generic.typeParameters.forEach { + $0.typeName = $0.typeName.actualTypeName ?? $0.typeName + $0.typeName.actualTypeName = nil // TODO: really don't like this old behaviour + } + typeName.generic = generic // TODO: really don't like this old behaviour + typeName.array = lookupName.array // TODO: really don't like this old behaviour + typeName.dictionary = lookupName.dictionary // TODO: really don't like this old behaviour -@objc protocol BytesRangeAutoJSExport: JSExport { - var offset: Int64 { get } - var length: Int64 { get } -} + let params = generic.typeParameters.map { $0.typeName.asSource }.joined(separator: ", ") -extension BytesRange: BytesRangeAutoJSExport {} + typeName.actualTypeName = TypeName(name: "\\(generic.name)<\\(params)>", + isOptional: typeName.isOptional, + isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, + tuple: lookupName.tuple, + array: lookupName.array, // TODO: asArray + dictionary: lookupName.dictionary, // TODO: asDictionary + closure: lookupName.closure, + set: lookupName.set, + generic: generic + ) + } + } -@objc protocol ClassAutoJSExport: JSExport { - var kind: String { get } - var isFinal: Bool { get } - var module: String? { get } - var imports: [Import] { get } - var allImports: [Import] { get } - var accessLevel: String { get } - var name: String { get } - var isUnknownExtension: Bool { get } - var globalName: String { get } - var isGeneric: Bool { get } - var localName: String { get } - var variables: [Variable] { get } - var rawVariables: [Variable] { get } - var allVariables: [Variable] { get } - var methods: [Method] { get } - var rawMethods: [Method] { get } - var allMethods: [Method] { get } - var subscripts: [Subscript] { get } - var rawSubscripts: [Subscript] { get } - var allSubscripts: [Subscript] { get } - var initializers: [Method] { get } - var annotations: Annotations { get } - var documentation: Documentation { get } - var staticVariables: [Variable] { get } - var staticMethods: [Method] { get } - var classMethods: [Method] { get } - var instanceVariables: [Variable] { get } - var instanceMethods: [Method] { get } - var computedVariables: [Variable] { get } - var storedVariables: [Variable] { get } - var inheritedTypes: [String] { get } - var based: [String: String] { get } - var basedTypes: [String: Type] { get } - var inherits: [String: Type] { get } - var implements: [String: Type] { get } - var containedTypes: [Type] { get } - var containedType: [String: Type] { get } - var parentName: String? { get } - var parent: Type? { get } - var supertype: Type? { get } - var attributes: AttributeList { get } - var modifiers: [SourceryModifier] { get } - var fileName: String? { get } -} + if let aliasedName = (typeName.actualTypeName ?? retrievedName), aliasedName.unwrappedTypeName != typeName.unwrappedTypeName { + typeName.actualTypeName = aliasedName + } -extension Class: ClassAutoJSExport {} + let hasGenericRequirements = containingType?.genericRequirements.isEmpty == false + || (method != nil && method?.genericRequirements.isEmpty == false) -@objc protocol ClosureParameterAutoJSExport: JSExport { - var argumentLabel: String? { get } - var name: String? { get } - var typeName: TypeName { get } - var `inout`: Bool { get } - var type: Type? { get } - var typeAttributes: AttributeList { get } - var defaultValue: String? { get } - var annotations: Annotations { get } - var asSource: String { get } - var isOptional: Bool { get } - var isImplicitlyUnwrappedOptional: Bool { get } - var unwrappedTypeName: String { get } -} + if hasGenericRequirements { + // we should consider if we are looking up return type of a method with generic constraints + // where `typeName` passed would include `... where ...` suffix + let typeNameForLookup = typeName.name.split(separator: " ").first! + let genericRequirements: [GenericRequirement] + if let requirements = containingType?.genericRequirements, !requirements.isEmpty { + genericRequirements = requirements + } else { + genericRequirements = method?.genericRequirements ?? [] + } + let relevantRequirements = genericRequirements.filter { + // matched type against a generic requirement name + // thus type should be replaced with a protocol composition + $0.leftType.name == typeNameForLookup + } + if relevantRequirements.count > 1 { + // compose protocols into `ProtocolComposition` and generate TypeName + var implements: [String: Type] = [:] + relevantRequirements.forEach { + implements[$0.rightType.typeName.name] = $0.rightType.type + } + let composedProtocols = ProtocolComposition( + inheritedTypes: relevantRequirements.map { $0.rightType.typeName.unwrappedTypeName }, + isGeneric: true, + composedTypes: relevantRequirements.compactMap { $0.rightType.type }, + implements: implements + ) + typeName.actualTypeName = TypeName(name: "(\\(relevantRequirements.map { $0.rightType.typeName.unwrappedTypeName }.joined(separator: " & ")))", isProtocolComposition: true) + return composedProtocols + } else if let protocolRequirement = relevantRequirements.first { + // create TypeName off a single generic's protocol requirement + typeName.actualTypeName = TypeName(name: "(\\(protocolRequirement.rightType.typeName))") + return protocolRequirement.rightType.type + } + } -extension ClosureParameter: ClosureParameterAutoJSExport {} + // try to peek into typealias, maybe part of the typeName is a composed identifier from a type and typealias + // i.e. + // enum Module { + // typealias ID = MyView + // } + // class MyView { + // class ID: String {} + // } + // + // let variable: Module.ID.ID // should be resolved as MyView.ID type + let finalLookup = typeName.actualTypeName ?? typeName + var resolvedIdentifier = finalLookup.generic?.name ?? finalLookup.unwrappedTypeName + for alias in resolvedTypealiases { + /// iteratively replace all typealiases from the resolvedIdentifier to get to the actual type name requested + if resolvedIdentifier.contains(alias.value.name), let range = resolvedIdentifier.range(of: alias.value.name) { + resolvedIdentifier = resolvedIdentifier.replacingCharacters(in: range, with: alias.value.typeName.name) + } + } + // should we cache resolved typenames? + if unique[resolvedIdentifier] == nil { + // peek into typealiases, if any of them contain the same typeName + // this is done after the initial attempt in order to prioritise local (recognized) types first + // before even trying to substitute the requested type with any typealias + for alias in resolvedTypealiases { + /// iteratively replace all typealiases from the resolvedIdentifier to get to the actual type name requested, + /// ignoring namespacing + if resolvedIdentifier == alias.value.aliasName { + resolvedIdentifier = alias.value.typeName.name + typeName.actualTypeName = alias.value.typeName + break + } + } + } -@objc protocol ClosureTypeAutoJSExport: JSExport { - var name: String { get } - var parameters: [ClosureParameter] { get } - var returnTypeName: TypeName { get } - var actualReturnTypeName: TypeName { get } - var returnType: Type? { get } - var isOptionalReturnType: Bool { get } - var isImplicitlyUnwrappedOptionalReturnType: Bool { get } - var unwrappedReturnTypeName: String { get } - var isAsync: Bool { get } - var asyncKeyword: String? { get } - var `throws`: Bool { get } - var throwsOrRethrowsKeyword: String? { get } - var asSource: String { get } -} + return unique[resolvedIdentifier] + } -extension ClosureType: ClosureTypeAutoJSExport {} + private func actualTypeName(for typeName: TypeName, + containingType: Type? = nil) -> TypeName? { + let unique = typeMap + let typealiases = resolvedTypealiases -@objc protocol DictionaryTypeAutoJSExport: JSExport { - var name: String { get } - var valueTypeName: TypeName { get } - var valueType: Type? { get } - var keyTypeName: TypeName { get } - var keyType: Type? { get } - var asGeneric: GenericType { get } - var asSource: String { get } -} + var unwrapped = typeName.unwrappedTypeName + if let generic = typeName.generic { + unwrapped = generic.name + } -extension DictionaryType: DictionaryTypeAutoJSExport {} + guard let aliased = resolveGlobalName(for: unwrapped, containingType: containingType, unique: unique, modules: modules, typealiases: typealiases) else { + return nil + } -@objc protocol EnumAutoJSExport: JSExport { - var kind: String { get } - var cases: [EnumCase] { get } - var rawTypeName: TypeName? { get } - var hasRawType: Bool { get } - var rawType: Type? { get } - var based: [String: String] { get } - var hasAssociatedValues: Bool { get } - var module: String? { get } - var imports: [Import] { get } - var allImports: [Import] { get } - var accessLevel: String { get } - var name: String { get } - var isUnknownExtension: Bool { get } - var globalName: String { get } - var isGeneric: Bool { get } - var localName: String { get } - var variables: [Variable] { get } - var rawVariables: [Variable] { get } - var allVariables: [Variable] { get } - var methods: [Method] { get } - var rawMethods: [Method] { get } - var allMethods: [Method] { get } - var subscripts: [Subscript] { get } - var rawSubscripts: [Subscript] { get } - var allSubscripts: [Subscript] { get } - var initializers: [Method] { get } - var annotations: Annotations { get } - var documentation: Documentation { get } - var staticVariables: [Variable] { get } - var staticMethods: [Method] { get } - var classMethods: [Method] { get } - var instanceVariables: [Variable] { get } - var instanceMethods: [Method] { get } - var computedVariables: [Variable] { get } - var storedVariables: [Variable] { get } - var inheritedTypes: [String] { get } - var basedTypes: [String: Type] { get } - var inherits: [String: Type] { get } - var implements: [String: Type] { get } - var containedTypes: [Type] { get } - var containedType: [String: Type] { get } - var parentName: String? { get } - var parent: Type? { get } - var supertype: Type? { get } - var attributes: AttributeList { get } - var modifiers: [SourceryModifier] { get } - var fileName: String? { get } -} - -extension Enum: EnumAutoJSExport {} - -@objc protocol EnumCaseAutoJSExport: JSExport { - var name: String { get } - var rawValue: String? { get } - var associatedValues: [AssociatedValue] { get } - var annotations: Annotations { get } - var documentation: Documentation { get } - var indirect: Bool { get } - var hasAssociatedValue: Bool { get } -} - -extension EnumCase: EnumCaseAutoJSExport {} - - -@objc protocol GenericRequirementAutoJSExport: JSExport { - var leftType: AssociatedType { get } - var rightType: GenericTypeParameter { get } - var relationship: String { get } - var relationshipSyntax: String { get } -} + /// TODO: verify + let generic = typeName.generic.map { GenericType(name: $0.name, typeParameters: $0.typeParameters) } + generic?.name = aliased.name + let dictionary = typeName.dictionary.map { DictionaryType(name: $0.name, valueTypeName: $0.valueTypeName, valueType: $0.valueType, keyTypeName: $0.keyTypeName, keyType: $0.keyType) } + dictionary?.name = aliased.name + let array = typeName.array.map { ArrayType(name: $0.name, elementTypeName: $0.elementTypeName, elementType: $0.elementType) } + array?.name = aliased.name + let set = typeName.set.map { SetType(name: $0.name, elementTypeName: $0.elementTypeName, elementType: $0.elementType) } + set?.name = aliased.name -extension GenericRequirement: GenericRequirementAutoJSExport {} + return TypeName(name: aliased.name, + isOptional: typeName.isOptional, + isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, + tuple: aliased.typealias?.typeName.tuple ?? typeName.tuple, // TODO: verify + array: aliased.typealias?.typeName.array ?? array, + dictionary: aliased.typealias?.typeName.dictionary ?? dictionary, + closure: aliased.typealias?.typeName.closure ?? typeName.closure, + set: aliased.typealias?.typeName.set ?? set, + generic: aliased.typealias?.typeName.generic ?? generic + ) + } -@objc protocol GenericTypeAutoJSExport: JSExport { - var name: String { get } - var typeParameters: [GenericTypeParameter] { get } - var asSource: String { get } - var description: String { get } } -extension GenericType: GenericTypeAutoJSExport {} +"""), + .init(name: "PhantomProtocols.swift", content: +""" +// +// Created by Krzysztof Zablocki on 23/01/2017. +// Copyright (c) 2017 Pixle. All rights reserved. +// -@objc protocol GenericTypeParameterAutoJSExport: JSExport { - var typeName: TypeName { get } - var type: Type? { get } -} +import Foundation -extension GenericTypeParameter: GenericTypeParameterAutoJSExport {} +/// Phantom protocol for diffing +protocol AutoDiffable {} -@objc protocol ImportAutoJSExport: JSExport { - var kind: String? { get } - var path: String { get } - var description: String { get } - var moduleName: String { get } -} +/// Phantom protocol for equality +protocol AutoEquatable {} -extension Import: ImportAutoJSExport {} +/// Phantom protocol for equality +protocol AutoDescription {} -@objc protocol MethodAutoJSExport: JSExport { - var name: String { get } - var selectorName: String { get } - var shortName: String { get } - var callName: String { get } - var parameters: [MethodParameter] { get } - var returnTypeName: TypeName { get } - var actualReturnTypeName: TypeName { get } - var returnType: Type? { get } - var isOptionalReturnType: Bool { get } - var isImplicitlyUnwrappedOptionalReturnType: Bool { get } - var unwrappedReturnTypeName: String { get } - var isAsync: Bool { get } - var `throws`: Bool { get } - var `rethrows`: Bool { get } - var accessLevel: String { get } - var isStatic: Bool { get } - var isClass: Bool { get } - var isInitializer: Bool { get } - var isDeinitializer: Bool { get } - var isFailableInitializer: Bool { get } - var isConvenienceInitializer: Bool { get } - var isRequired: Bool { get } - var isFinal: Bool { get } - var isMutating: Bool { get } - var isGeneric: Bool { get } - var isOptional: Bool { get } - var isNonisolated: Bool { get } - var annotations: Annotations { get } - var documentation: Documentation { get } - var definedInTypeName: TypeName? { get } - var actualDefinedInTypeName: TypeName? { get } - var definedInType: Type? { get } - var attributes: AttributeList { get } - var modifiers: [SourceryModifier] { get } -} +/// Phantom protocol for NSCoding +protocol AutoCoding {} -extension Method: MethodAutoJSExport {} +protocol AutoJSExport {} -@objc protocol MethodParameterAutoJSExport: JSExport { - var argumentLabel: String? { get } - var name: String { get } - var typeName: TypeName { get } - var `inout`: Bool { get } - var isVariadic: Bool { get } - var type: Type? { get } - var typeAttributes: AttributeList { get } - var defaultValue: String? { get } - var annotations: Annotations { get } - var asSource: String { get } - var isOptional: Bool { get } - var isImplicitlyUnwrappedOptional: Bool { get } - var unwrappedTypeName: String { get } -} +/// Phantom protocol for NSCoding, Equatable and Diffable +protocol SourceryModelWithoutDescription: AutoDiffable, AutoEquatable, AutoCoding, AutoJSExport {} -extension MethodParameter: MethodParameterAutoJSExport {} +protocol SourceryModel: SourceryModelWithoutDescription, AutoDescription {} -@objc protocol ModifierAutoJSExport: JSExport { - var name: String { get } - var detail: String? { get } - var asSource: String { get } -} +"""), + .init(name: "Protocol.swift", content: +""" +// +// Protocol.swift +// Sourcery +// +// Created by Krzysztof Zablocki on 09/12/2016. +// Copyright © 2016 Pixle. All rights reserved. +// -extension Modifier: ModifierAutoJSExport {} +import Foundation -@objc protocol ProtocolAutoJSExport: JSExport { - var kind: String { get } - var associatedTypes: [String: AssociatedType] { get } - var genericRequirements: [GenericRequirement] { get } - var module: String? { get } - var imports: [Import] { get } - var allImports: [Import] { get } - var accessLevel: String { get } - var name: String { get } - var isUnknownExtension: Bool { get } - var globalName: String { get } - var isGeneric: Bool { get } - var localName: String { get } - var variables: [Variable] { get } - var rawVariables: [Variable] { get } - var allVariables: [Variable] { get } - var methods: [Method] { get } - var rawMethods: [Method] { get } - var allMethods: [Method] { get } - var subscripts: [Subscript] { get } - var rawSubscripts: [Subscript] { get } - var allSubscripts: [Subscript] { get } - var initializers: [Method] { get } - var annotations: Annotations { get } - var documentation: Documentation { get } - var staticVariables: [Variable] { get } - var staticMethods: [Method] { get } - var classMethods: [Method] { get } - var instanceVariables: [Variable] { get } - var instanceMethods: [Method] { get } - var computedVariables: [Variable] { get } - var storedVariables: [Variable] { get } - var inheritedTypes: [String] { get } - var based: [String: String] { get } - var basedTypes: [String: Type] { get } - var inherits: [String: Type] { get } - var implements: [String: Type] { get } - var containedTypes: [Type] { get } - var containedType: [String: Type] { get } - var parentName: String? { get } - var parent: Type? { get } - var supertype: Type? { get } - var attributes: AttributeList { get } - var modifiers: [SourceryModifier] { get } - var fileName: String? { get } -} +/// :nodoc: +public typealias SourceryProtocol = Protocol -extension Protocol: ProtocolAutoJSExport {} +/// Describes Swift protocol +#if canImport(ObjectiveC) +@objcMembers +#endif +public final class Protocol: Type { + /// Returns "protocol" + public override var kind: String { return "protocol" } + /// list of all declared associated types with their names as keys + public var associatedTypes: [String: AssociatedType] { + didSet { + isGeneric = !associatedTypes.isEmpty || !genericRequirements.isEmpty + } + } + // sourcery: skipCoding + /// list of generic requirements + public override var genericRequirements: [GenericRequirement] { + didSet { + isGeneric = !associatedTypes.isEmpty || !genericRequirements.isEmpty + } + } -@objc protocol StructAutoJSExport: JSExport { - var kind: String { get } - var module: String? { get } - var imports: [Import] { get } - var allImports: [Import] { get } - var accessLevel: String { get } - var name: String { get } - var isUnknownExtension: Bool { get } - var globalName: String { get } - var isGeneric: Bool { get } - var localName: String { get } - var variables: [Variable] { get } - var rawVariables: [Variable] { get } - var allVariables: [Variable] { get } - var methods: [Method] { get } - var rawMethods: [Method] { get } - var allMethods: [Method] { get } - var subscripts: [Subscript] { get } - var rawSubscripts: [Subscript] { get } - var allSubscripts: [Subscript] { get } - var initializers: [Method] { get } - var annotations: Annotations { get } - var documentation: Documentation { get } - var staticVariables: [Variable] { get } - var staticMethods: [Method] { get } - var classMethods: [Method] { get } - var instanceVariables: [Variable] { get } - var instanceMethods: [Method] { get } - var computedVariables: [Variable] { get } - var storedVariables: [Variable] { get } - var inheritedTypes: [String] { get } - var based: [String: String] { get } - var basedTypes: [String: Type] { get } - var inherits: [String: Type] { get } - var implements: [String: Type] { get } - var containedTypes: [Type] { get } - var containedType: [String: Type] { get } - var parentName: String? { get } - var parent: Type? { get } - var supertype: Type? { get } - var attributes: AttributeList { get } - var modifiers: [SourceryModifier] { get } - var fileName: String? { get } -} - -extension Struct: StructAutoJSExport {} + /// :nodoc: + public init(name: String = "", + parent: Type? = nil, + accessLevel: AccessLevel = .internal, + isExtension: Bool = false, + variables: [Variable] = [], + methods: [Method] = [], + subscripts: [Subscript] = [], + inheritedTypes: [String] = [], + containedTypes: [Type] = [], + typealiases: [Typealias] = [], + associatedTypes: [String: AssociatedType] = [:], + genericRequirements: [GenericRequirement] = [], + attributes: AttributeList = [:], + modifiers: [SourceryModifier] = [], + annotations: [String: NSObject] = [:], + documentation: [String] = [], + implements: [String: Type] = [:]) { + self.associatedTypes = associatedTypes + super.init( + name: name, + parent: parent, + accessLevel: accessLevel, + isExtension: isExtension, + variables: variables, + methods: methods, + subscripts: subscripts, + inheritedTypes: inheritedTypes, + containedTypes: containedTypes, + typealiases: typealiases, + genericRequirements: genericRequirements, + attributes: attributes, + modifiers: modifiers, + annotations: annotations, + documentation: documentation, + isGeneric: !associatedTypes.isEmpty || !genericRequirements.isEmpty, + implements: implements + ) + } -@objc protocol SubscriptAutoJSExport: JSExport { - var parameters: [MethodParameter] { get } - var returnTypeName: TypeName { get } - var actualReturnTypeName: TypeName { get } - var returnType: Type? { get } - var isOptionalReturnType: Bool { get } - var isImplicitlyUnwrappedOptionalReturnType: Bool { get } - var unwrappedReturnTypeName: String { get } - var isFinal: Bool { get } - var readAccess: String { get } - var writeAccess: String { get } - var isMutable: Bool { get } - var annotations: Annotations { get } - var documentation: Documentation { get } - var definedInTypeName: TypeName? { get } - var actualDefinedInTypeName: TypeName? { get } - var definedInType: Type? { get } - var attributes: AttributeList { get } - var modifiers: [SourceryModifier] { get } -} + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = super.description + string.append(", ") + string.append("kind = \\(String(describing: self.kind)), ") + string.append("associatedTypes = \\(String(describing: self.associatedTypes)), ") + return string + } -extension Subscript: SubscriptAutoJSExport {} + override public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? Protocol else { + results.append("Incorrect type ") + return results + } + results.append(contentsOf: DiffableResult(identifier: "associatedTypes").trackDifference(actual: self.associatedTypes, expected: castObject.associatedTypes)) + results.append(contentsOf: super.diffAgainst(castObject)) + return results + } -@objc protocol TemplateContextAutoJSExport: JSExport { - var functions: [SourceryMethod] { get } - var types: Types { get } - var argument: [String: NSObject] { get } - var type: [String: Type] { get } - var stencilContext: [String: Any] { get } - var jsContext: [String: Any] { get } -} + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.associatedTypes) + hasher.combine(super.hash) + return hasher.finalize() + } -extension TemplateContext: TemplateContextAutoJSExport {} + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? Protocol else { return false } + if self.associatedTypes != rhs.associatedTypes { return false } + return super.isEqual(rhs) + } -@objc protocol TupleElementAutoJSExport: JSExport { - var name: String? { get } - var typeName: TypeName { get } - var type: Type? { get } - var asSource: String { get } - var isOptional: Bool { get } - var isImplicitlyUnwrappedOptional: Bool { get } - var unwrappedTypeName: String { get } -} +// sourcery:inline:Protocol.AutoCoding -extension TupleElement: TupleElementAutoJSExport {} + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let associatedTypes: [String: AssociatedType] = aDecoder.decode(forKey: "associatedTypes") else { + withVaList(["associatedTypes"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.associatedTypes = associatedTypes + super.init(coder: aDecoder) + } -@objc protocol TupleTypeAutoJSExport: JSExport { - var name: String { get } - var elements: [TupleElement] { get } + /// :nodoc: + override public func encode(with aCoder: NSCoder) { + super.encode(with: aCoder) + aCoder.encode(self.associatedTypes, forKey: "associatedTypes") + } +// sourcery:end } -extension TupleType: TupleTypeAutoJSExport {} +"""), + .init(name: "ProtocolComposition.swift", content: +""" +// Created by eric_horacek on 2/12/20. +// Copyright © 2020 Airbnb Inc. All rights reserved. -@objc protocol TypeAutoJSExport: JSExport { - var module: String? { get } - var imports: [Import] { get } - var allImports: [Import] { get } - var kind: String { get } - var accessLevel: String { get } - var name: String { get } - var isUnknownExtension: Bool { get } - var globalName: String { get } - var isGeneric: Bool { get } - var localName: String { get } - var variables: [Variable] { get } - var rawVariables: [Variable] { get } - var allVariables: [Variable] { get } - var methods: [Method] { get } - var rawMethods: [Method] { get } - var allMethods: [Method] { get } - var subscripts: [Subscript] { get } - var rawSubscripts: [Subscript] { get } - var allSubscripts: [Subscript] { get } - var initializers: [Method] { get } - var annotations: Annotations { get } - var documentation: Documentation { get } - var staticVariables: [Variable] { get } - var staticMethods: [Method] { get } - var classMethods: [Method] { get } - var instanceVariables: [Variable] { get } - var instanceMethods: [Method] { get } - var computedVariables: [Variable] { get } - var storedVariables: [Variable] { get } - var inheritedTypes: [String] { get } - var based: [String: String] { get } - var basedTypes: [String: Type] { get } - var inherits: [String: Type] { get } - var implements: [String: Type] { get } - var containedTypes: [Type] { get } - var containedType: [String: Type] { get } - var parentName: String? { get } - var parent: Type? { get } - var supertype: Type? { get } - var attributes: AttributeList { get } - var modifiers: [SourceryModifier] { get } - var fileName: String? { get } -} +import Foundation -extension Type: TypeAutoJSExport {} +/// Describes a Swift [protocol composition](https://docs.swift.org/swift-book/ReferenceManual/Types.html#ID454). +#if canImport(ObjectiveC) +@objcMembers +#endif +public final class ProtocolComposition: Type { -@objc protocol TypeNameAutoJSExport: JSExport { - var name: String { get } - var generic: GenericType? { get } - var isGeneric: Bool { get } - var isProtocolComposition: Bool { get } - var actualTypeName: TypeName? { get } - var attributes: AttributeList { get } - var modifiers: [SourceryModifier] { get } - var isOptional: Bool { get } - var isImplicitlyUnwrappedOptional: Bool { get } - var unwrappedTypeName: String { get } - var isVoid: Bool { get } - var isTuple: Bool { get } - var tuple: TupleType? { get } - var isArray: Bool { get } - var array: ArrayType? { get } - var isDictionary: Bool { get } - var dictionary: DictionaryType? { get } - var isClosure: Bool { get } - var closure: ClosureType? { get } - var set: SetType? { get } - var isSet: Bool { get } - var asSource: String { get } - var description: String { get } - var debugDescription: String { get } -} + /// Returns "protocolComposition" + public override var kind: String { return "protocolComposition" } -extension TypeName: TypeNameAutoJSExport {} + /// The names of the types composed to form this composition + public let composedTypeNames: [TypeName] + // sourcery: skipEquality, skipDescription + /// The types composed to form this composition, if known + public var composedTypes: [Type]? - -@objc protocol TypesCollectionAutoJSExport: JSExport { -} - -extension TypesCollection: TypesCollectionAutoJSExport {} - -@objc protocol VariableAutoJSExport: JSExport { - var name: String { get } - var typeName: TypeName { get } - var type: Type? { get } - var isComputed: Bool { get } - var isAsync: Bool { get } - var `throws`: Bool { get } - var isStatic: Bool { get } - var readAccess: String { get } - var writeAccess: String { get } - var isMutable: Bool { get } - var defaultValue: String? { get } - var annotations: Annotations { get } - var documentation: Documentation { get } - var attributes: AttributeList { get } - var modifiers: [SourceryModifier] { get } - var isFinal: Bool { get } - var isLazy: Bool { get } - var definedInTypeName: TypeName? { get } - var actualDefinedInTypeName: TypeName? { get } - var definedInType: Type? { get } - var isOptional: Bool { get } - var isImplicitlyUnwrappedOptional: Bool { get } - var unwrappedTypeName: String { get } -} - -extension Variable: VariableAutoJSExport {} - - -"""), - .init(name: "Log.swift", content: -""" -import Darwin -import Foundation - -/// :nodoc: -public enum Log { - - public enum Level: Int { - case errors - case warnings - case info - case verbose - } - - public static var level: Level = .warnings - public static var logBenchmarks: Bool = false - public static var logAST: Bool = false - - public static var stackMessages: Bool = false - public private(set) static var messagesStack = [String]() - - public static func error(_ message: Any) { - log(level: .errors, "error: \\(message)") - // to return error when running swift templates which is done in a different process - if ProcessInfo.processInfo.processName != "Sourcery" { - fputs("\\(message)", stderr) - } + /// :nodoc: + public init(name: String = "", + parent: Type? = nil, + accessLevel: AccessLevel = .internal, + isExtension: Bool = false, + variables: [Variable] = [], + methods: [Method] = [], + subscripts: [Subscript] = [], + inheritedTypes: [String] = [], + containedTypes: [Type] = [], + typealiases: [Typealias] = [], + attributes: AttributeList = [:], + annotations: [String: NSObject] = [:], + isGeneric: Bool = false, + composedTypeNames: [TypeName] = [], + composedTypes: [Type]? = nil, + implements: [String: Type] = [:]) { + self.composedTypeNames = composedTypeNames + self.composedTypes = composedTypes + super.init( + name: name, + parent: parent, + accessLevel: accessLevel, + isExtension: isExtension, + variables: variables, + methods: methods, + subscripts: subscripts, + inheritedTypes: inheritedTypes, + containedTypes: containedTypes, + typealiases: typealiases, + annotations: annotations, + isGeneric: isGeneric, + implements: implements + ) } - public static func warning(_ message: Any) { - log(level: .warnings, "warning: \\(message)") + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = super.description + string += ", " + string += "kind = \\(String(describing: self.kind)), " + string += "composedTypeNames = \\(String(describing: self.composedTypeNames))" + return string } - public static func astWarning(_ message: Any) { - guard logAST else { return } - log(level: .warnings, "ast warning: \\(message)") + override public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? ProtocolComposition else { + results.append("Incorrect type ") + return results + } + results.append(contentsOf: DiffableResult(identifier: "composedTypeNames").trackDifference(actual: self.composedTypeNames, expected: castObject.composedTypeNames)) + results.append(contentsOf: super.diffAgainst(castObject)) + return results } - public static func astError(_ message: Any) { - guard logAST else { return } - log(level: .errors, "ast error: \\(message)") + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.composedTypeNames) + hasher.combine(super.hash) + return hasher.finalize() } - public static func verbose(_ message: Any) { - log(level: .verbose, message) + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? ProtocolComposition else { return false } + if self.composedTypeNames != rhs.composedTypeNames { return false } + return super.isEqual(rhs) } - public static func info(_ message: Any) { - log(level: .info, message) - } +// sourcery:inline:ProtocolComposition.AutoCoding - public static func benchmark(_ message: Any) { - guard logBenchmarks else { return } - if stackMessages { - messagesStack.append("\\(message)") - } else { - print(message) + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let composedTypeNames: [TypeName] = aDecoder.decode(forKey: "composedTypeNames") else { + withVaList(["composedTypeNames"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.composedTypeNames = composedTypeNames + self.composedTypes = aDecoder.decode(forKey: "composedTypes") + super.init(coder: aDecoder) } - } - private static func log(level logLevel: Level, _ message: Any) { - guard logLevel.rawValue <= Log.level.rawValue else { return } - if stackMessages { - messagesStack.append("\\(message)") - } else { - print(message) + /// :nodoc: + override public func encode(with aCoder: NSCoder) { + super.encode(with: aCoder) + aCoder.encode(self.composedTypeNames, forKey: "composedTypeNames") + aCoder.encode(self.composedTypes, forKey: "composedTypes") } - } +// sourcery:end - public static func output(_ message: String) { - print(message) - } } -extension String: Error {} - """), - .init(name: "MethodParameter.swift", content: + .init(name: "Set.swift", content: """ import Foundation -/// Describes method parameter +/// Describes set type +#if canImport(ObjectiveC) @objcMembers -public class MethodParameter: NSObject, SourceryModel, Typed, Annotated, Diffable { - /// Parameter external name - public var argumentLabel: String? - - // Note: although method parameter can have no name, this property is not optional, - // this is so to maintain compatibility with existing templates. - /// Parameter internal name - public let name: String - - /// Parameter type name - public let typeName: TypeName - - /// Parameter flag whether it's inout or not - public let `inout`: Bool +#endif +public final class SetType: NSObject, SourceryModel, Diffable { + /// Type name used in declaration + public var name: String - /// Is this variadic parameter? - public let isVariadic: Bool + /// Array element type name + public var elementTypeName: TypeName // sourcery: skipEquality, skipDescription - /// Parameter type, if known - public var type: Type? - - /// Parameter type attributes, i.e. `@escaping` - public var typeAttributes: AttributeList { - return typeName.attributes - } - - /// Method parameter default value expression - public var defaultValue: String? - - /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 - public var annotations: Annotations = [:] + /// Array element type, if known + public var elementType: Type? /// :nodoc: - public init(argumentLabel: String?, name: String = "", typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false, isVariadic: Bool = false) { - self.typeName = typeName - self.argumentLabel = argumentLabel + public init(name: String, elementTypeName: TypeName, elementType: Type? = nil) { self.name = name - self.type = type - self.defaultValue = defaultValue - self.annotations = annotations - self.`inout` = isInout - self.isVariadic = isVariadic + self.elementTypeName = elementTypeName + self.elementType = elementType } - /// :nodoc: - public init(name: String = "", typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false, isVariadic: Bool = false) { - self.typeName = typeName - self.argumentLabel = name - self.name = name - self.type = type - self.defaultValue = defaultValue - self.annotations = annotations - self.`inout` = isInout - self.isVariadic = isVariadic + /// Returns array as generic type + public var asGeneric: GenericType { + GenericType(name: "Set", typeParameters: [ + .init(typeName: elementTypeName) + ]) } public var asSource: String { - let typeSuffix = ": \\(`inout` ? "inout " : "")\\(typeName.asSource)\\(defaultValue.map { " = \\($0)" } ?? "")" + (isVariadic ? "..." : "") - guard argumentLabel != name else { - return name + typeSuffix - } - - let labels = [argumentLabel ?? "_", name.nilIfEmpty] - .compactMap { $0 } - .joined(separator: " ") - - return (labels.nilIfEmpty ?? "_") + typeSuffix + "[\\(elementTypeName.asSource)]" } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " - string += "argumentLabel = \\(String(describing: self.argumentLabel)), " - string += "name = \\(String(describing: self.name)), " - string += "typeName = \\(String(describing: self.typeName)), " - string += "`inout` = \\(String(describing: self.`inout`)), " - string += "isVariadic = \\(String(describing: self.isVariadic)), " - string += "typeAttributes = \\(String(describing: self.typeAttributes)), " - string += "defaultValue = \\(String(describing: self.defaultValue)), " - string += "annotations = \\(String(describing: self.annotations)), " - string += "asSource = \\(String(describing: self.asSource))" + string.append("name = \\(String(describing: self.name)), ") + string.append("elementTypeName = \\(String(describing: self.elementTypeName)), ") + string.append("asGeneric = \\(String(describing: self.asGeneric)), ") + string.append("asSource = \\(String(describing: self.asSource))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() - guard let castObject = object as? MethodParameter else { - results.append("Incorrect type ") + guard let castObject = object as? SetType else { + results.append("Incorrect type ") return results } - results.append(contentsOf: DiffableResult(identifier: "argumentLabel").trackDifference(actual: self.argumentLabel, expected: castObject.argumentLabel)) results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) - results.append(contentsOf: DiffableResult(identifier: "`inout`").trackDifference(actual: self.`inout`, expected: castObject.`inout`)) - results.append(contentsOf: DiffableResult(identifier: "isVariadic").trackDifference(actual: self.isVariadic, expected: castObject.isVariadic)) - results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) - results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) + results.append(contentsOf: DiffableResult(identifier: "elementTypeName").trackDifference(actual: self.elementTypeName, expected: castObject.elementTypeName)) return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() - hasher.combine(self.argumentLabel) hasher.combine(self.name) - hasher.combine(self.typeName) - hasher.combine(self.`inout`) - hasher.combine(self.isVariadic) - hasher.combine(self.defaultValue) - hasher.combine(self.annotations) + hasher.combine(self.elementTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? MethodParameter else { return false } - if self.argumentLabel != rhs.argumentLabel { return false } + guard let rhs = object as? SetType else { return false } if self.name != rhs.name { return false } - if self.typeName != rhs.typeName { return false } - if self.`inout` != rhs.`inout` { return false } - if self.isVariadic != rhs.isVariadic { return false } - if self.defaultValue != rhs.defaultValue { return false } - if self.annotations != rhs.annotations { return false } + if self.elementTypeName != rhs.elementTypeName { return false } return true } -// sourcery:inline:MethodParameter.AutoCoding +// sourcery:inline:SetType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { - self.argumentLabel = aDecoder.decode(forKey: "argumentLabel") - guard let name: String = aDecoder.decode(forKey: "name") else { + guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name - guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { - withVaList(["typeName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.typeName = typeName - self.`inout` = aDecoder.decode(forKey: "`inout`") - self.isVariadic = aDecoder.decode(forKey: "isVariadic") - self.type = aDecoder.decode(forKey: "type") - self.defaultValue = aDecoder.decode(forKey: "defaultValue") - guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { - withVaList(["annotations"]) { arguments in + guard let elementTypeName: TypeName = aDecoder.decode(forKey: "elementTypeName") else { + withVaList(["elementTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.annotations = annotations + }; self.elementTypeName = elementTypeName + self.elementType = aDecoder.decode(forKey: "elementType") } /// :nodoc: public func encode(with aCoder: NSCoder) { - aCoder.encode(self.argumentLabel, forKey: "argumentLabel") aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.typeName, forKey: "typeName") - aCoder.encode(self.`inout`, forKey: "`inout`") - aCoder.encode(self.isVariadic, forKey: "isVariadic") - aCoder.encode(self.type, forKey: "type") - aCoder.encode(self.defaultValue, forKey: "defaultValue") - aCoder.encode(self.annotations, forKey: "annotations") + aCoder.encode(self.elementTypeName, forKey: "elementTypeName") + aCoder.encode(self.elementType, forKey: "elementType") } // sourcery:end } -extension Array where Element == MethodParameter { - public var asSource: String { - "(\\(map { $0.asSource }.joined(separator: ", ")))" - } -} - """), - .init(name: "ClosureParameter.swift", content: + .init(name: "Struct.swift", content: """ +// +// Struct.swift +// Sourcery +// +// Created by Krzysztof Zablocki on 13/09/2016. +// Copyright © 2016 Pixle. All rights reserved. +// + import Foundation -// sourcery: skipDiffing +// sourcery: skipDescription +/// Describes Swift struct +#if canImport(ObjectiveC) @objcMembers -public final class ClosureParameter: NSObject, SourceryModel, Typed, Annotated { - /// Parameter external name - public var argumentLabel: String? - - /// Parameter internal name - public let name: String? - - /// Parameter type name - public let typeName: TypeName - - /// Parameter flag whether it's inout or not - public let `inout`: Bool +#endif +public final class Struct: Type { - // sourcery: skipEquality, skipDescription - /// Parameter type, if known - public var type: Type? + /// Returns "struct" + public override var kind: String { return "struct" } - /// Parameter type attributes, i.e. `@escaping` - public var typeAttributes: AttributeList { - return typeName.attributes + /// :nodoc: + public override init(name: String = "", + parent: Type? = nil, + accessLevel: AccessLevel = .internal, + isExtension: Bool = false, + variables: [Variable] = [], + methods: [Method] = [], + subscripts: [Subscript] = [], + inheritedTypes: [String] = [], + containedTypes: [Type] = [], + typealiases: [Typealias] = [], + genericRequirements: [GenericRequirement] = [], + attributes: AttributeList = [:], + modifiers: [SourceryModifier] = [], + annotations: [String: NSObject] = [:], + documentation: [String] = [], + isGeneric: Bool = false, + implements: [String: Type] = [:]) { + super.init( + name: name, + parent: parent, + accessLevel: accessLevel, + isExtension: isExtension, + variables: variables, + methods: methods, + subscripts: subscripts, + inheritedTypes: inheritedTypes, + containedTypes: containedTypes, + typealiases: typealiases, + genericRequirements: genericRequirements, + attributes: attributes, + modifiers: modifiers, + annotations: annotations, + documentation: documentation, + isGeneric: isGeneric, + implements: implements + ) } - /// Method parameter default value expression - public var defaultValue: String? - - /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 - public var annotations: Annotations = [:] - /// :nodoc: - public init(argumentLabel: String? = nil, name: String? = nil, typeName: TypeName, type: Type? = nil, - defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false) { - self.typeName = typeName - self.argumentLabel = argumentLabel - self.name = name - self.type = type - self.defaultValue = defaultValue - self.annotations = annotations - self.`inout` = isInout + // sourcery: skipJSExport + override public var description: String { + var string = super.description + string += ", " + string += "kind = \\(String(describing: self.kind))" + return string } - public var asSource: String { - let typeInfo = "\\(`inout` ? "inout " : "")\\(typeName.asSource)" - if argumentLabel?.nilIfNotValidParameterName == nil, name?.nilIfNotValidParameterName == nil { - return typeInfo - } - - let typeSuffix = ": \\(typeInfo)" - guard argumentLabel != name else { - return name ?? "" + typeSuffix + override public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? Struct else { + results.append("Incorrect type ") + return results } - - let labels = [argumentLabel ?? "_", name?.nilIfEmpty] - .compactMap { $0 } - .joined(separator: " ") - - return (labels.nilIfEmpty ?? "_") + typeSuffix + results.append(contentsOf: super.diffAgainst(castObject)) + return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() - hasher.combine(self.argumentLabel) - hasher.combine(self.name) - hasher.combine(self.typeName) - hasher.combine(self.`inout`) - hasher.combine(self.defaultValue) - hasher.combine(self.annotations) + hasher.combine(super.hash) return hasher.finalize() } - /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "argumentLabel = \\(String(describing: self.argumentLabel)), " - string += "name = \\(String(describing: self.name)), " - string += "typeName = \\(String(describing: self.typeName)), " - string += "`inout` = \\(String(describing: self.`inout`)), " - string += "typeAttributes = \\(String(describing: self.typeAttributes)), " - string += "defaultValue = \\(String(describing: self.defaultValue)), " - string += "annotations = \\(String(describing: self.annotations)), " - string += "asSource = \\(String(describing: self.asSource))" - return string - } - /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? ClosureParameter else { return false } - if self.argumentLabel != rhs.argumentLabel { return false } - if self.name != rhs.name { return false } - if self.typeName != rhs.typeName { return false } - if self.`inout` != rhs.`inout` { return false } - if self.defaultValue != rhs.defaultValue { return false } - if self.annotations != rhs.annotations { return false } - return true + guard let rhs = object as? Struct else { return false } + return super.isEqual(rhs) } - // sourcery:inline:ClosureParameter.AutoCoding - - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - self.argumentLabel = aDecoder.decode(forKey: "argumentLabel") - self.name = aDecoder.decode(forKey: "name") - guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { - withVaList(["typeName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.typeName = typeName - self.`inout` = aDecoder.decode(forKey: "`inout`") - self.type = aDecoder.decode(forKey: "type") - self.defaultValue = aDecoder.decode(forKey: "defaultValue") - guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { - withVaList(["annotations"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.annotations = annotations - } +// sourcery:inline:Struct.AutoCoding - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.argumentLabel, forKey: "argumentLabel") - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.typeName, forKey: "typeName") - aCoder.encode(self.`inout`, forKey: "`inout`") - aCoder.encode(self.type, forKey: "type") - aCoder.encode(self.defaultValue, forKey: "defaultValue") - aCoder.encode(self.annotations, forKey: "annotations") - } + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } - // sourcery:end + /// :nodoc: + override public func encode(with aCoder: NSCoder) { + super.encode(with: aCoder) + } +// sourcery:end } -extension Array where Element == ClosureParameter { - public var asSource: String { - "(\\(map { $0.asSource }.joined(separator: ", ")))" - } -} """), - .init(name: "Method.swift", content: + .init(name: "TemplateContext.swift", content: """ +// +// Created by Krzysztof Zablocki on 31/12/2016. +// Copyright (c) 2016 Pixle. All rights reserved. +// + import Foundation /// :nodoc: -public typealias SourceryMethod = Method - -/// Describes method -@objc(SwiftMethod) @objcMembers -public final class Method: NSObject, SourceryModel, Annotated, Documented, Definition, Diffable { - - /// Full method name, including generic constraints, i.e. `foo(bar: T)` - public let name: String - - /// Method name including arguments names, i.e. `foo(bar:)` - public var selectorName: String +// sourcery: skipCoding +#if canImport(ObjectiveC) +@objcMembers +#endif +public final class TemplateContext: NSObject, SourceryModel, NSCoding, Diffable { + // sourcery: skipJSExport + public let parserResult: FileParserResult? + public let functions: [SourceryMethod] + public let types: Types + public let argument: [String: NSObject] - // sourcery: skipEquality, skipDescription - /// Method name without arguments names and parenthesis, i.e. `foo` - public var shortName: String { - return name.range(of: "(").map({ String(name[..<$0.lowerBound]) }) ?? name + // sourcery: skipDescription + public var type: [String: Type] { + return types.typesByName } - // sourcery: skipEquality, skipDescription - /// Method name without arguments names, parenthesis and generic types, i.e. `foo` (can be used to generate code for method call) - public var callName: String { - return shortName.range(of: "<").map({ String(shortName[..<$0.lowerBound]) }) ?? shortName + public init(parserResult: FileParserResult?, types: Types, functions: [SourceryMethod], arguments: [String: NSObject]) { + self.parserResult = parserResult + self.types = types + self.functions = functions + self.argument = arguments } - /// Method parameters - public var parameters: [MethodParameter] - - /// Return value type name used in declaration, including generic constraints, i.e. `where T: Equatable` - public var returnTypeName: TypeName + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let parserResult: FileParserResult = aDecoder.decode(forKey: "parserResult") else { + withVaList(["parserResult"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found. FileParserResults are required for template context that needs persisting.", arguments: arguments) + } + fatalError() + } + guard let argument: [String: NSObject] = aDecoder.decode(forKey: "argument") else { + withVaList(["argument"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + } - // sourcery: skipEquality, skipDescription - /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` - public var actualReturnTypeName: TypeName { - return returnTypeName.actualTypeName ?? returnTypeName - } + // if we want to support multiple cycles of encode / decode we need deep copy because composer changes reference types + let fileParserResultCopy: FileParserResult? = nil +// fileParserResultCopy = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(NSKeyedArchiver.archivedData(withRootObject: parserResult)) as? FileParserResult - // sourcery: skipEquality, skipDescription - /// Actual return value type, if known - public var returnType: Type? + let composed = Composer.uniqueTypesAndFunctions(parserResult) + self.types = .init(types: composed.types, typealiases: composed.typealiases) + self.functions = composed.functions - // sourcery: skipEquality, skipDescription - /// Whether return value type is optional - public var isOptionalReturnType: Bool { - return returnTypeName.isOptional || isFailableInitializer + self.parserResult = fileParserResultCopy + self.argument = argument } - // sourcery: skipEquality, skipDescription - /// Whether return value type is implicitly unwrapped optional - public var isImplicitlyUnwrappedOptionalReturnType: Bool { - return returnTypeName.isImplicitlyUnwrappedOptional + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.parserResult, forKey: "parserResult") + aCoder.encode(self.argument, forKey: "argument") } - // sourcery: skipEquality, skipDescription - /// Return value type name without attributes and optional type information - public var unwrappedReturnTypeName: String { - return returnTypeName.unwrappedTypeName + public var stencilContext: [String: Any] { + return [ + "types": types, + "functions": functions, + "type": types.typesByName, + "argument": argument + ] } - /// Whether method is async method - public let isAsync: Bool - - /// Whether method throws - public let `throws`: Bool - - /// Whether method rethrows - public let `rethrows`: Bool - - /// Method access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` - public let accessLevel: String - - /// Whether method is a static method - public let isStatic: Bool - - /// Whether method is a class method - public let isClass: Bool - - // sourcery: skipEquality, skipDescription - /// Whether method is an initializer - public var isInitializer: Bool { - return selectorName.hasPrefix("init(") || selectorName == "init" + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("parserResult = \\(String(describing: self.parserResult)), ") + string.append("functions = \\(String(describing: self.functions)), ") + string.append("types = \\(String(describing: self.types)), ") + string.append("argument = \\(String(describing: self.argument)), ") + string.append("stencilContext = \\(String(describing: self.stencilContext))") + return string } - // sourcery: skipEquality, skipDescription - /// Whether method is an deinitializer - public var isDeinitializer: Bool { - return selectorName == "deinit" + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? TemplateContext else { + results.append("Incorrect type ") + return results + } + results.append(contentsOf: DiffableResult(identifier: "parserResult").trackDifference(actual: self.parserResult, expected: castObject.parserResult)) + results.append(contentsOf: DiffableResult(identifier: "functions").trackDifference(actual: self.functions, expected: castObject.functions)) + results.append(contentsOf: DiffableResult(identifier: "types").trackDifference(actual: self.types, expected: castObject.types)) + results.append(contentsOf: DiffableResult(identifier: "argument").trackDifference(actual: self.argument, expected: castObject.argument)) + return results } - /// Whether method is a failable initializer - public let isFailableInitializer: Bool - - // sourcery: skipEquality, skipDescription - /// Whether method is a convenience initializer - public var isConvenienceInitializer: Bool { - modifiers.contains { $0.name == Attribute.Identifier.convenience.rawValue } + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.parserResult) + hasher.combine(self.functions) + hasher.combine(self.types) + hasher.combine(self.argument) + return hasher.finalize() } - // sourcery: skipEquality, skipDescription - /// Whether method is required - public var isRequired: Bool { - modifiers.contains { $0.name == Attribute.Identifier.required.rawValue } + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? TemplateContext else { return false } + if self.parserResult != rhs.parserResult { return false } + if self.functions != rhs.functions { return false } + if self.types != rhs.types { return false } + if self.argument != rhs.argument { return false } + return true } - // sourcery: skipEquality, skipDescription - /// Whether method is final - public var isFinal: Bool { - modifiers.contains { $0.name == Attribute.Identifier.final.rawValue } + // sourcery: skipDescription, skipEquality + public var jsContext: [String: Any] { + return [ + "types": [ + "all": types.all, + "protocols": types.protocols, + "classes": types.classes, + "structs": types.structs, + "enums": types.enums, + "extensions": types.extensions, + "based": types.based, + "inheriting": types.inheriting, + "implementing": types.implementing, + "protocolCompositions": types.protocolCompositions + ] as [String : Any], + "functions": functions, + "type": types.typesByName, + "argument": argument + ] } - // sourcery: skipEquality, skipDescription - /// Whether method is mutating - public var isMutating: Bool { - modifiers.contains { $0.name == Attribute.Identifier.mutating.rawValue } - } +} - // sourcery: skipEquality, skipDescription - /// Whether method is generic - public var isGeneric: Bool { - shortName.hasSuffix(">") +extension ProcessInfo { + /// :nodoc: + public var context: TemplateContext! { + return NSKeyedUnarchiver.unarchiveObject(withFile: arguments[1]) as? TemplateContext } +} - // sourcery: skipEquality, skipDescription - /// Whether method is optional (in an Objective-C protocol) - public var isOptional: Bool { - modifiers.contains { $0.name == Attribute.Identifier.optional.rawValue } - } +"""), + .init(name: "Typealias.swift", content: +""" +import Foundation - // sourcery: skipEquality, skipDescription - /// Whether method is nonisolated (this modifier only applies to actor methods) - public var isNonisolated: Bool { - modifiers.contains { $0.name == Attribute.Identifier.nonisolated.rawValue } - } +/// :nodoc: +#if canImport(ObjectiveC) +@objcMembers +#endif +public final class Typealias: NSObject, Typed, SourceryModel, Diffable { + // New typealias name + public let aliasName: String + + // Target name + public let typeName: TypeName // sourcery: skipEquality, skipDescription - /// Whether method is dynamic - public var isDynamic: Bool { - modifiers.contains { $0.name == Attribute.Identifier.dynamic.rawValue } - } + public var type: Type? - /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 - public let annotations: Annotations + /// module in which this typealias was declared + public var module: String? - public let documentation: Documentation + /// typealias annotations + public var annotations: Annotations = [:] - /// Reference to type name where the method is defined, - /// nil if defined outside of any `enum`, `struct`, `class` etc - public let definedInTypeName: TypeName? + /// typealias documentation + public var documentation: Documentation = [] // sourcery: skipEquality, skipDescription - /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` - public var actualDefinedInTypeName: TypeName? { - return definedInTypeName?.actualTypeName ?? definedInTypeName + public var parent: Type? { + didSet { + parentName = parent?.name + } } - // sourcery: skipEquality, skipDescription - /// Reference to actual type where the object is defined, - /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown - public var definedInType: Type? - - /// Method attributes, i.e. `@discardableResult` - public let attributes: AttributeList + /// Type access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` + public let accessLevel: String - /// Method modifiers, i.e. `private` - public let modifiers: [SourceryModifier] + var parentName: String? - // Underlying parser data, never to be used by anything else - // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport - /// :nodoc: - public var __parserData: Any? - - /// list of generic requirements - public var genericRequirements: [GenericRequirement] + public var name: String { + if let parentName = parent?.name { + return "\\(module != nil ? "\\(module!)." : "")\\(parentName).\\(aliasName)" + } else { + return "\\(module != nil ? "\\(module!)." : "")\\(aliasName)" + } + } - /// :nodoc: - public init(name: String, - selectorName: String? = nil, - parameters: [MethodParameter] = [], - returnTypeName: TypeName = TypeName(name: "Void"), - isAsync: Bool = false, - throws: Bool = false, - rethrows: Bool = false, - accessLevel: AccessLevel = .internal, - isStatic: Bool = false, - isClass: Bool = false, - isFailableInitializer: Bool = false, - attributes: AttributeList = [:], - modifiers: [SourceryModifier] = [], - annotations: [String: NSObject] = [:], - documentation: [String] = [], - definedInTypeName: TypeName? = nil, - genericRequirements: [GenericRequirement] = []) { - self.name = name - self.selectorName = selectorName ?? name - self.parameters = parameters - self.returnTypeName = returnTypeName - self.isAsync = isAsync - self.throws = `throws` - self.rethrows = `rethrows` + public init(aliasName: String = "", typeName: TypeName, accessLevel: AccessLevel = .internal, parent: Type? = nil, module: String? = nil, annotations: [String: NSObject] = [:], documentation: [String] = []) { + self.aliasName = aliasName + self.typeName = typeName self.accessLevel = accessLevel.rawValue - self.isStatic = isStatic - self.isClass = isClass - self.isFailableInitializer = isFailableInitializer - self.attributes = attributes - self.modifiers = modifiers + self.parent = parent + self.parentName = parent?.name + self.module = module self.annotations = annotations self.documentation = documentation - self.definedInTypeName = definedInTypeName - self.genericRequirements = genericRequirements } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " - string += "name = \\(String(describing: self.name)), " - string += "selectorName = \\(String(describing: self.selectorName)), " - string += "parameters = \\(String(describing: self.parameters)), " - string += "returnTypeName = \\(String(describing: self.returnTypeName)), " - string += "isAsync = \\(String(describing: self.isAsync)), " - string += "`throws` = \\(String(describing: self.`throws`)), " - string += "`rethrows` = \\(String(describing: self.`rethrows`)), " - string += "accessLevel = \\(String(describing: self.accessLevel)), " - string += "isStatic = \\(String(describing: self.isStatic)), " - string += "isClass = \\(String(describing: self.isClass)), " - string += "isFailableInitializer = \\(String(describing: self.isFailableInitializer)), " - string += "annotations = \\(String(describing: self.annotations)), " - string += "documentation = \\(String(describing: self.documentation)), " - string += "definedInTypeName = \\(String(describing: self.definedInTypeName)), " - string += "attributes = \\(String(describing: self.attributes)), " - string += "modifiers = \\(String(describing: self.modifiers)), " - string += "genericRequirements = \\(String(describing: self.genericRequirements))" + string.append("aliasName = \\(String(describing: self.aliasName)), ") + string.append("typeName = \\(String(describing: self.typeName)), ") + string.append("module = \\(String(describing: self.module)), ") + string.append("accessLevel = \\(String(describing: self.accessLevel)), ") + string.append("parentName = \\(String(describing: self.parentName)), ") + string.append("name = \\(String(describing: self.name)), ") + string.append("annotations = \\(String(describing: self.annotations)), ") + string.append("documentation = \\(String(describing: self.documentation)), ") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() - guard let castObject = object as? Method else { - results.append("Incorrect type ") + guard let castObject = object as? Typealias else { + results.append("Incorrect type ") return results } - results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "selectorName").trackDifference(actual: self.selectorName, expected: castObject.selectorName)) - results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) - results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) - results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) - results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) - results.append(contentsOf: DiffableResult(identifier: "`rethrows`").trackDifference(actual: self.`rethrows`, expected: castObject.`rethrows`)) + results.append(contentsOf: DiffableResult(identifier: "aliasName").trackDifference(actual: self.aliasName, expected: castObject.aliasName)) + results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) + results.append(contentsOf: DiffableResult(identifier: "module").trackDifference(actual: self.module, expected: castObject.module)) results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) - results.append(contentsOf: DiffableResult(identifier: "isStatic").trackDifference(actual: self.isStatic, expected: castObject.isStatic)) - results.append(contentsOf: DiffableResult(identifier: "isClass").trackDifference(actual: self.isClass, expected: castObject.isClass)) - results.append(contentsOf: DiffableResult(identifier: "isFailableInitializer").trackDifference(actual: self.isFailableInitializer, expected: castObject.isFailableInitializer)) + results.append(contentsOf: DiffableResult(identifier: "parentName").trackDifference(actual: self.parentName, expected: castObject.parentName)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) - results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) - results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) - results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) - results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() - hasher.combine(self.name) - hasher.combine(self.selectorName) - hasher.combine(self.parameters) - hasher.combine(self.returnTypeName) - hasher.combine(self.isAsync) - hasher.combine(self.`throws`) - hasher.combine(self.`rethrows`) + hasher.combine(self.aliasName) + hasher.combine(self.typeName) + hasher.combine(self.module) hasher.combine(self.accessLevel) - hasher.combine(self.isStatic) - hasher.combine(self.isClass) - hasher.combine(self.isFailableInitializer) + hasher.combine(self.parentName) hasher.combine(self.annotations) hasher.combine(self.documentation) - hasher.combine(self.definedInTypeName) - hasher.combine(self.attributes) - hasher.combine(self.modifiers) - hasher.combine(self.genericRequirements) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? Method else { return false } - if self.name != rhs.name { return false } - if self.selectorName != rhs.selectorName { return false } - if self.parameters != rhs.parameters { return false } - if self.returnTypeName != rhs.returnTypeName { return false } - if self.isAsync != rhs.isAsync { return false } - if self.`throws` != rhs.`throws` { return false } - if self.`rethrows` != rhs.`rethrows` { return false } + guard let rhs = object as? Typealias else { return false } + if self.aliasName != rhs.aliasName { return false } + if self.typeName != rhs.typeName { return false } + if self.module != rhs.module { return false } if self.accessLevel != rhs.accessLevel { return false } - if self.isStatic != rhs.isStatic { return false } - if self.isClass != rhs.isClass { return false } - if self.isFailableInitializer != rhs.isFailableInitializer { return false } - if self.annotations != rhs.annotations { return false } + if self.parentName != rhs.parentName { return false } if self.documentation != rhs.documentation { return false } - if self.definedInTypeName != rhs.definedInTypeName { return false } - if self.attributes != rhs.attributes { return false } - if self.modifiers != rhs.modifiers { return false } - if self.genericRequirements != rhs.genericRequirements { return false } + if self.annotations != rhs.annotations { return false } return true } - -// sourcery:inline:Method.AutoCoding + +// sourcery:inline:Typealias.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { - withVaList(["name"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.name = name - guard let selectorName: String = aDecoder.decode(forKey: "selectorName") else { - withVaList(["selectorName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.selectorName = selectorName - guard let parameters: [MethodParameter] = aDecoder.decode(forKey: "parameters") else { - withVaList(["parameters"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.parameters = parameters - guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { - withVaList(["returnTypeName"]) { arguments in + guard let aliasName: String = aDecoder.decode(forKey: "aliasName") else { + withVaList(["aliasName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.returnTypeName = returnTypeName - self.returnType = aDecoder.decode(forKey: "returnType") - self.isAsync = aDecoder.decode(forKey: "isAsync") - self.`throws` = aDecoder.decode(forKey: "`throws`") - self.`rethrows` = aDecoder.decode(forKey: "`rethrows`") - guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { - withVaList(["accessLevel"]) { arguments in + }; self.aliasName = aliasName + guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { + withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.accessLevel = accessLevel - self.isStatic = aDecoder.decode(forKey: "isStatic") - self.isClass = aDecoder.decode(forKey: "isClass") - self.isFailableInitializer = aDecoder.decode(forKey: "isFailableInitializer") - guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { + }; self.typeName = typeName + self.type = aDecoder.decode(forKey: "type") + self.module = aDecoder.decode(forKey: "module") + guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations - guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { + guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation - self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") - self.definedInType = aDecoder.decode(forKey: "definedInType") - guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { - withVaList(["attributes"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.attributes = attributes - guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { - withVaList(["modifiers"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.modifiers = modifiers - guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { - withVaList(["genericRequirements"]) { arguments in + self.parent = aDecoder.decode(forKey: "parent") + guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { + withVaList(["accessLevel"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.genericRequirements = genericRequirements + }; self.accessLevel = accessLevel + self.parentName = aDecoder.decode(forKey: "parentName") } /// :nodoc: public func encode(with aCoder: NSCoder) { - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.selectorName, forKey: "selectorName") - aCoder.encode(self.parameters, forKey: "parameters") - aCoder.encode(self.returnTypeName, forKey: "returnTypeName") - aCoder.encode(self.returnType, forKey: "returnType") - aCoder.encode(self.isAsync, forKey: "isAsync") - aCoder.encode(self.`throws`, forKey: "`throws`") - aCoder.encode(self.`rethrows`, forKey: "`rethrows`") - aCoder.encode(self.accessLevel, forKey: "accessLevel") - aCoder.encode(self.isStatic, forKey: "isStatic") - aCoder.encode(self.isClass, forKey: "isClass") - aCoder.encode(self.isFailableInitializer, forKey: "isFailableInitializer") + aCoder.encode(self.aliasName, forKey: "aliasName") + aCoder.encode(self.typeName, forKey: "typeName") + aCoder.encode(self.type, forKey: "type") + aCoder.encode(self.module, forKey: "module") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") - aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") - aCoder.encode(self.definedInType, forKey: "definedInType") - aCoder.encode(self.attributes, forKey: "attributes") - aCoder.encode(self.modifiers, forKey: "modifiers") - aCoder.encode(self.genericRequirements, forKey: "genericRequirements") + aCoder.encode(self.parent, forKey: "parent") + aCoder.encode(self.accessLevel, forKey: "accessLevel") + aCoder.encode(self.parentName, forKey: "parentName") } // sourcery:end } """), - .init(name: "Modifier.swift", content: + .init(name: "Typed.swift", content: """ import Foundation -public typealias SourceryModifier = Modifier -/// modifier can be thing like `private`, `class`, `nonmutating` -/// if a declaration has modifier like `private(set)` it's name will be `private` and detail will be `set` -@objcMembers -public class Modifier: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJSExport, Diffable { +/// Descibes typed declaration, i.e. variable, method parameter, tuple element, enum case associated value +public protocol Typed { - /// The declaration modifier name. - public let name: String + // sourcery: skipEquality, skipDescription + /// Type, if known + var type: Type? { get } - /// The modifier detail, if any. - public let detail: String? + // sourcery: skipEquality, skipDescription + /// Type name + var typeName: TypeName { get } - public init(name: String, detail: String? = nil) { - self.name = name - self.detail = detail - } + // sourcery: skipEquality, skipDescription + /// Whether type is optional + var isOptional: Bool { get } - public var asSource: String { - if let detail = detail { - return "\\(name)(\\(detail))" - } else { - return name - } - } + // sourcery: skipEquality, skipDescription + /// Whether type is implicitly unwrapped optional + var isImplicitlyUnwrappedOptional: Bool { get } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? Modifier else { - results.append("Incorrect type ") - return results - } - results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "detail").trackDifference(actual: self.detail, expected: castObject.detail)) - return results - } + // sourcery: skipEquality, skipDescription + /// Type name without attributes and optional type information + var unwrappedTypeName: String { get } +} - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.name) - hasher.combine(self.detail) - return hasher.finalize() - } +"""), + .init(name: "AssociatedType.swift", content: +""" +#if canImport(ObjectiveC) +import Foundation - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? Modifier else { return false } +/// Describes Swift AssociatedType +@objcMembers +public final class AssociatedType: NSObject, SourceryModel { + /// Associated type name + public let name: String + + /// Associated type type constraint name, if specified + public let typeName: TypeName? + + // sourcery: skipEquality, skipDescription + /// Associated type constrained type, if known, i.e. if the type is declared in the scanned sources. + public var type: Type? + + /// :nodoc: + public init(name: String, typeName: TypeName? = nil, type: Type? = nil) { + self.name = name + self.typeName = typeName + self.type = type + } + + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("name = \\(String(describing: self.name)), ") + string.append("typeName = \\(String(describing: self.typeName))") + return string + } + + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? AssociatedType else { + results.append("Incorrect type ") + return results + } + results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) + results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) + return results + } + + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.name) + hasher.combine(self.typeName) + return hasher.finalize() + } + + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? AssociatedType else { return false } if self.name != rhs.name { return false } - if self.detail != rhs.detail { return false } + if self.typeName != rhs.typeName { return false } return true } - // sourcery:inline:Modifier.AutoCoding +// sourcery:inline:AssociatedType.AutoCoding - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name - self.detail = aDecoder.decode(forKey: "detail") - } + self.typeName = aDecoder.decode(forKey: "typeName") + self.type = aDecoder.decode(forKey: "type") + } - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.detail, forKey: "detail") - } - // sourcery:end + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.typeName, forKey: "typeName") + aCoder.encode(self.type, forKey: "type") + } +// sourcery:end } - +#endif """), - .init(name: "ParserResultsComposed.swift", content: + .init(name: "AssociatedValue.swift", content: """ // -// Created by Krzysztof Zablocki on 31/12/2016. +// Created by Krzysztof Zablocki on 13/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // - +#if canImport(ObjectiveC) import Foundation -internal struct ParserResultsComposed { - private(set) var typeMap = [String: Type]() - private(set) var modules = [String: [String: Type]]() - private(set) var types = [Type]() +/// Defines enum case associated value +@objcMembers +public final class AssociatedValue: NSObject, SourceryModel, AutoDescription, Typed, Annotated, Diffable { - let parsedTypes: [Type] - let functions: [SourceryMethod] - let resolvedTypealiases: [String: Typealias] - let unresolvedTypealiases: [String: Typealias] + /// Associated value local name. + /// This is a name to be used to construct enum case value + public let localName: String? - init(parserResult: FileParserResult) { - // TODO: This logic should really be more complicated - // For any resolution we need to be looking at accessLevel and module boundaries - // e.g. there might be a typealias `private typealias Something = MyType` in one module and same name in another with public modifier, one could be accessed and the other could not - self.functions = parserResult.functions - let aliases = Self.typealiases(parserResult) - resolvedTypealiases = aliases.resolved - unresolvedTypealiases = aliases.unresolved - parsedTypes = parserResult.types + /// Associated value external name. + /// This is a name to be used to access value in value-bindig + public let externalName: String? - // set definedInType for all methods and variables - parsedTypes - .forEach { type in - type.variables.forEach { $0.definedInType = type } - type.methods.forEach { $0.definedInType = type } - type.subscripts.forEach { $0.definedInType = type } - } + /// Associated value type name + public let typeName: TypeName - // map all known types to their names - parsedTypes - .filter { !$0.isExtension } - .forEach { - typeMap[$0.globalName] = $0 - if let module = $0.module { - var typesByModules = modules[module, default: [:]] - typesByModules[$0.name] = $0 - modules[module] = typesByModules - } - } + // sourcery: skipEquality, skipDescription + /// Associated value type, if known + public var type: Type? - /// Resolve typealiases - let typealiases = Array(unresolvedTypealiases.values) - typealiases.forEach { alias in - alias.type = resolveType(typeName: alias.typeName, containingType: alias.parent) - } + /// Associated value default value + public let defaultValue: String? - types = unifyTypes() + /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 + public var annotations: Annotations = [:] + + /// :nodoc: + public init(localName: String?, externalName: String?, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:]) { + self.localName = localName + self.externalName = externalName + self.typeName = typeName + self.type = type + self.defaultValue = defaultValue + self.annotations = annotations } - private func resolveExtensionOfNestedType(_ type: Type) { - var components = type.localName.components(separatedBy: ".") - let rootName = type.module ?? components.removeFirst() // Module/parent name - if let moduleTypes = modules[rootName], let baseType = moduleTypes[components.joined(separator: ".")] ?? moduleTypes[type.localName] { - type.localName = baseType.localName - type.module = baseType.module - type.parent = baseType.parent - } else { - for _import in type.imports { - let parentKey = "\\(rootName).\\(components.joined(separator: "."))" - let parentKeyFull = "\\(_import.moduleName).\\(parentKey)" - if let moduleTypes = modules[_import.moduleName], let baseType = moduleTypes[parentKey] ?? moduleTypes[parentKeyFull] { - type.localName = baseType.localName - type.module = baseType.module - type.parent = baseType.parent - return - } - } + convenience init(name: String? = nil, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:]) { + self.init(localName: name, externalName: name, typeName: typeName, type: type, defaultValue: defaultValue, annotations: annotations) + } + + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("localName = \\(String(describing: self.localName)), ") + string.append("externalName = \\(String(describing: self.externalName)), ") + string.append("typeName = \\(String(describing: self.typeName)), ") + string.append("defaultValue = \\(String(describing: self.defaultValue)), ") + string.append("annotations = \\(String(describing: self.annotations))") + return string + } + + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? AssociatedValue else { + results.append("Incorrect type ") + return results } + results.append(contentsOf: DiffableResult(identifier: "localName").trackDifference(actual: self.localName, expected: castObject.localName)) + results.append(contentsOf: DiffableResult(identifier: "externalName").trackDifference(actual: self.externalName, expected: castObject.externalName)) + results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) + results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) + results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) + return results } - private mutating func unifyTypes() -> [Type] { - /// Resolve actual names of extensions, as they could have been done on typealias and note updated child names in uniques if needed - parsedTypes - .filter { $0.isExtension } - .forEach { - let oldName = $0.globalName + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.localName) + hasher.combine(self.externalName) + hasher.combine(self.typeName) + hasher.combine(self.defaultValue) + hasher.combine(self.annotations) + return hasher.finalize() + } - if $0.parent == nil, $0.localName.contains(".") { - resolveExtensionOfNestedType($0) - } + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? AssociatedValue else { return false } + if self.localName != rhs.localName { return false } + if self.externalName != rhs.externalName { return false } + if self.typeName != rhs.typeName { return false } + if self.defaultValue != rhs.defaultValue { return false } + if self.annotations != rhs.annotations { return false } + return true + } - if let resolved = resolveGlobalName(for: oldName, containingType: $0.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases)?.name { - $0.localName = resolved.replacingOccurrences(of: "\\($0.module != nil ? "\\($0.module!)." : "")", with: "") - } else { - return - } +// sourcery:inline:AssociatedValue.AutoCoding - // nothing left to do - guard oldName != $0.globalName else { - return + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + self.localName = aDecoder.decode(forKey: "localName") + self.externalName = aDecoder.decode(forKey: "externalName") + guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { + withVaList(["typeName"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } - - // if it had contained types, they might have been fully defined and so their name has to be noted in uniques - func rewriteChildren(of type: Type) { - // child is never an extension so no need to check - for child in type.containedTypes { - typeMap[child.globalName] = child - rewriteChildren(of: child) - } + fatalError() + }; self.typeName = typeName + self.type = aDecoder.decode(forKey: "type") + self.defaultValue = aDecoder.decode(forKey: "defaultValue") + guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { + withVaList(["annotations"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } - rewriteChildren(of: $0) - } - - // extend all types with their extensions - parsedTypes.forEach { type in - type.inheritedTypes = type.inheritedTypes.map { inheritedName in - resolveGlobalName(for: inheritedName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases)?.name ?? inheritedName - } - - let uniqueType = typeMap[type.globalName] ?? // this check will only fail on an extension? - typeFromComposedName(type.name, modules: modules) ?? // this can happen for an extension on unknown type, this case should probably be handled by the inferTypeNameFromModules - (inferTypeNameFromModules(from: type.localName, containedInType: type.parent, uniqueTypes: typeMap, modules: modules).flatMap { typeMap[$0] }) - - guard let current = uniqueType else { - assert(type.isExtension, "Type \\(type.globalName) should be extension") + fatalError() + }; self.annotations = annotations + } - // for unknown types we still store their extensions but mark them as unknown - type.isUnknownExtension = true - if let existingType = typeMap[type.globalName] { - existingType.extend(type) - typeMap[type.globalName] = existingType - } else { - typeMap[type.globalName] = type - } + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.localName, forKey: "localName") + aCoder.encode(self.externalName, forKey: "externalName") + aCoder.encode(self.typeName, forKey: "typeName") + aCoder.encode(self.type, forKey: "type") + aCoder.encode(self.defaultValue, forKey: "defaultValue") + aCoder.encode(self.annotations, forKey: "annotations") + } +// sourcery:end - let inheritanceClause = type.inheritedTypes.isEmpty ? "" : - ": \\(type.inheritedTypes.joined(separator: ", "))" +} +#endif - Log.astWarning("Found \\"extension \\(type.name)\\(inheritanceClause)\\" of type for which there is no original type declaration information.") - return - } +"""), + .init(name: "Closure.swift", content: +""" +#if canImport(ObjectiveC) +import Foundation - if current == type { return } +/// Describes closure type +@objcMembers +public final class ClosureType: NSObject, SourceryModel, Diffable { - current.extend(type) - typeMap[current.globalName] = current - } + /// Type name used in declaration with stripped whitespaces and new lines + public let name: String - let values = typeMap.values - var processed = Set(minimumCapacity: values.count) - return typeMap.values.filter({ - let name = $0.globalName - let wasProcessed = processed.contains(name) - processed.insert(name) - return !wasProcessed - }) - } + /// List of closure parameters + public let parameters: [ClosureParameter] - /// returns typealiases map to their full names, with `resolved` removing intermediate - /// typealises and `unresolved` including typealiases that reference other typealiases. - private static func typealiases(_ parserResult: FileParserResult) -> (resolved: [String: Typealias], unresolved: [String: Typealias]) { - var typealiasesByNames = [String: Typealias]() - parserResult.typealiases.forEach { typealiasesByNames[$0.name] = $0 } - parserResult.types.forEach { type in - type.typealiases.forEach({ (_, alias) in - // TODO: should I deal with the fact that alias.name depends on type name but typenames might be updated later on - // maybe just handle non extension case here and extension aliases after resolving them? - typealiasesByNames[alias.name] = alias - }) - } + /// Return value type name + public let returnTypeName: TypeName - let unresolved = typealiasesByNames + /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` + public var actualReturnTypeName: TypeName { + return returnTypeName.actualTypeName ?? returnTypeName + } - // ! if a typealias leads to another typealias, follow through and replace with final type - typealiasesByNames.forEach { _, alias in - var aliasNamesToReplace = [alias.name] - var finalAlias = alias - while let targetAlias = typealiasesByNames[finalAlias.typeName.name] { - aliasNamesToReplace.append(targetAlias.name) - finalAlias = targetAlias - } + // sourcery: skipEquality, skipDescription + /// Actual return value type, if known + public var returnType: Type? - // ! replace all keys - aliasNamesToReplace.forEach { typealiasesByNames[$0] = finalAlias } - } + // sourcery: skipEquality, skipDescription + /// Whether return value type is optional + public var isOptionalReturnType: Bool { + return returnTypeName.isOptional + } - return (resolved: typealiasesByNames, unresolved: unresolved) + // sourcery: skipEquality, skipDescription + /// Whether return value type is implicitly unwrapped optional + public var isImplicitlyUnwrappedOptionalReturnType: Bool { + return returnTypeName.isImplicitlyUnwrappedOptional } - /// Resolves type identifier for name - func resolveGlobalName(for type: String, - containingType: Type? = nil, - unique: [String: Type]? = nil, - modules: [String: [String: Type]], - typealiases: [String: Typealias]) -> (name: String, typealias: Typealias?)? { - // if the type exists for this name and isn't an extension just return it's name - // if it's extension we need to check if there aren't other options TODO: verify - if let realType = unique?[type], realType.isExtension == false { - return (name: realType.globalName, typealias: nil) - } + // sourcery: skipEquality, skipDescription + /// Return value type name without attributes and optional type information + public var unwrappedReturnTypeName: String { + return returnTypeName.unwrappedTypeName + } + + /// Whether method is async method + public let isAsync: Bool - if let alias = typealiases[type] { - return (name: alias.type?.globalName ?? alias.typeName.name, typealias: alias) - } + /// async keyword + public let asyncKeyword: String? - if let containingType = containingType { - if type == "Self" { - return (name: containingType.globalName, typealias: nil) - } + /// Whether closure throws + public let `throws`: Bool - var currentContainer: Type? = containingType - while currentContainer != nil, let parentName = currentContainer?.globalName { - /// TODO: no parent for sure? - /// manually walk the containment tree - if let name = resolveGlobalName(for: "\\(parentName).\\(type)", containingType: nil, unique: unique, modules: modules, typealiases: typealiases) { - return name - } + /// throws or rethrows keyword + public let throwsOrRethrowsKeyword: String? - currentContainer = currentContainer?.parent - } + /// :nodoc: + public init(name: String, parameters: [ClosureParameter], returnTypeName: TypeName, returnType: Type? = nil, asyncKeyword: String? = nil, throwsOrRethrowsKeyword: String? = nil) { + self.name = name + self.parameters = parameters + self.returnTypeName = returnTypeName + self.returnType = returnType + self.asyncKeyword = asyncKeyword + self.isAsync = asyncKeyword != nil + self.throwsOrRethrowsKeyword = throwsOrRethrowsKeyword + self.`throws` = throwsOrRethrowsKeyword != nil + } -// if let name = resolveGlobalName(for: "\\(containingType.globalName).\\(type)", containingType: containingType.parent, unique: unique, modules: modules, typealiases: typealiases) { -// return name -// } + public var asSource: String { + "\\(parameters.asSource)\\(asyncKeyword != nil ? " \\(asyncKeyword!)" : "")\\(throwsOrRethrowsKeyword != nil ? " \\(throwsOrRethrowsKeyword!)" : "") -> \\(returnTypeName.asSource)" + } -// last check it's via module -// if let module = containingType.module, let name = resolveGlobalName(for: "\\(module).\\(type)", containingType: nil, unique: unique, modules: modules, typealiases: typealiases) { -// return name -// } - } + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("name = \\(String(describing: self.name)), ") + string.append("parameters = \\(String(describing: self.parameters)), ") + string.append("returnTypeName = \\(String(describing: self.returnTypeName)), ") + string.append("actualReturnTypeName = \\(String(describing: self.actualReturnTypeName)), ") + string.append("isAsync = \\(String(describing: self.isAsync)), ") + string.append("asyncKeyword = \\(String(describing: self.asyncKeyword)), ") + string.append("`throws` = \\(String(describing: self.`throws`)), ") + string.append("throwsOrRethrowsKeyword = \\(String(describing: self.throwsOrRethrowsKeyword)), ") + string.append("asSource = \\(String(describing: self.asSource))") + return string + } - // TODO: is this needed? - if let inferred = inferTypeNameFromModules(from: type, containedInType: containingType, uniqueTypes: unique ?? [:], modules: modules) { - return (name: inferred, typealias: nil) + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? ClosureType else { + results.append("Incorrect type ") + return results } + results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) + results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) + results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) + results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) + results.append(contentsOf: DiffableResult(identifier: "asyncKeyword").trackDifference(actual: self.asyncKeyword, expected: castObject.asyncKeyword)) + results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) + results.append(contentsOf: DiffableResult(identifier: "throwsOrRethrowsKeyword").trackDifference(actual: self.throwsOrRethrowsKeyword, expected: castObject.throwsOrRethrowsKeyword)) + return results + } - return typeFromComposedName(type, modules: modules).map { (name: $0.globalName, typealias: nil) } + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.name) + hasher.combine(self.parameters) + hasher.combine(self.returnTypeName) + hasher.combine(self.isAsync) + hasher.combine(self.asyncKeyword) + hasher.combine(self.`throws`) + hasher.combine(self.throwsOrRethrowsKeyword) + return hasher.finalize() } - private func inferTypeNameFromModules(from typeIdentifier: String, containedInType: Type?, uniqueTypes: [String: Type], modules: [String: [String: Type]]) -> String? { - func fullName(for module: String) -> String { - "\\(module).\\(typeIdentifier)" - } + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? ClosureType else { return false } + if self.name != rhs.name { return false } + if self.parameters != rhs.parameters { return false } + if self.returnTypeName != rhs.returnTypeName { return false } + if self.isAsync != rhs.isAsync { return false } + if self.asyncKeyword != rhs.asyncKeyword { return false } + if self.`throws` != rhs.`throws` { return false } + if self.throwsOrRethrowsKeyword != rhs.throwsOrRethrowsKeyword { return false } + return true + } - func type(for module: String) -> Type? { - return modules[module]?[typeIdentifier] +// sourcery:inline:ClosureType.AutoCoding + + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let name: String = aDecoder.decode(forKey: "name") else { + withVaList(["name"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.name = name + guard let parameters: [ClosureParameter] = aDecoder.decode(forKey: "parameters") else { + withVaList(["parameters"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.parameters = parameters + guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { + withVaList(["returnTypeName"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.returnTypeName = returnTypeName + self.returnType = aDecoder.decode(forKey: "returnType") + self.isAsync = aDecoder.decode(forKey: "isAsync") + self.asyncKeyword = aDecoder.decode(forKey: "asyncKeyword") + self.`throws` = aDecoder.decode(forKey: "`throws`") + self.throwsOrRethrowsKeyword = aDecoder.decode(forKey: "throwsOrRethrowsKeyword") } - func ambiguousErrorMessage(from types: [Type]) -> String? { - Log.astWarning("Ambiguous type \\(typeIdentifier), found \\(types.map { $0.globalName }.joined(separator: ", ")). Specify module name at declaration site to disambiguate.") - return nil + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.parameters, forKey: "parameters") + aCoder.encode(self.returnTypeName, forKey: "returnTypeName") + aCoder.encode(self.returnType, forKey: "returnType") + aCoder.encode(self.isAsync, forKey: "isAsync") + aCoder.encode(self.asyncKeyword, forKey: "asyncKeyword") + aCoder.encode(self.`throws`, forKey: "`throws`") + aCoder.encode(self.throwsOrRethrowsKeyword, forKey: "throwsOrRethrowsKeyword") } +// sourcery:end - let explicitModulesAtDeclarationSite: [String] = [ - containedInType?.module.map { [$0] } ?? [], // main module for this typename - containedInType?.imports.map { $0.moduleName } ?? [] // imported modules - ] - .flatMap { $0 } +} +#endif - let remainingModules = Set(modules.keys).subtracting(explicitModulesAtDeclarationSite) +"""), + .init(name: "ClosureParameter.swift", content: +""" +#if canImport(ObjectiveC) +import Foundation - /// We need to check whether we can find type in one of the modules but we need to be careful to avoid amibiguity - /// First checking explicit modules available at declaration site (so source module + all imported ones) - /// If there is no ambigiuity there we can assume that module will be resolved by the compiler - /// If that's not the case we look after remaining modules in the application and if the typename has no ambigiuity we use that - /// But if there is more than 1 typename duplication across modules we have no way to resolve what is the compiler going to use so we fail - let moduleSetsToCheck: [[String]] = [ - explicitModulesAtDeclarationSite, - Array(remainingModules) - ] +// sourcery: skipDiffing +@objcMembers +public final class ClosureParameter: NSObject, SourceryModel, Typed, Annotated { + /// Parameter external name + public var argumentLabel: String? - for modules in moduleSetsToCheck { - let possibleTypes = modules - .compactMap { type(for: $0) } + /// Parameter internal name + public let name: String? - if possibleTypes.count > 1 { - return ambiguousErrorMessage(from: possibleTypes) - } + /// Parameter type name + public let typeName: TypeName - if let type = possibleTypes.first { - return type.globalName - } - } + /// Parameter flag whether it's inout or not + public let `inout`: Bool - // as last result for unknown types / extensions - // try extracting type from unique array - if let module = containedInType?.module { - return uniqueTypes[fullName(for: module)]?.globalName - } - return nil + // sourcery: skipEquality, skipDescription + /// Parameter type, if known + public var type: Type? + + /// Parameter if the argument has a variadic type or not + public let isVariadic: Bool + + /// Parameter type attributes, i.e. `@escaping` + public var typeAttributes: AttributeList { + return typeName.attributes } - func typeFromComposedName(_ name: String, modules: [String: [String: Type]]) -> Type? { - guard name.contains(".") else { return nil } - let nameComponents = name.components(separatedBy: ".") - let moduleName = nameComponents[0] - let typeName = nameComponents.suffix(from: 1).joined(separator: ".") - return modules[moduleName]?[typeName] + /// Method parameter default value expression + public var defaultValue: String? + + /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 + public var annotations: Annotations = [:] + + /// :nodoc: + public init(argumentLabel: String? = nil, name: String? = nil, typeName: TypeName, type: Type? = nil, + defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false, + isVariadic: Bool = false) { + self.typeName = typeName + self.argumentLabel = argumentLabel + self.name = name + self.type = type + self.defaultValue = defaultValue + self.annotations = annotations + self.`inout` = isInout + self.isVariadic = isVariadic } - func resolveType(typeName: TypeName, containingType: Type?, method: Method? = nil) -> Type? { - let resolveTypeWithName = { (typeName: TypeName) -> Type? in - return self.resolveType(typeName: typeName, containingType: containingType) + public var asSource: String { + let typeInfo = "\\(`inout` ? "inout " : "")\\(typeName.asSource)\\(isVariadic ? "..." : "")" + if argumentLabel?.nilIfNotValidParameterName == nil, name?.nilIfNotValidParameterName == nil { + return typeInfo } - let unique = typeMap - - if let name = typeName.actualTypeName { - let resolvedIdentifier = name.generic?.name ?? name.unwrappedTypeName - return unique[resolvedIdentifier] + let typeSuffix = ": \\(typeInfo)" + guard argumentLabel != name else { + return name ?? "" + typeSuffix } - let retrievedName = actualTypeName(for: typeName, containingType: containingType) - let lookupName = retrievedName ?? typeName + let labels = [argumentLabel ?? "_", name?.nilIfEmpty] + .compactMap { $0 } + .joined(separator: " ") - if let tuple = lookupName.tuple { - var needsUpdate = false + return (labels.nilIfEmpty ?? "_") + typeSuffix + } - tuple.elements.forEach { tupleElement in - tupleElement.type = resolveTypeWithName(tupleElement.typeName) - if tupleElement.typeName.actualTypeName != nil { - needsUpdate = true - } - } + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.argumentLabel) + hasher.combine(self.name) + hasher.combine(self.typeName) + hasher.combine(self.`inout`) + hasher.combine(self.isVariadic) + hasher.combine(self.defaultValue) + hasher.combine(self.annotations) + return hasher.finalize() + } - if needsUpdate || retrievedName != nil { - let tupleCopy = TupleType(name: tuple.name, elements: tuple.elements) - tupleCopy.elements.forEach { - $0.typeName = $0.actualTypeName ?? $0.typeName - $0.typeName.actualTypeName = nil - } - tupleCopy.name = tupleCopy.elements.asTypeName + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("argumentLabel = \\(String(describing: self.argumentLabel)), ") + string.append("name = \\(String(describing: self.name)), ") + string.append("typeName = \\(String(describing: self.typeName)), ") + string.append("`inout` = \\(String(describing: self.`inout`)), ") + string.append("typeAttributes = \\(String(describing: self.typeAttributes)), ") + string.append("defaultValue = \\(String(describing: self.defaultValue)), ") + string.append("annotations = \\(String(describing: self.annotations)), ") + string.append("asSource = \\(String(describing: self.asSource))") + return string + } - typeName.tuple = tupleCopy // TODO: really don't like this old behaviour - typeName.actualTypeName = TypeName(name: tupleCopy.name, - isOptional: typeName.isOptional, - isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, - tuple: tupleCopy, - array: lookupName.array, - dictionary: lookupName.dictionary, - closure: lookupName.closure, - set: lookupName.set, - generic: lookupName.generic - ) - } - return nil - } else - if let array = lookupName.array { - array.elementType = resolveTypeWithName(array.elementTypeName) + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? ClosureParameter else { return false } + if self.argumentLabel != rhs.argumentLabel { return false } + if self.name != rhs.name { return false } + if self.typeName != rhs.typeName { return false } + if self.`inout` != rhs.`inout` { return false } + if self.isVariadic != rhs.isVariadic { return false } + if self.defaultValue != rhs.defaultValue { return false } + if self.annotations != rhs.annotations { return false } + return true + } - if array.elementTypeName.actualTypeName != nil || retrievedName != nil { - let array = ArrayType(name: array.name, elementTypeName: array.elementTypeName, elementType: array.elementType) - array.elementTypeName = array.elementTypeName.actualTypeName ?? array.elementTypeName - array.elementTypeName.actualTypeName = nil - array.name = array.asSource - typeName.array = array // TODO: really don't like this old behaviour - typeName.generic = array.asGeneric // TODO: really don't like this old behaviour + // sourcery:inline:ClosureParameter.AutoCoding - typeName.actualTypeName = TypeName(name: array.name, - isOptional: typeName.isOptional, - isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, - tuple: lookupName.tuple, - array: array, - dictionary: lookupName.dictionary, - closure: lookupName.closure, - set: lookupName.set, - generic: typeName.generic - ) + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + self.argumentLabel = aDecoder.decode(forKey: "argumentLabel") + self.name = aDecoder.decode(forKey: "name") + guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { + withVaList(["typeName"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.typeName = typeName + self.`inout` = aDecoder.decode(forKey: "`inout`") + self.type = aDecoder.decode(forKey: "type") + self.isVariadic = aDecoder.decode(forKey: "isVariadic") + self.defaultValue = aDecoder.decode(forKey: "defaultValue") + guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { + withVaList(["annotations"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.annotations = annotations } - } else - if let dictionary = lookupName.dictionary { - dictionary.keyType = resolveTypeWithName(dictionary.keyTypeName) - dictionary.valueType = resolveTypeWithName(dictionary.valueTypeName) - if dictionary.keyTypeName.actualTypeName != nil || dictionary.valueTypeName.actualTypeName != nil || retrievedName != nil { - let dictionary = DictionaryType(name: dictionary.name, valueTypeName: dictionary.valueTypeName, valueType: dictionary.valueType, keyTypeName: dictionary.keyTypeName, keyType: dictionary.keyType) - dictionary.keyTypeName = dictionary.keyTypeName.actualTypeName ?? dictionary.keyTypeName - dictionary.keyTypeName.actualTypeName = nil // TODO: really don't like this old behaviour - dictionary.valueTypeName = dictionary.valueTypeName.actualTypeName ?? dictionary.valueTypeName - dictionary.valueTypeName.actualTypeName = nil // TODO: really don't like this old behaviour + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.argumentLabel, forKey: "argumentLabel") + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.typeName, forKey: "typeName") + aCoder.encode(self.`inout`, forKey: "`inout`") + aCoder.encode(self.type, forKey: "type") + aCoder.encode(self.isVariadic, forKey: "isVariadic") + aCoder.encode(self.defaultValue, forKey: "defaultValue") + aCoder.encode(self.annotations, forKey: "annotations") + } - dictionary.name = dictionary.asSource + // sourcery:end +} - typeName.dictionary = dictionary // TODO: really don't like this old behaviour - typeName.generic = dictionary.asGeneric // TODO: really don't like this old behaviour +extension Array where Element == ClosureParameter { + public var asSource: String { + "(\\(map { $0.asSource }.joined(separator: ", ")))" + } +} +#endif - typeName.actualTypeName = TypeName(name: dictionary.asSource, - isOptional: typeName.isOptional, - isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, - tuple: lookupName.tuple, - array: lookupName.array, - dictionary: dictionary, - closure: lookupName.closure, - set: lookupName.set, - generic: dictionary.asGeneric - ) - } - } else - if let closure = lookupName.closure { - var needsUpdate = false +"""), + .init(name: "Enum.swift", content: +""" +// +// Created by Krzysztof Zablocki on 13/09/2016. +// Copyright (c) 2016 Pixle. All rights reserved. +// - closure.returnType = resolveTypeWithName(closure.returnTypeName) - closure.parameters.forEach { parameter in - parameter.type = resolveTypeWithName(parameter.typeName) - if parameter.typeName.actualTypeName != nil { - needsUpdate = true - } - } +#if canImport(ObjectiveC) +import Foundation - if closure.returnTypeName.actualTypeName != nil || needsUpdate || retrievedName != nil { - typeName.closure = closure // TODO: really don't like this old behaviour +/// Defines Swift enum +@objcMembers +public final class Enum: Type { + // sourcery: skipDescription + /// Returns "enum" + public override var kind: String { return "enum" } - typeName.actualTypeName = TypeName(name: closure.asSource, - isOptional: typeName.isOptional, - isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, - tuple: lookupName.tuple, - array: lookupName.array, - dictionary: lookupName.dictionary, - closure: closure, - set: lookupName.set, - generic: lookupName.generic - ) - } + /// Enum cases + public var cases: [EnumCase] - return nil - } else - if let generic = lookupName.generic { - var needsUpdate = false + /** + Enum raw value type name, if any. This type is removed from enum's `based` and `inherited` types collections. - generic.typeParameters.forEach { parameter in - parameter.type = resolveTypeWithName(parameter.typeName) - if parameter.typeName.actualTypeName != nil { - needsUpdate = true + - important: Unless raw type is specified explicitly via type alias RawValue it will be set to the first type in the inheritance chain. + So if your enum does not have raw value but implements protocols you'll have to specify conformance to these protocols via extension to get enum with nil raw value type and all based and inherited types. + */ + public var rawTypeName: TypeName? { + didSet { + if let rawTypeName = rawTypeName { + hasRawType = true + if let index = inheritedTypes.firstIndex(of: rawTypeName.name) { + inheritedTypes.remove(at: index) } - } - - if needsUpdate || retrievedName != nil { - let generic = GenericType(name: generic.name, typeParameters: generic.typeParameters) - generic.typeParameters.forEach { - $0.typeName = $0.typeName.actualTypeName ?? $0.typeName - $0.typeName.actualTypeName = nil // TODO: really don't like this old behaviour + if based[rawTypeName.name] != nil { + based[rawTypeName.name] = nil } - typeName.generic = generic // TODO: really don't like this old behaviour - typeName.array = lookupName.array // TODO: really don't like this old behaviour - typeName.dictionary = lookupName.dictionary // TODO: really don't like this old behaviour - - let params = generic.typeParameters.map { $0.typeName.asSource }.joined(separator: ", ") - - typeName.actualTypeName = TypeName(name: "\\(generic.name)<\\(params)>", - isOptional: typeName.isOptional, - isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, - tuple: lookupName.tuple, - array: lookupName.array, // TODO: asArray - dictionary: lookupName.dictionary, // TODO: asDictionary - closure: lookupName.closure, - set: lookupName.set, - generic: generic - ) - } - } - - if let aliasedName = (typeName.actualTypeName ?? retrievedName), aliasedName.unwrappedTypeName != typeName.unwrappedTypeName { - typeName.actualTypeName = aliasedName - } - - let hasGenericRequirements = containingType?.genericRequirements.isEmpty == false - || (method != nil && method?.genericRequirements.isEmpty == false) - - if hasGenericRequirements { - // we should consider if we are looking up return type of a method with generic constraints - // where `typeName` passed would include `... where ...` suffix - let typeNameForLookup = typeName.name.split(separator: " ").first! - let genericRequirements: [GenericRequirement] - if let requirements = containingType?.genericRequirements, !requirements.isEmpty { - genericRequirements = requirements } else { - genericRequirements = method?.genericRequirements ?? [] - } - let relevantRequirements = genericRequirements.filter { - // matched type against a generic requirement name - // thus type should be replaced with a protocol composition - $0.leftType.name == typeNameForLookup - } - if relevantRequirements.count > 1 { - // compose protocols into `ProtocolComposition` and generate TypeName - var implements: [String: Type] = [:] - relevantRequirements.forEach { - implements[$0.rightType.typeName.name] = $0.rightType.type - } - let composedProtocols = ProtocolComposition( - inheritedTypes: relevantRequirements.map { $0.rightType.typeName.unwrappedTypeName }, - isGeneric: true, - composedTypes: relevantRequirements.compactMap { $0.rightType.type }, - implements: implements - ) - typeName.actualTypeName = TypeName(name: "(\\(relevantRequirements.map { $0.rightType.typeName.unwrappedTypeName }.joined(separator: " & ")))", isProtocolComposition: true) - return composedProtocols - } else if let protocolRequirement = relevantRequirements.first { - // create TypeName off a single generic's protocol requirement - typeName.actualTypeName = TypeName(name: "(\\(protocolRequirement.rightType.typeName))") - return protocolRequirement.rightType.type - } - } - - // try to peek into typealias, maybe part of the typeName is a composed identifier from a type and typealias - // i.e. - // enum Module { - // typealias ID = MyView - // } - // class MyView { - // class ID: String {} - // } - // - // let variable: Module.ID.ID // should be resolved as MyView.ID type - let finalLookup = typeName.actualTypeName ?? typeName - var resolvedIdentifier = finalLookup.generic?.name ?? finalLookup.unwrappedTypeName - for alias in resolvedTypealiases { - /// iteratively replace all typealiases from the resolvedIdentifier to get to the actual type name requested - if resolvedIdentifier.contains(alias.value.name), let range = resolvedIdentifier.range(of: alias.value.name) { - resolvedIdentifier = resolvedIdentifier.replacingCharacters(in: range, with: alias.value.typeName.name) - } - } - // should we cache resolved typenames? - if unique[resolvedIdentifier] == nil { - // peek into typealiases, if any of them contain the same typeName - // this is done after the initial attempt in order to prioritise local (recognized) types first - // before even trying to substitute the requested type with any typealias - for alias in resolvedTypealiases { - /// iteratively replace all typealiases from the resolvedIdentifier to get to the actual type name requested, - /// ignoring namespacing - if resolvedIdentifier == alias.value.aliasName { - resolvedIdentifier = alias.value.typeName.name - typeName.actualTypeName = alias.value.typeName - break - } + hasRawType = false } } - - return unique[resolvedIdentifier] - } - - private func actualTypeName(for typeName: TypeName, - containingType: Type? = nil) -> TypeName? { - let unique = typeMap - let typealiases = resolvedTypealiases - - var unwrapped = typeName.unwrappedTypeName - if let generic = typeName.generic { - unwrapped = generic.name - } - - guard let aliased = resolveGlobalName(for: unwrapped, containingType: containingType, unique: unique, modules: modules, typealiases: typealiases) else { - return nil - } - - /// TODO: verify - let generic = typeName.generic.map { GenericType(name: $0.name, typeParameters: $0.typeParameters) } - generic?.name = aliased.name - let dictionary = typeName.dictionary.map { DictionaryType(name: $0.name, valueTypeName: $0.valueTypeName, valueType: $0.valueType, keyTypeName: $0.keyTypeName, keyType: $0.keyType) } - dictionary?.name = aliased.name - let array = typeName.array.map { ArrayType(name: $0.name, elementTypeName: $0.elementTypeName, elementType: $0.elementType) } - array?.name = aliased.name - let set = typeName.set.map { SetType(name: $0.name, elementTypeName: $0.elementTypeName, elementType: $0.elementType) } - set?.name = aliased.name - - return TypeName(name: aliased.name, - isOptional: typeName.isOptional, - isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, - tuple: aliased.typealias?.typeName.tuple ?? typeName.tuple, // TODO: verify - array: aliased.typealias?.typeName.array ?? array, - dictionary: aliased.typealias?.typeName.dictionary ?? dictionary, - closure: aliased.typealias?.typeName.closure ?? typeName.closure, - set: aliased.typealias?.typeName.set ?? set, - generic: aliased.typealias?.typeName.generic ?? generic - ) } -} - -"""), - .init(name: "PhantomProtocols.swift", content: -""" -// -// Created by Krzysztof Zablocki on 23/01/2017. -// Copyright (c) 2017 Pixle. All rights reserved. -// - -import Foundation - -/// Phantom protocol for diffing -protocol AutoDiffable {} - -/// Phantom protocol for equality -protocol AutoEquatable {} - -/// Phantom protocol for equality -protocol AutoDescription {} - -/// Phantom protocol for NSCoding -protocol AutoCoding {} - -protocol AutoJSExport {} - -/// Phantom protocol for NSCoding, Equatable and Diffable -protocol SourceryModelWithoutDescription: AutoDiffable, AutoEquatable, AutoCoding, AutoJSExport {} - -protocol SourceryModel: SourceryModelWithoutDescription, AutoDescription {} - -"""), - .init(name: "Protocol.swift", content: -""" -// -// Protocol.swift -// Sourcery -// -// Created by Krzysztof Zablocki on 09/12/2016. -// Copyright © 2016 Pixle. All rights reserved. -// - -import Foundation - -/// :nodoc: -public typealias SourceryProtocol = Protocol - -/// Describes Swift protocol -@objcMembers -public final class Protocol: Type { + // sourcery: skipDescription, skipEquality + /// :nodoc: + public private(set) var hasRawType: Bool - /// Returns "protocol" - public override var kind: String { return "protocol" } + // sourcery: skipDescription, skipEquality + /// Enum raw value type, if known + public var rawType: Type? - /// list of all declared associated types with their names as keys - public var associatedTypes: [String: AssociatedType] { + // sourcery: skipEquality, skipDescription, skipCoding + /// Names of types or protocols this type inherits from, including unknown (not scanned) types + public override var based: [String: String] { didSet { - isGeneric = !associatedTypes.isEmpty || !genericRequirements.isEmpty + if let rawTypeName = rawTypeName, based[rawTypeName.name] != nil { + based[rawTypeName.name] = nil + } } } - /// list of generic requirements - public override var genericRequirements: [GenericRequirement] { - didSet { - isGeneric = !associatedTypes.isEmpty || !genericRequirements.isEmpty - } + /// Whether enum contains any associated values + public var hasAssociatedValues: Bool { + return cases.contains(where: { $0.hasAssociatedValue }) } /// :nodoc: @@ -5219,2867 +4203,4273 @@ public final class Protocol: Type { parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, + inheritedTypes: [String] = [], + rawTypeName: TypeName? = nil, + cases: [EnumCase] = [], variables: [Variable] = [], methods: [Method] = [], - subscripts: [Subscript] = [], - inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], - associatedTypes: [String: AssociatedType] = [:], - genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], - implements: [String: Type] = [:]) { - self.associatedTypes = associatedTypes - super.init( - name: name, - parent: parent, - accessLevel: accessLevel, - isExtension: isExtension, - variables: variables, - methods: methods, - subscripts: subscripts, - inheritedTypes: inheritedTypes, - containedTypes: containedTypes, - typealiases: typealiases, - genericRequirements: genericRequirements, - attributes: attributes, - modifiers: modifiers, - annotations: annotations, - documentation: documentation, - isGeneric: !associatedTypes.isEmpty || !genericRequirements.isEmpty, - implements: implements - ) + isGeneric: Bool = false) { + + self.cases = cases + self.rawTypeName = rawTypeName + self.hasRawType = rawTypeName != nil || !inheritedTypes.isEmpty + + super.init(name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric) + + if let rawTypeName = rawTypeName?.name, let index = self.inheritedTypes.firstIndex(of: rawTypeName) { + self.inheritedTypes.remove(at: index) + } } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = super.description - string += ", " - string += "kind = \\(String(describing: self.kind)), " - string += "associatedTypes = \\(String(describing: self.associatedTypes)), " + string.append(", ") + string.append("cases = \\(String(describing: self.cases)), ") + string.append("rawTypeName = \\(String(describing: self.rawTypeName)), ") + string.append("hasAssociatedValues = \\(String(describing: self.hasAssociatedValues))") return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() - guard let castObject = object as? Protocol else { - results.append("Incorrect type ") + guard let castObject = object as? Enum else { + results.append("Incorrect type ") return results } - results.append(contentsOf: DiffableResult(identifier: "associatedTypes").trackDifference(actual: self.associatedTypes, expected: castObject.associatedTypes)) + results.append(contentsOf: DiffableResult(identifier: "cases").trackDifference(actual: self.cases, expected: castObject.cases)) + results.append(contentsOf: DiffableResult(identifier: "rawTypeName").trackDifference(actual: self.rawTypeName, expected: castObject.rawTypeName)) results.append(contentsOf: super.diffAgainst(castObject)) return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() - hasher.combine(self.associatedTypes) + hasher.combine(self.cases) + hasher.combine(self.rawTypeName) hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? Protocol else { return false } - if self.associatedTypes != rhs.associatedTypes { return false } + guard let rhs = object as? Enum else { return false } + if self.cases != rhs.cases { return false } + if self.rawTypeName != rhs.rawTypeName { return false } return super.isEqual(rhs) } -// sourcery:inline:Protocol.AutoCoding +// sourcery:inline:Enum.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let associatedTypes: [String: AssociatedType] = aDecoder.decode(forKey: "associatedTypes") else { - withVaList(["associatedTypes"]) { arguments in + guard let cases: [EnumCase] = aDecoder.decode(forKey: "cases") else { + withVaList(["cases"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.associatedTypes = associatedTypes + }; self.cases = cases + self.rawTypeName = aDecoder.decode(forKey: "rawTypeName") + self.hasRawType = aDecoder.decode(forKey: "hasRawType") + self.rawType = aDecoder.decode(forKey: "rawType") super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) - aCoder.encode(self.associatedTypes, forKey: "associatedTypes") + aCoder.encode(self.cases, forKey: "cases") + aCoder.encode(self.rawTypeName, forKey: "rawTypeName") + aCoder.encode(self.hasRawType, forKey: "hasRawType") + aCoder.encode(self.rawType, forKey: "rawType") } // sourcery:end } +#endif """), - .init(name: "ProtocolComposition.swift", content: + .init(name: "EnumCase.swift", content: """ -// Created by eric_horacek on 2/12/20. -// Copyright © 2020 Airbnb Inc. All rights reserved. - +// +// Created by Krzysztof Zablocki on 13/09/2016. +// Copyright (c) 2016 Pixle. All rights reserved. +// +#if canImport(ObjectiveC) import Foundation -// sourcery: skipJSExport -/// Describes a Swift [protocol composition](https://docs.swift.org/swift-book/ReferenceManual/Types.html#ID454). +/// Defines enum case @objcMembers -public final class ProtocolComposition: Type { +public final class EnumCase: NSObject, SourceryModel, AutoDescription, Annotated, Documented, Diffable { - /// Returns "protocolComposition" - public override var kind: String { return "protocolComposition" } + /// Enum case name + public let name: String - /// The names of the types composed to form this composition - public let composedTypeNames: [TypeName] + /// Enum case raw value, if any + public let rawValue: String? - // sourcery: skipEquality, skipDescription - /// The types composed to form this composition, if known - public var composedTypes: [Type]? + /// Enum case associated values + public let associatedValues: [AssociatedValue] + + /// Enum case annotations + public var annotations: Annotations = [:] + + public var documentation: Documentation = [] + + /// Whether enum case is indirect + public let indirect: Bool + /// Whether enum case has associated value + public var hasAssociatedValue: Bool { + return !associatedValues.isEmpty + } + + // Underlying parser data, never to be used by anything else + // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: - public init(name: String = "", - parent: Type? = nil, - accessLevel: AccessLevel = .internal, - isExtension: Bool = false, - variables: [Variable] = [], - methods: [Method] = [], - subscripts: [Subscript] = [], - inheritedTypes: [String] = [], - containedTypes: [Type] = [], - typealiases: [Typealias] = [], - attributes: AttributeList = [:], - annotations: [String: NSObject] = [:], - isGeneric: Bool = false, - composedTypeNames: [TypeName] = [], - composedTypes: [Type]? = nil, - implements: [String: Type] = [:]) { - self.composedTypeNames = composedTypeNames - self.composedTypes = composedTypes - super.init( - name: name, - parent: parent, - accessLevel: accessLevel, - isExtension: isExtension, - variables: variables, - methods: methods, - subscripts: subscripts, - inheritedTypes: inheritedTypes, - containedTypes: containedTypes, - typealiases: typealiases, - annotations: annotations, - isGeneric: isGeneric, - implements: implements - ) + public var __parserData: Any? + + /// :nodoc: + public init(name: String, rawValue: String? = nil, associatedValues: [AssociatedValue] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], indirect: Bool = false) { + self.name = name + self.rawValue = rawValue + self.associatedValues = associatedValues + self.annotations = annotations + self.documentation = documentation + self.indirect = indirect } /// :nodoc: + // sourcery: skipJSExport override public var description: String { - var string = super.description - string += ", " - string += "kind = \\(String(describing: self.kind)), " - string += "composedTypeNames = \\(String(describing: self.composedTypeNames))" + var string = "\\(Swift.type(of: self)): " + string.append("name = \\(String(describing: self.name)), ") + string.append("rawValue = \\(String(describing: self.rawValue)), ") + string.append("associatedValues = \\(String(describing: self.associatedValues)), ") + string.append("annotations = \\(String(describing: self.annotations)), ") + string.append("documentation = \\(String(describing: self.documentation)), ") + string.append("indirect = \\(String(describing: self.indirect)), ") + string.append("hasAssociatedValue = \\(String(describing: self.hasAssociatedValue))") return string } - override public func diffAgainst(_ object: Any?) -> DiffableResult { + public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() - guard let castObject = object as? ProtocolComposition else { - results.append("Incorrect type ") + guard let castObject = object as? EnumCase else { + results.append("Incorrect type ") return results } - results.append(contentsOf: DiffableResult(identifier: "composedTypeNames").trackDifference(actual: self.composedTypeNames, expected: castObject.composedTypeNames)) - results.append(contentsOf: super.diffAgainst(castObject)) + results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) + results.append(contentsOf: DiffableResult(identifier: "rawValue").trackDifference(actual: self.rawValue, expected: castObject.rawValue)) + results.append(contentsOf: DiffableResult(identifier: "associatedValues").trackDifference(actual: self.associatedValues, expected: castObject.associatedValues)) + results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) + results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) + results.append(contentsOf: DiffableResult(identifier: "indirect").trackDifference(actual: self.indirect, expected: castObject.indirect)) return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() - hasher.combine(self.composedTypeNames) - hasher.combine(super.hash) + hasher.combine(self.name) + hasher.combine(self.rawValue) + hasher.combine(self.associatedValues) + hasher.combine(self.annotations) + hasher.combine(self.documentation) + hasher.combine(self.indirect) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? ProtocolComposition else { return false } - if self.composedTypeNames != rhs.composedTypeNames { return false } - return super.isEqual(rhs) + guard let rhs = object as? EnumCase else { return false } + if self.name != rhs.name { return false } + if self.rawValue != rhs.rawValue { return false } + if self.associatedValues != rhs.associatedValues { return false } + if self.annotations != rhs.annotations { return false } + if self.documentation != rhs.documentation { return false } + if self.indirect != rhs.indirect { return false } + return true } -// sourcery:inline:ProtocolComposition.AutoCoding +// sourcery:inline:EnumCase.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let composedTypeNames: [TypeName] = aDecoder.decode(forKey: "composedTypeNames") else { - withVaList(["composedTypeNames"]) { arguments in + guard let name: String = aDecoder.decode(forKey: "name") else { + withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.composedTypeNames = composedTypeNames - self.composedTypes = aDecoder.decode(forKey: "composedTypes") - super.init(coder: aDecoder) + }; self.name = name + self.rawValue = aDecoder.decode(forKey: "rawValue") + guard let associatedValues: [AssociatedValue] = aDecoder.decode(forKey: "associatedValues") else { + withVaList(["associatedValues"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.associatedValues = associatedValues + guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { + withVaList(["annotations"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.annotations = annotations + guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { + withVaList(["documentation"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.documentation = documentation + self.indirect = aDecoder.decode(forKey: "indirect") } /// :nodoc: - override public func encode(with aCoder: NSCoder) { - super.encode(with: aCoder) - aCoder.encode(self.composedTypeNames, forKey: "composedTypeNames") - aCoder.encode(self.composedTypes, forKey: "composedTypes") + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.rawValue, forKey: "rawValue") + aCoder.encode(self.associatedValues, forKey: "associatedValues") + aCoder.encode(self.annotations, forKey: "annotations") + aCoder.encode(self.documentation, forKey: "documentation") + aCoder.encode(self.indirect, forKey: "indirect") } // sourcery:end - } +#endif """), - .init(name: "Struct.swift", content: + .init(name: "GenericParameter.swift", content: """ -// -// Struct.swift -// Sourcery -// -// Created by Krzysztof Zablocki on 13/09/2016. -// Copyright © 2016 Pixle. All rights reserved. -// - +#if canImport(ObjectiveC) import Foundation -// sourcery: skipDescription -/// Describes Swift struct +/// Descibes Swift generic parameter @objcMembers -public final class Struct: Type { +public final class GenericParameter: NSObject, SourceryModel, Diffable { - /// Returns "struct" - public override var kind: String { return "struct" } + /// Generic parameter name + public var name: String + + /// Generic parameter inherited type + public var inheritedTypeName: TypeName? /// :nodoc: - public override init(name: String = "", - parent: Type? = nil, - accessLevel: AccessLevel = .internal, - isExtension: Bool = false, - variables: [Variable] = [], - methods: [Method] = [], - subscripts: [Subscript] = [], - inheritedTypes: [String] = [], - containedTypes: [Type] = [], - typealiases: [Typealias] = [], - genericRequirements: [GenericRequirement] = [], - attributes: AttributeList = [:], - modifiers: [SourceryModifier] = [], - annotations: [String: NSObject] = [:], - documentation: [String] = [], - isGeneric: Bool = false, - implements: [String: Type] = [:]) { - super.init( - name: name, - parent: parent, - accessLevel: accessLevel, - isExtension: isExtension, - variables: variables, - methods: methods, - subscripts: subscripts, - inheritedTypes: inheritedTypes, - containedTypes: containedTypes, - typealiases: typealiases, - genericRequirements: genericRequirements, - attributes: attributes, - modifiers: modifiers, - annotations: annotations, - documentation: documentation, - isGeneric: isGeneric, - implements: implements - ) + public init(name: String, inheritedTypeName: TypeName? = nil) { + self.name = name + self.inheritedTypeName = inheritedTypeName } /// :nodoc: + // sourcery: skipJSExport override public var description: String { - var string = super.description - string += ", " - string += "kind = \\(String(describing: self.kind))" + var string = "\\(Swift.type(of: self)): " + string.append("name = \\(String(describing: self.name)), ") + string.append("inheritedTypeName = \\(String(describing: self.inheritedTypeName))") return string } - override public func diffAgainst(_ object: Any?) -> DiffableResult { + public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() - guard let castObject = object as? Struct else { - results.append("Incorrect type ") + guard let castObject = object as? GenericParameter else { + results.append("Incorrect type ") return results } - results.append(contentsOf: super.diffAgainst(castObject)) + results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) + results.append(contentsOf: DiffableResult(identifier: "inheritedTypeName").trackDifference(actual: self.inheritedTypeName, expected: castObject.inheritedTypeName)) return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() - hasher.combine(super.hash) + hasher.combine(self.name) + hasher.combine(self.inheritedTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? Struct else { return false } - return super.isEqual(rhs) + guard let rhs = object as? GenericParameter else { return false } + if self.name != rhs.name { return false } + if self.inheritedTypeName != rhs.inheritedTypeName { return false } + return true } -// sourcery:inline:Struct.AutoCoding +// sourcery:inline:GenericParameter.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) + guard let name: String = aDecoder.decode(forKey: "name") else { + withVaList(["name"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.name = name + self.inheritedTypeName = aDecoder.decode(forKey: "inheritedTypeName") } /// :nodoc: - override public func encode(with aCoder: NSCoder) { - super.encode(with: aCoder) + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.inheritedTypeName, forKey: "inheritedTypeName") } + // sourcery:end } +#endif """), - .init(name: "Subscript.swift", content: -#""" + .init(name: "GenericRequirement.swift", content: +""" +#if canImport(ObjectiveC) import Foundation -/// Describes subscript +/// Descibes Swift generic requirement @objcMembers -public final class Subscript: NSObject, SourceryModel, Annotated, Documented, Definition, Diffable { - - /// Method parameters - public var parameters: [MethodParameter] +public class GenericRequirement: NSObject, SourceryModel, Diffable { - /// Return value type name used in declaration, including generic constraints, i.e. `where T: Equatable` - public var returnTypeName: TypeName + public enum Relationship: String { + case equals + case conformsTo - /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` - public var actualReturnTypeName: TypeName { - return returnTypeName.actualTypeName ?? returnTypeName + var syntax: String { + switch self { + case .equals: + return "==" + case .conformsTo: + return ":" + } + } } - // sourcery: skipEquality, skipDescription - /// Actual return value type, if known - public var returnType: Type? + public var leftType: AssociatedType + public let rightType: GenericTypeParameter - // sourcery: skipEquality, skipDescription - /// Whether return value type is optional - public var isOptionalReturnType: Bool { - return returnTypeName.isOptional - } + /// relationship name + public let relationship: String - // sourcery: skipEquality, skipDescription - /// Whether return value type is implicitly unwrapped optional - public var isImplicitlyUnwrappedOptionalReturnType: Bool { - return returnTypeName.isImplicitlyUnwrappedOptional - } + /// Syntax e.g. `==` or `:` + public let relationshipSyntax: String - // sourcery: skipEquality, skipDescription - /// Return value type name without attributes and optional type information - public var unwrappedReturnTypeName: String { - return returnTypeName.unwrappedTypeName + public init(leftType: AssociatedType, rightType: GenericTypeParameter, relationship: Relationship) { + self.leftType = leftType + self.rightType = rightType + self.relationship = relationship.rawValue + self.relationshipSyntax = relationship.syntax } - /// Whether method is final - public var isFinal: Bool { - modifiers.contains { $0.name == "final" } + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("leftType = \\(String(describing: self.leftType)), ") + string.append("rightType = \\(String(describing: self.rightType)), ") + string.append("relationship = \\(String(describing: self.relationship)), ") + string.append("relationshipSyntax = \\(String(describing: self.relationshipSyntax))") + return string } - /// Variable read access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` - public let readAccess: String - - /// Variable write access, i.e. `internal`, `private`, `fileprivate`, `public`, `open`. - /// For immutable variables this value is empty string - public var writeAccess: String - - /// Whether subscript is async - public let isAsync: Bool + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? GenericRequirement else { + results.append("Incorrect type ") + return results + } + results.append(contentsOf: DiffableResult(identifier: "leftType").trackDifference(actual: self.leftType, expected: castObject.leftType)) + results.append(contentsOf: DiffableResult(identifier: "rightType").trackDifference(actual: self.rightType, expected: castObject.rightType)) + results.append(contentsOf: DiffableResult(identifier: "relationship").trackDifference(actual: self.relationship, expected: castObject.relationship)) + results.append(contentsOf: DiffableResult(identifier: "relationshipSyntax").trackDifference(actual: self.relationshipSyntax, expected: castObject.relationshipSyntax)) + return results + } - /// Whether subscript throws - public let `throws`: Bool + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.leftType) + hasher.combine(self.rightType) + hasher.combine(self.relationship) + hasher.combine(self.relationshipSyntax) + return hasher.finalize() + } - /// Whether variable is mutable or not - public var isMutable: Bool { - return writeAccess != AccessLevel.none.rawValue + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? GenericRequirement else { return false } + if self.leftType != rhs.leftType { return false } + if self.rightType != rhs.rightType { return false } + if self.relationship != rhs.relationship { return false } + if self.relationshipSyntax != rhs.relationshipSyntax { return false } + return true } - /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 - public let annotations: Annotations + // sourcery:inline:GenericRequirement.AutoCoding - public let documentation: Documentation + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let leftType: AssociatedType = aDecoder.decode(forKey: "leftType") else { + withVaList(["leftType"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.leftType = leftType + guard let rightType: GenericTypeParameter = aDecoder.decode(forKey: "rightType") else { + withVaList(["rightType"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.rightType = rightType + guard let relationship: String = aDecoder.decode(forKey: "relationship") else { + withVaList(["relationship"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.relationship = relationship + guard let relationshipSyntax: String = aDecoder.decode(forKey: "relationshipSyntax") else { + withVaList(["relationshipSyntax"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.relationshipSyntax = relationshipSyntax + } - /// Reference to type name where the method is defined, - /// nil if defined outside of any `enum`, `struct`, `class` etc - public let definedInTypeName: TypeName? + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.leftType, forKey: "leftType") + aCoder.encode(self.rightType, forKey: "rightType") + aCoder.encode(self.relationship, forKey: "relationship") + aCoder.encode(self.relationshipSyntax, forKey: "relationshipSyntax") + } + // sourcery:end +} +#endif - /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` - public var actualDefinedInTypeName: TypeName? { - return definedInTypeName?.actualTypeName ?? definedInTypeName - } +"""), + .init(name: "GenericTypeParameter.swift", content: +""" +#if canImport(ObjectiveC) +import Foundation - // sourcery: skipEquality, skipDescription - /// Reference to actual type where the object is defined, - /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown - public var definedInType: Type? +/// Descibes Swift generic type parameter +@objcMembers +public final class GenericTypeParameter: NSObject, SourceryModel, Diffable { - /// Method attributes, i.e. `@discardableResult` - public let attributes: AttributeList + /// Generic parameter type name + public var typeName: TypeName - /// Method modifiers, i.e. `private` - public let modifiers: [SourceryModifier] + // sourcery: skipEquality, skipDescription + /// Generic parameter type, if known + public var type: Type? - /// list of generic parameters - public let genericParameters: [GenericParameter] + /// :nodoc: + public init(typeName: TypeName, type: Type? = nil) { + self.typeName = typeName + self.type = type + } - /// list of generic requirements - public let genericRequirements: [GenericRequirement] + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("typeName = \\(String(describing: self.typeName))") + return string + } - /// Whether subscript is generic or not - public var isGeneric: Bool { - return genericParameters.isEmpty == false + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? GenericTypeParameter else { + results.append("Incorrect type ") + return results + } + results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) + return results } - // Underlying parser data, never to be used by anything else - // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: - public var __parserData: Any? - - /// :nodoc: - public init(parameters: [MethodParameter] = [], - returnTypeName: TypeName, - accessLevel: (read: AccessLevel, write: AccessLevel) = (.internal, .internal), - isAsync: Bool = false, - `throws`: Bool = false, - genericParameters: [GenericParameter] = [], - genericRequirements: [GenericRequirement] = [], - attributes: AttributeList = [:], - modifiers: [SourceryModifier] = [], - annotations: [String: NSObject] = [:], - documentation: [String] = [], - definedInTypeName: TypeName? = nil) { - - self.parameters = parameters - self.returnTypeName = returnTypeName - self.readAccess = accessLevel.read.rawValue - self.writeAccess = accessLevel.write.rawValue - self.isAsync = isAsync - self.throws = `throws` - self.genericParameters = genericParameters - self.genericRequirements = genericRequirements - self.attributes = attributes - self.modifiers = modifiers - self.annotations = annotations - self.documentation = documentation - self.definedInTypeName = definedInTypeName - } - - /// :nodoc: - override public var description: String { - var string = "\(Swift.type(of: self)): " - string += "parameters = \(String(describing: self.parameters)), " - string += "returnTypeName = \(String(describing: self.returnTypeName)), " - string += "actualReturnTypeName = \(String(describing: self.actualReturnTypeName)), " - string += "isFinal = \(String(describing: self.isFinal)), " - string += "readAccess = \(String(describing: self.readAccess)), " - string += "writeAccess = \(String(describing: self.writeAccess)), " - string += "isAsync = \(String(describing: self.isAsync)), " - string += "`throws` = \(String(describing: self.throws)), " - string += "isMutable = \(String(describing: self.isMutable)), " - string += "annotations = \(String(describing: self.annotations)), " - string += "documentation = \(String(describing: self.documentation)), " - string += "definedInTypeName = \(String(describing: self.definedInTypeName)), " - string += "actualDefinedInTypeName = \(String(describing: self.actualDefinedInTypeName)), " - string += "genericParameters = \(String(describing: self.genericParameters)), " - string += "genericRequirements = \(String(describing: self.genericRequirements)), " - string += "isGeneric = \(String(describing: self.isGeneric)), " - string += "attributes = \(String(describing: self.attributes)), " - string += "modifiers = \(String(describing: self.modifiers))" - return string - } - - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? Subscript else { - results.append("Incorrect type ") - return results - } - results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) - results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) - results.append(contentsOf: DiffableResult(identifier: "readAccess").trackDifference(actual: self.readAccess, expected: castObject.readAccess)) - results.append(contentsOf: DiffableResult(identifier: "writeAccess").trackDifference(actual: self.writeAccess, expected: castObject.writeAccess)) - results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) - results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.throws, expected: castObject.throws)) - results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) - results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) - results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) - results.append(contentsOf: DiffableResult(identifier: "genericParameters").trackDifference(actual: self.genericParameters, expected: castObject.genericParameters)) - results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) - results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) - results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) - return results - } - + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() - hasher.combine(self.parameters) - hasher.combine(self.returnTypeName) - hasher.combine(self.readAccess) - hasher.combine(self.writeAccess) - hasher.combine(self.isAsync) - hasher.combine(self.throws) - hasher.combine(self.annotations) - hasher.combine(self.documentation) - hasher.combine(self.definedInTypeName) - hasher.combine(self.genericParameters) - hasher.combine(self.genericRequirements) - hasher.combine(self.attributes) - hasher.combine(self.modifiers) + hasher.combine(self.typeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? Subscript else { return false } - if self.parameters != rhs.parameters { return false } - if self.returnTypeName != rhs.returnTypeName { return false } - if self.readAccess != rhs.readAccess { return false } - if self.writeAccess != rhs.writeAccess { return false } - if self.isAsync != rhs.isAsync { return false } - if self.throws != rhs.throws { return false } - if self.annotations != rhs.annotations { return false } - if self.documentation != rhs.documentation { return false } - if self.definedInTypeName != rhs.definedInTypeName { return false } - if self.genericParameters != rhs.genericParameters { return false } - if self.genericRequirements != rhs.genericRequirements { return false } - if self.attributes != rhs.attributes { return false } - if self.modifiers != rhs.modifiers { return false } + guard let rhs = object as? GenericTypeParameter else { return false } + if self.typeName != rhs.typeName { return false } return true } -// sourcery:inline:Subscript.AutoCoding +// sourcery:inline:GenericTypeParameter.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let parameters: [MethodParameter] = aDecoder.decode(forKey: "parameters") else { - withVaList(["parameters"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.parameters = parameters - guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { - withVaList(["returnTypeName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.returnTypeName = returnTypeName - self.returnType = aDecoder.decode(forKey: "returnType") - guard let readAccess: String = aDecoder.decode(forKey: "readAccess") else { - withVaList(["readAccess"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.readAccess = readAccess - guard let writeAccess: String = aDecoder.decode(forKey: "writeAccess") else { - withVaList(["writeAccess"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.writeAccess = writeAccess - guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { - withVaList(["annotations"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.annotations = annotations - guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { - withVaList(["documentation"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.documentation = documentation - self.isAsync = aDecoder.decode(forKey: "isAsync") - self.`throws` = aDecoder.decode(forKey: "`throws`") - self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") - self.definedInType = aDecoder.decode(forKey: "definedInType") - guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { - withVaList(["attributes"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.attributes = attributes - guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { - withVaList(["modifiers"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.modifiers = modifiers - guard let genericParameters: [GenericParameter] = aDecoder.decode(forKey: "genericParameters") else { - withVaList(["genericParameters"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.genericParameters = genericParameters - guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { - withVaList(["genericRequirements"]) { arguments in + guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { + withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.genericRequirements = genericRequirements + }; self.typeName = typeName + self.type = aDecoder.decode(forKey: "type") } /// :nodoc: public func encode(with aCoder: NSCoder) { - aCoder.encode(self.parameters, forKey: "parameters") - aCoder.encode(self.returnTypeName, forKey: "returnTypeName") - aCoder.encode(self.returnType, forKey: "returnType") - aCoder.encode(self.readAccess, forKey: "readAccess") - aCoder.encode(self.writeAccess, forKey: "writeAccess") - aCoder.encode(self.isAsync, forKey: "isAsync") - aCoder.encode(self.`throws`, forKey: "`throws`") - aCoder.encode(self.annotations, forKey: "annotations") - aCoder.encode(self.documentation, forKey: "documentation") - aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") - aCoder.encode(self.definedInType, forKey: "definedInType") - aCoder.encode(self.genericParameters, forKey: "genericParameters") - aCoder.encode(self.genericRequirements, forKey: "genericRequirements") - aCoder.encode(self.attributes, forKey: "attributes") - aCoder.encode(self.modifiers, forKey: "modifiers") + aCoder.encode(self.typeName, forKey: "typeName") + aCoder.encode(self.type, forKey: "type") } -// sourcery:end +// sourcery:end } +#endif -"""#), - .init(name: "TemplateContext.swift", content: +"""), + .init(name: "Method.swift", content: """ -// -// Created by Krzysztof Zablocki on 31/12/2016. -// Copyright (c) 2016 Pixle. All rights reserved. -// - +#if canImport(ObjectiveC) import Foundation /// :nodoc: -// sourcery: skipCoding -@objcMembers -public final class TemplateContext: NSObject, SourceryModel, NSCoding, Diffable { - // sourcery: skipJSExport - public let parserResult: FileParserResult? - public let functions: [SourceryMethod] - public let types: Types - public let argument: [String: NSObject] +public typealias SourceryMethod = Method - // sourcery: skipDescription - public var type: [String: Type] { - return types.typesByName - } +/// Describes method +@objc(SwiftMethod) @objcMembers +public final class Method: NSObject, SourceryModel, Annotated, Documented, Definition, Diffable { - public init(parserResult: FileParserResult?, types: Types, functions: [SourceryMethod], arguments: [String: NSObject]) { - self.parserResult = parserResult - self.types = types - self.functions = functions - self.argument = arguments + /// Full method name, including generic constraints, i.e. `foo(bar: T)` + public let name: String + + /// Method name including arguments names, i.e. `foo(bar:)` + public var selectorName: String + + // sourcery: skipEquality, skipDescription + /// Method name without arguments names and parenthesis, i.e. `foo` + public var shortName: String { + return name.range(of: "(").map({ String(name[..<$0.lowerBound]) }) ?? name } - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let parserResult: FileParserResult = aDecoder.decode(forKey: "parserResult") else { - withVaList(["parserResult"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found. FileParserResults are required for template context that needs persisting.", arguments: arguments) - } - fatalError() - } - guard let argument: [String: NSObject] = aDecoder.decode(forKey: "argument") else { - withVaList(["argument"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - } + // sourcery: skipEquality, skipDescription + /// Method name without arguments names, parenthesis and generic types, i.e. `foo` (can be used to generate code for method call) + public var callName: String { + return shortName.range(of: "<").map({ String(shortName[..<$0.lowerBound]) }) ?? shortName + } - // if we want to support multiple cycles of encode / decode we need deep copy because composer changes reference types - let fileParserResultCopy: FileParserResult? = nil -// fileParserResultCopy = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(NSKeyedArchiver.archivedData(withRootObject: parserResult)) as? FileParserResult + /// Method parameters + public var parameters: [MethodParameter] - let composed = Composer.uniqueTypesAndFunctions(parserResult) - self.types = .init(types: composed.types, typealiases: composed.typealiases) - self.functions = composed.functions + /// Return value type name used in declaration, including generic constraints, i.e. `where T: Equatable` + public var returnTypeName: TypeName - self.parserResult = fileParserResultCopy - self.argument = argument + // sourcery: skipEquality, skipDescription + /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` + public var actualReturnTypeName: TypeName { + return returnTypeName.actualTypeName ?? returnTypeName } - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.parserResult, forKey: "parserResult") - aCoder.encode(self.argument, forKey: "argument") - } + // sourcery: skipEquality, skipDescription + /// Actual return value type, if known + public var returnType: Type? - public var stencilContext: [String: Any] { - return [ - "types": types, - "functions": functions, - "type": types.typesByName, - "argument": argument - ] + // sourcery: skipEquality, skipDescription + /// Whether return value type is optional + public var isOptionalReturnType: Bool { + return returnTypeName.isOptional || isFailableInitializer } - /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "parserResult = \\(String(describing: self.parserResult)), " - string += "functions = \\(String(describing: self.functions)), " - string += "types = \\(String(describing: self.types)), " - string += "argument = \\(String(describing: self.argument)), " - string += "stencilContext = \\(String(describing: self.stencilContext))" - return string + // sourcery: skipEquality, skipDescription + /// Whether return value type is implicitly unwrapped optional + public var isImplicitlyUnwrappedOptionalReturnType: Bool { + return returnTypeName.isImplicitlyUnwrappedOptional } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? TemplateContext else { - results.append("Incorrect type ") - return results - } - results.append(contentsOf: DiffableResult(identifier: "parserResult").trackDifference(actual: self.parserResult, expected: castObject.parserResult)) - results.append(contentsOf: DiffableResult(identifier: "functions").trackDifference(actual: self.functions, expected: castObject.functions)) - results.append(contentsOf: DiffableResult(identifier: "types").trackDifference(actual: self.types, expected: castObject.types)) - results.append(contentsOf: DiffableResult(identifier: "argument").trackDifference(actual: self.argument, expected: castObject.argument)) - return results + // sourcery: skipEquality, skipDescription + /// Return value type name without attributes and optional type information + public var unwrappedReturnTypeName: String { + return returnTypeName.unwrappedTypeName } - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.parserResult) - hasher.combine(self.functions) - hasher.combine(self.types) - hasher.combine(self.argument) - return hasher.finalize() + /// Whether method is async method + public let isAsync: Bool + + /// Whether method throws + public let `throws`: Bool + + /// Whether method rethrows + public let `rethrows`: Bool + + /// Method access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` + public let accessLevel: String + + /// Whether method is a static method + public let isStatic: Bool + + /// Whether method is a class method + public let isClass: Bool + + // sourcery: skipEquality, skipDescription + /// Whether method is an initializer + public var isInitializer: Bool { + return selectorName.hasPrefix("init(") || selectorName == "init" } - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? TemplateContext else { return false } - if self.parserResult != rhs.parserResult { return false } - if self.functions != rhs.functions { return false } - if self.types != rhs.types { return false } - if self.argument != rhs.argument { return false } - return true + // sourcery: skipEquality, skipDescription + /// Whether method is an deinitializer + public var isDeinitializer: Bool { + return selectorName == "deinit" } - // sourcery: skipDescription, skipEquality - public var jsContext: [String: Any] { - return [ - "types": [ - "all": types.all, - "protocols": types.protocols, - "classes": types.classes, - "structs": types.structs, - "enums": types.enums, - "extensions": types.extensions, - "based": types.based, - "inheriting": types.inheriting, - "implementing": types.implementing - ] as [String : Any], - "functions": functions, - "type": types.typesByName, - "argument": argument - ] + /// Whether method is a failable initializer + public let isFailableInitializer: Bool + + // sourcery: skipEquality, skipDescription + /// Whether method is a convenience initializer + public var isConvenienceInitializer: Bool { + modifiers.contains { $0.name == Attribute.Identifier.convenience.rawValue } } -} + // sourcery: skipEquality, skipDescription + /// Whether method is required + public var isRequired: Bool { + modifiers.contains { $0.name == Attribute.Identifier.required.rawValue } + } -extension ProcessInfo { - /// :nodoc: - public var context: TemplateContext! { - return NSKeyedUnarchiver.unarchiveObject(withFile: arguments[1]) as? TemplateContext + // sourcery: skipEquality, skipDescription + /// Whether method is final + public var isFinal: Bool { + modifiers.contains { $0.name == Attribute.Identifier.final.rawValue } } -} -"""), - .init(name: "Types.swift", content: -""" -import Foundation + // sourcery: skipEquality, skipDescription + /// Whether method is mutating + public var isMutating: Bool { + modifiers.contains { $0.name == Attribute.Identifier.mutating.rawValue } + } -// sourcery: skipJSExport -/// Collection of scanned types for accessing in templates -@objcMembers -public final class Types: NSObject, SourceryModel, Diffable { + // sourcery: skipEquality, skipDescription + /// Whether method is generic + public var isGeneric: Bool { + shortName.hasSuffix(">") + } + + // sourcery: skipEquality, skipDescription + /// Whether method is optional (in an Objective-C protocol) + public var isOptional: Bool { + modifiers.contains { $0.name == Attribute.Identifier.optional.rawValue } + } + + // sourcery: skipEquality, skipDescription + /// Whether method is nonisolated (this modifier only applies to actor methods) + public var isNonisolated: Bool { + modifiers.contains { $0.name == Attribute.Identifier.nonisolated.rawValue } + } + + // sourcery: skipEquality, skipDescription + /// Whether method is dynamic + public var isDynamic: Bool { + modifiers.contains { $0.name == Attribute.Identifier.dynamic.rawValue } + } + + /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 + public let annotations: Annotations + + public let documentation: Documentation + + /// Reference to type name where the method is defined, + /// nil if defined outside of any `enum`, `struct`, `class` etc + public let definedInTypeName: TypeName? + + // sourcery: skipEquality, skipDescription + /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` + public var actualDefinedInTypeName: TypeName? { + return definedInTypeName?.actualTypeName ?? definedInTypeName + } + + // sourcery: skipEquality, skipDescription + /// Reference to actual type where the object is defined, + /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown + public var definedInType: Type? + + /// Method attributes, i.e. `@discardableResult` + public let attributes: AttributeList + + /// Method modifiers, i.e. `private` + public let modifiers: [SourceryModifier] + // Underlying parser data, never to be used by anything else + // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: - public let types: [Type] + public var __parserData: Any? - /// All known typealiases - public let typealiases: [Typealias] + /// list of generic requirements + public var genericRequirements: [GenericRequirement] /// :nodoc: - public init(types: [Type], typealiases: [Typealias] = []) { - self.types = types - self.typealiases = typealiases + public init(name: String, + selectorName: String? = nil, + parameters: [MethodParameter] = [], + returnTypeName: TypeName = TypeName(name: "Void"), + isAsync: Bool = false, + throws: Bool = false, + rethrows: Bool = false, + accessLevel: AccessLevel = .internal, + isStatic: Bool = false, + isClass: Bool = false, + isFailableInitializer: Bool = false, + attributes: AttributeList = [:], + modifiers: [SourceryModifier] = [], + annotations: [String: NSObject] = [:], + documentation: [String] = [], + definedInTypeName: TypeName? = nil, + genericRequirements: [GenericRequirement] = []) { + self.name = name + self.selectorName = selectorName ?? name + self.parameters = parameters + self.returnTypeName = returnTypeName + self.isAsync = isAsync + self.throws = `throws` + self.rethrows = `rethrows` + self.accessLevel = accessLevel.rawValue + self.isStatic = isStatic + self.isClass = isClass + self.isFailableInitializer = isFailableInitializer + self.attributes = attributes + self.modifiers = modifiers + self.annotations = annotations + self.documentation = documentation + self.definedInTypeName = definedInTypeName + self.genericRequirements = genericRequirements } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " - string += "types = \\(String(describing: self.types)), " - string += "typealiases = \\(String(describing: self.typealiases))" + string.append("name = \\(String(describing: self.name)), ") + string.append("selectorName = \\(String(describing: self.selectorName)), ") + string.append("parameters = \\(String(describing: self.parameters)), ") + string.append("returnTypeName = \\(String(describing: self.returnTypeName)), ") + string.append("isAsync = \\(String(describing: self.isAsync)), ") + string.append("`throws` = \\(String(describing: self.`throws`)), ") + string.append("`rethrows` = \\(String(describing: self.`rethrows`)), ") + string.append("accessLevel = \\(String(describing: self.accessLevel)), ") + string.append("isStatic = \\(String(describing: self.isStatic)), ") + string.append("isClass = \\(String(describing: self.isClass)), ") + string.append("isFailableInitializer = \\(String(describing: self.isFailableInitializer)), ") + string.append("annotations = \\(String(describing: self.annotations)), ") + string.append("documentation = \\(String(describing: self.documentation)), ") + string.append("definedInTypeName = \\(String(describing: self.definedInTypeName)), ") + string.append("attributes = \\(String(describing: self.attributes)), ") + string.append("modifiers = \\(String(describing: self.modifiers)), ") + string.append("genericRequirements = \\(String(describing: self.genericRequirements))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() - guard let castObject = object as? Types else { - results.append("Incorrect type ") + guard let castObject = object as? Method else { + results.append("Incorrect type ") return results } - results.append(contentsOf: DiffableResult(identifier: "types").trackDifference(actual: self.types, expected: castObject.types)) - results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) + results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) + results.append(contentsOf: DiffableResult(identifier: "selectorName").trackDifference(actual: self.selectorName, expected: castObject.selectorName)) + results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) + results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) + results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) + results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) + results.append(contentsOf: DiffableResult(identifier: "`rethrows`").trackDifference(actual: self.`rethrows`, expected: castObject.`rethrows`)) + results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) + results.append(contentsOf: DiffableResult(identifier: "isStatic").trackDifference(actual: self.isStatic, expected: castObject.isStatic)) + results.append(contentsOf: DiffableResult(identifier: "isClass").trackDifference(actual: self.isClass, expected: castObject.isClass)) + results.append(contentsOf: DiffableResult(identifier: "isFailableInitializer").trackDifference(actual: self.isFailableInitializer, expected: castObject.isFailableInitializer)) + results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) + results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) + results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) + results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) + results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) + results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() - hasher.combine(self.types) - hasher.combine(self.typealiases) + hasher.combine(self.name) + hasher.combine(self.selectorName) + hasher.combine(self.parameters) + hasher.combine(self.returnTypeName) + hasher.combine(self.isAsync) + hasher.combine(self.`throws`) + hasher.combine(self.`rethrows`) + hasher.combine(self.accessLevel) + hasher.combine(self.isStatic) + hasher.combine(self.isClass) + hasher.combine(self.isFailableInitializer) + hasher.combine(self.annotations) + hasher.combine(self.documentation) + hasher.combine(self.definedInTypeName) + hasher.combine(self.attributes) + hasher.combine(self.modifiers) + hasher.combine(self.genericRequirements) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? Types else { return false } - if self.types != rhs.types { return false } - if self.typealiases != rhs.typealiases { return false } - return true + guard let rhs = object as? Method else { return false } + if self.name != rhs.name { return false } + if self.selectorName != rhs.selectorName { return false } + if self.parameters != rhs.parameters { return false } + if self.returnTypeName != rhs.returnTypeName { return false } + if self.isAsync != rhs.isAsync { return false } + if self.`throws` != rhs.`throws` { return false } + if self.`rethrows` != rhs.`rethrows` { return false } + if self.accessLevel != rhs.accessLevel { return false } + if self.isStatic != rhs.isStatic { return false } + if self.isClass != rhs.isClass { return false } + if self.isFailableInitializer != rhs.isFailableInitializer { return false } + if self.annotations != rhs.annotations { return false } + if self.documentation != rhs.documentation { return false } + if self.definedInTypeName != rhs.definedInTypeName { return false } + if self.attributes != rhs.attributes { return false } + if self.modifiers != rhs.modifiers { return false } + if self.genericRequirements != rhs.genericRequirements { return false } + return true } -// sourcery:inline:Types.AutoCoding +// sourcery:inline:Method.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let types: [Type] = aDecoder.decode(forKey: "types") else { - withVaList(["types"]) { arguments in + guard let name: String = aDecoder.decode(forKey: "name") else { + withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.types = types - guard let typealiases: [Typealias] = aDecoder.decode(forKey: "typealiases") else { - withVaList(["typealiases"]) { arguments in + }; self.name = name + guard let selectorName: String = aDecoder.decode(forKey: "selectorName") else { + withVaList(["selectorName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.typealiases = typealiases + }; self.selectorName = selectorName + guard let parameters: [MethodParameter] = aDecoder.decode(forKey: "parameters") else { + withVaList(["parameters"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.parameters = parameters + guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { + withVaList(["returnTypeName"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.returnTypeName = returnTypeName + self.returnType = aDecoder.decode(forKey: "returnType") + self.isAsync = aDecoder.decode(forKey: "isAsync") + self.`throws` = aDecoder.decode(forKey: "`throws`") + self.`rethrows` = aDecoder.decode(forKey: "`rethrows`") + guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { + withVaList(["accessLevel"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.accessLevel = accessLevel + self.isStatic = aDecoder.decode(forKey: "isStatic") + self.isClass = aDecoder.decode(forKey: "isClass") + self.isFailableInitializer = aDecoder.decode(forKey: "isFailableInitializer") + guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { + withVaList(["annotations"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.annotations = annotations + guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { + withVaList(["documentation"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.documentation = documentation + self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") + self.definedInType = aDecoder.decode(forKey: "definedInType") + guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { + withVaList(["attributes"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.attributes = attributes + guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { + withVaList(["modifiers"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.modifiers = modifiers + guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { + withVaList(["genericRequirements"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.genericRequirements = genericRequirements } /// :nodoc: public func encode(with aCoder: NSCoder) { - aCoder.encode(self.types, forKey: "types") - aCoder.encode(self.typealiases, forKey: "typealiases") + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.selectorName, forKey: "selectorName") + aCoder.encode(self.parameters, forKey: "parameters") + aCoder.encode(self.returnTypeName, forKey: "returnTypeName") + aCoder.encode(self.returnType, forKey: "returnType") + aCoder.encode(self.isAsync, forKey: "isAsync") + aCoder.encode(self.`throws`, forKey: "`throws`") + aCoder.encode(self.`rethrows`, forKey: "`rethrows`") + aCoder.encode(self.accessLevel, forKey: "accessLevel") + aCoder.encode(self.isStatic, forKey: "isStatic") + aCoder.encode(self.isClass, forKey: "isClass") + aCoder.encode(self.isFailableInitializer, forKey: "isFailableInitializer") + aCoder.encode(self.annotations, forKey: "annotations") + aCoder.encode(self.documentation, forKey: "documentation") + aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") + aCoder.encode(self.definedInType, forKey: "definedInType") + aCoder.encode(self.attributes, forKey: "attributes") + aCoder.encode(self.modifiers, forKey: "modifiers") + aCoder.encode(self.genericRequirements, forKey: "genericRequirements") } // sourcery:end +} +#endif - // sourcery: skipDescription, skipEquality, skipCoding - /// :nodoc: - public lazy internal(set) var typesByName: [String: Type] = { - var typesByName = [String: Type]() - self.types.forEach { typesByName[$0.globalName] = $0 } - return typesByName - }() +"""), + .init(name: "MethodParameter.swift", content: +""" +#if canImport(ObjectiveC) +import Foundation - // sourcery: skipDescription, skipEquality, skipCoding - /// :nodoc: - public lazy internal(set) var typesaliasesByName: [String: Typealias] = { - var typesaliasesByName = [String: Typealias]() - self.typealiases.forEach { typesaliasesByName[$0.name] = $0 } - return typesaliasesByName - }() +/// Describes method parameter +@objcMembers +public class MethodParameter: NSObject, SourceryModel, Typed, Annotated, Diffable { + /// Parameter external name + public var argumentLabel: String? - // sourcery: skipDescription, skipEquality, skipCoding - /// All known types, excluding protocols or protocol compositions. - public lazy internal(set) var all: [Type] = { - return self.types.filter { !($0 is Protocol || $0 is ProtocolComposition) } - }() + // Note: although method parameter can have no name, this property is not optional, + // this is so to maintain compatibility with existing templates. + /// Parameter internal name + public let name: String - // sourcery: skipDescription, skipEquality, skipCoding - /// All known protocols - public lazy internal(set) var protocols: [Protocol] = { - return self.types.compactMap { $0 as? Protocol } - }() + /// Parameter type name + public let typeName: TypeName - // sourcery: skipDescription, skipEquality, skipCoding - /// All known protocol compositions - public lazy internal(set) var protocolCompositions: [ProtocolComposition] = { - return self.types.compactMap { $0 as? ProtocolComposition } - }() + /// Parameter flag whether it's inout or not + public let `inout`: Bool + + /// Is this variadic parameter? + public let isVariadic: Bool - // sourcery: skipDescription, skipEquality, skipCoding - /// All known classes - public lazy internal(set) var classes: [Class] = { - return self.all.compactMap { $0 as? Class } - }() + // sourcery: skipEquality, skipDescription + /// Parameter type, if known + public var type: Type? - // sourcery: skipDescription, skipEquality, skipCoding - /// All known structs - public lazy internal(set) var structs: [Struct] = { - return self.all.compactMap { $0 as? Struct } - }() + /// Parameter type attributes, i.e. `@escaping` + public var typeAttributes: AttributeList { + return typeName.attributes + } - // sourcery: skipDescription, skipEquality, skipCoding - /// All known enums - public lazy internal(set) var enums: [Enum] = { - return self.all.compactMap { $0 as? Enum } - }() + /// Method parameter default value expression + public var defaultValue: String? - // sourcery: skipDescription, skipEquality, skipCoding - /// All known extensions - public lazy internal(set) var extensions: [Type] = { - return self.all.compactMap { $0.isExtension ? $0 : nil } - }() + /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 + public var annotations: Annotations = [:] - // sourcery: skipDescription, skipEquality, skipCoding - /// Types based on any other type, grouped by its name, even if they are not known. - /// `types.based.MyType` returns list of types based on `MyType` - public lazy internal(set) var based: TypesCollection = { - TypesCollection( - types: self.types, - collection: { Array($0.based.keys) } - ) - }() + /// :nodoc: + public init(argumentLabel: String?, name: String = "", typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false, isVariadic: Bool = false) { + self.typeName = typeName + self.argumentLabel = argumentLabel + self.name = name + self.type = type + self.defaultValue = defaultValue + self.annotations = annotations + self.`inout` = isInout + self.isVariadic = isVariadic + } - // sourcery: skipDescription, skipEquality, skipCoding - /// Classes inheriting from any known class, grouped by its name. - /// `types.inheriting.MyClass` returns list of types inheriting from `MyClass` - public lazy internal(set) var inheriting: TypesCollection = { - TypesCollection( - types: self.types, - collection: { Array($0.inherits.keys) }, - validate: { type in - guard type is Class else { - throw "\\(type.name) is not a class and should be used with `implementing` or `based`" - } - }) - }() + /// :nodoc: + public init(name: String = "", typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false, isVariadic: Bool = false) { + self.typeName = typeName + self.argumentLabel = name + self.name = name + self.type = type + self.defaultValue = defaultValue + self.annotations = annotations + self.`inout` = isInout + self.isVariadic = isVariadic + } - // sourcery: skipDescription, skipEquality, skipCoding - /// Types implementing known protocol, grouped by its name. - /// `types.implementing.MyProtocol` returns list of types implementing `MyProtocol` - public lazy internal(set) var implementing: TypesCollection = { - TypesCollection( - types: self.types, - collection: { Array($0.implements.keys) }, - validate: { type in - guard type is Protocol else { - throw "\\(type.name) is a class and should be used with `inheriting` or `based`" - } - }) - }() -} + public var asSource: String { + let values: String = defaultValue.map { " = \\($0)" } ?? "" + let variadicity: String = isVariadic ? "..." : "" + let inoutness: String = `inout` ? "inout " : "" + let typeSuffix = ": \\(inoutness)\\(typeName.asSource)\\(values)\\(variadicity)" + guard argumentLabel != name else { + return name + typeSuffix + } -"""), - .init(name: "TypesCollection.swift", content: -""" -import Foundation + let labels = [argumentLabel ?? "_", name.nilIfEmpty] + .compactMap { $0 } + .joined(separator: " ") -/// :nodoc: -@objcMembers -public class TypesCollection: NSObject, AutoJSExport { - // sourcery:begin: skipJSExport - let all: [Type] - let types: [String: [Type]] - let validate: ((Type) throws -> Void)? - // sourcery:end - - init(types: [Type], collection: (Type) -> [String], validate: ((Type) throws -> Void)? = nil) { - self.all = types - var content = [String: [Type]]() - self.all.forEach { type in - collection(type).forEach { name in - var list = content[name] ?? [Type]() - list.append(type) - content[name] = list - } - } - self.types = content - self.validate = validate - } - - public func types(forKey key: String) throws -> [Type] { - // In some configurations, the types are keyed by "ModuleName.TypeName" - var longKey: String? - - if let validate = validate { - guard let type = all.first(where: { $0.name == key }) else { - throw "Unknown type \\(key), should be used with `based`" - } - - try validate(type) - - if let module = type.module { - longKey = [module, type.name].joined(separator: ".") - } - } - - // If we find the types directly, return them - if let types = types[key] { - return types - } - - // if we find a types for the longKey, return them - if let longKey = longKey, let types = types[longKey] { - return types - } - - return [] - } - - /// :nodoc: - override public func value(forKey key: String) -> Any? { - do { - return try types(forKey: key) - } catch { - Log.error(error) - return nil - } - } - - /// :nodoc: - public subscript(_ key: String) -> [Type] { - do { - return try types(forKey: key) - } catch { - Log.error(error) - return [] - } - } - - override public func responds(to aSelector: Selector!) -> Bool { - return true - } -} - -"""), - .init(name: "Tuple.swift", content: -""" -import Foundation - -/// Describes tuple type -@objcMembers -public final class TupleType: NSObject, SourceryModel, Diffable { - - /// Type name used in declaration - public var name: String - - /// Tuple elements - public var elements: [TupleElement] - - /// :nodoc: - public init(name: String, elements: [TupleElement]) { - self.name = name - self.elements = elements - } - - /// :nodoc: - public init(elements: [TupleElement]) { - self.name = elements.asSource - self.elements = elements + return (labels.nilIfEmpty ?? "_") + typeSuffix } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " - string += "name = \\(String(describing: self.name)), " - string += "elements = \\(String(describing: self.elements))" + string.append("argumentLabel = \\(String(describing: self.argumentLabel)), ") + string.append("name = \\(String(describing: self.name)), ") + string.append("typeName = \\(String(describing: self.typeName)), ") + string.append("`inout` = \\(String(describing: self.`inout`)), ") + string.append("isVariadic = \\(String(describing: self.isVariadic)), ") + string.append("typeAttributes = \\(String(describing: self.typeAttributes)), ") + string.append("defaultValue = \\(String(describing: self.defaultValue)), ") + string.append("annotations = \\(String(describing: self.annotations)), ") + string.append("asSource = \\(String(describing: self.asSource))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() - guard let castObject = object as? TupleType else { - results.append("Incorrect type ") + guard let castObject = object as? MethodParameter else { + results.append("Incorrect type ") return results } + results.append(contentsOf: DiffableResult(identifier: "argumentLabel").trackDifference(actual: self.argumentLabel, expected: castObject.argumentLabel)) results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "elements").trackDifference(actual: self.elements, expected: castObject.elements)) + results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) + results.append(contentsOf: DiffableResult(identifier: "`inout`").trackDifference(actual: self.`inout`, expected: castObject.`inout`)) + results.append(contentsOf: DiffableResult(identifier: "isVariadic").trackDifference(actual: self.isVariadic, expected: castObject.isVariadic)) + results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) + results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() + hasher.combine(self.argumentLabel) hasher.combine(self.name) - hasher.combine(self.elements) + hasher.combine(self.typeName) + hasher.combine(self.`inout`) + hasher.combine(self.isVariadic) + hasher.combine(self.defaultValue) + hasher.combine(self.annotations) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? TupleType else { return false } + guard let rhs = object as? MethodParameter else { return false } + if self.argumentLabel != rhs.argumentLabel { return false } if self.name != rhs.name { return false } - if self.elements != rhs.elements { return false } + if self.typeName != rhs.typeName { return false } + if self.`inout` != rhs.`inout` { return false } + if self.isVariadic != rhs.isVariadic { return false } + if self.defaultValue != rhs.defaultValue { return false } + if self.annotations != rhs.annotations { return false } return true } -// sourcery:inline:TupleType.AutoCoding +// sourcery:inline:MethodParameter.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { + self.argumentLabel = aDecoder.decode(forKey: "argumentLabel") + guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name - guard let elements: [TupleElement] = aDecoder.decode(forKey: "elements") else { - withVaList(["elements"]) { arguments in + guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { + withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.elements = elements + }; self.typeName = typeName + self.`inout` = aDecoder.decode(forKey: "`inout`") + self.isVariadic = aDecoder.decode(forKey: "isVariadic") + self.type = aDecoder.decode(forKey: "type") + self.defaultValue = aDecoder.decode(forKey: "defaultValue") + guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { + withVaList(["annotations"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.annotations = annotations } /// :nodoc: public func encode(with aCoder: NSCoder) { + aCoder.encode(self.argumentLabel, forKey: "argumentLabel") aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.elements, forKey: "elements") + aCoder.encode(self.typeName, forKey: "typeName") + aCoder.encode(self.`inout`, forKey: "`inout`") + aCoder.encode(self.isVariadic, forKey: "isVariadic") + aCoder.encode(self.type, forKey: "type") + aCoder.encode(self.defaultValue, forKey: "defaultValue") + aCoder.encode(self.annotations, forKey: "annotations") } // sourcery:end } -/// Describes tuple type element +extension Array where Element == MethodParameter { + public var asSource: String { + "(\\(map { $0.asSource }.joined(separator: ", ")))" + } +} +#endif + +"""), + .init(name: "Subscript.swift", content: +""" +#if canImport(ObjectiveC) +import Foundation + +/// Describes subscript @objcMembers -public final class TupleElement: NSObject, SourceryModel, Typed, Diffable { +public final class Subscript: NSObject, SourceryModel, Annotated, Documented, Definition, Diffable { + + /// Method parameters + public var parameters: [MethodParameter] - /// Tuple element name - public let name: String? + /// Return value type name used in declaration, including generic constraints, i.e. `where T: Equatable` + public var returnTypeName: TypeName - /// Tuple element type name - public var typeName: TypeName + /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` + public var actualReturnTypeName: TypeName { + return returnTypeName.actualTypeName ?? returnTypeName + } // sourcery: skipEquality, skipDescription - /// Tuple element type, if known - public var type: Type? + /// Actual return value type, if known + public var returnType: Type? - /// :nodoc: - public init(name: String? = nil, typeName: TypeName, type: Type? = nil) { - self.name = name - self.typeName = typeName - self.type = type + // sourcery: skipEquality, skipDescription + /// Whether return value type is optional + public var isOptionalReturnType: Bool { + return returnTypeName.isOptional } - public var asSource: String { - // swiftlint:disable:next force_unwrapping - "\\(name != nil ? "\\(name!): " : "")\\(typeName.asSource)" + // sourcery: skipEquality, skipDescription + /// Whether return value type is implicitly unwrapped optional + public var isImplicitlyUnwrappedOptionalReturnType: Bool { + return returnTypeName.isImplicitlyUnwrappedOptional } - /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "name = \\(String(describing: self.name)), " - string += "typeName = \\(String(describing: self.typeName)), " - string += "asSource = \\(String(describing: self.asSource))" - return string + // sourcery: skipEquality, skipDescription + /// Return value type name without attributes and optional type information + public var unwrappedReturnTypeName: String { + return returnTypeName.unwrappedTypeName } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? TupleElement else { - results.append("Incorrect type ") - return results - } - results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) - return results + /// Whether method is final + public var isFinal: Bool { + modifiers.contains { $0.name == "final" } } - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.name) - hasher.combine(self.typeName) - return hasher.finalize() - } + /// Variable read access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` + public let readAccess: String - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? TupleElement else { return false } - if self.name != rhs.name { return false } - if self.typeName != rhs.typeName { return false } - return true - } + /// Variable write access, i.e. `internal`, `private`, `fileprivate`, `public`, `open`. + /// For immutable variables this value is empty string + public var writeAccess: String -// sourcery:inline:TupleElement.AutoCoding + /// Whether subscript is async + public let isAsync: Bool - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - self.name = aDecoder.decode(forKey: "name") - guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { - withVaList(["typeName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.typeName = typeName - self.type = aDecoder.decode(forKey: "type") - } + /// Whether subscript throws + public let `throws`: Bool - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.typeName, forKey: "typeName") - aCoder.encode(self.type, forKey: "type") - } -// sourcery:end -} - -extension Array where Element == TupleElement { - public var asSource: String { - "(\\(map { $0.asSource }.joined(separator: ", ")))" - } - - public var asTypeName: String { - "(\\(map { $0.typeName.asSource }.joined(separator: ", ")))" + /// Whether variable is mutable or not + public var isMutable: Bool { + return writeAccess != AccessLevel.none.rawValue } -} - -"""), - .init(name: "Type.swift", content: -""" -// -// Created by Krzysztof Zablocki on 11/09/2016. -// Copyright (c) 2016 Pixle. All rights reserved. -// - -import Foundation - -/// :nodoc: -public typealias AttributeList = [String: [Attribute]] -/// Defines Swift type -@objcMembers -public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable { - - /// :nodoc: - public var module: String? - - /// Imports that existed in the file that contained this type declaration - public var imports: [Import] = [] - - // sourcery: skipEquality - /// Imports existed in all files containing this type and all its super classes/protocols - public var allImports: [Import] { - return self.unique({ $0.gatherAllImports() }, filter: { $0 == $1 }) - } + /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 + public let annotations: Annotations - private func gatherAllImports() -> [Import] { - var allImports: [Import] = Array(self.imports) + public let documentation: Documentation - self.basedTypes.values.forEach { (basedType) in - allImports.append(contentsOf: basedType.imports) - } - return allImports - } + /// Reference to type name where the method is defined, + /// nil if defined outside of any `enum`, `struct`, `class` etc + public let definedInTypeName: TypeName? - // All local typealiases - /// :nodoc: - public var typealiases: [String: Typealias] { - didSet { - typealiases.values.forEach { $0.parent = self } - } + /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` + public var actualDefinedInTypeName: TypeName? { + return definedInTypeName?.actualTypeName ?? definedInTypeName } - // sourcery: skipJSExport - /// Whether declaration is an extension of some type - public var isExtension: Bool - - // sourcery: forceEquality - /// Kind of type declaration, i.e. `enum`, `struct`, `class`, `protocol` or `extension` - public var kind: String { isExtension ? "extension" : "unknown" } - - /// Type access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` - public let accessLevel: String - - /// Type name in global scope. For inner types includes the name of its containing type, i.e. `Type.Inner` - public var name: String { - guard let parentName = parent?.name else { return localName } - return "\\(parentName).\\(localName)" - } + // sourcery: skipEquality, skipDescription + /// Reference to actual type where the object is defined, + /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown + public var definedInType: Type? - // sourcery: skipCoding - /// Whether the type has been resolved as unknown extension - public var isUnknownExtension: Bool = false + /// Method attributes, i.e. `@discardableResult` + public let attributes: AttributeList - // sourcery: skipDescription - /// Global type name including module name, unless it's an extension of unknown type - public var globalName: String { - guard let module = module, !isUnknownExtension else { return name } - return "\\(module).\\(name)" - } + /// Method modifiers, i.e. `private` + public let modifiers: [SourceryModifier] - /// Whether type is generic - public var isGeneric: Bool + /// list of generic parameters + public let genericParameters: [GenericParameter] - /// Type name in its own scope. - public var localName: String + /// list of generic requirements + public let genericRequirements: [GenericRequirement] - // sourcery: skipEquality, skipDescription - /// Variables defined in this type only, inluding variables defined in its extensions, - /// but not including variables inherited from superclasses (for classes only) and protocols - public var variables: [Variable] { - unique({ $0.rawVariables }, filter: Self.uniqueVariableFilter) + /// Whether subscript is generic or not + public var isGeneric: Bool { + return genericParameters.isEmpty == false } - /// Unfiltered (can contain duplications from extensions) variables defined in this type only, inluding variables defined in its extensions, - /// but not including variables inherited from superclasses (for classes only) and protocols - public var rawVariables: [Variable] + // Underlying parser data, never to be used by anything else + // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport + /// :nodoc: + public var __parserData: Any? - // sourcery: skipEquality, skipDescription - /// All variables defined for this type, including variables defined in extensions, - /// in superclasses (for classes only) and protocols - public var allVariables: [Variable] { - return flattenAll({ - return $0.variables - }, - isExtension: { $0.definedInType?.isExtension == true }, - filter: { all, extracted in - !all.contains(where: { Self.uniqueVariableFilter($0, rhs: extracted) }) - }) - } + public init(parameters: [MethodParameter] = [], + returnTypeName: TypeName, + accessLevel: (read: AccessLevel, write: AccessLevel) = (.internal, .internal), + isAsync: Bool = false, + `throws`: Bool = false, + genericParameters: [GenericParameter] = [], + genericRequirements: [GenericRequirement] = [], + attributes: AttributeList = [:], + modifiers: [SourceryModifier] = [], + annotations: [String: NSObject] = [:], + documentation: [String] = [], + definedInTypeName: TypeName? = nil) { - private static func uniqueVariableFilter(_ lhs: Variable, rhs: Variable) -> Bool { - return lhs.name == rhs.name && lhs.isStatic == rhs.isStatic && lhs.typeName == rhs.typeName + self.parameters = parameters + self.returnTypeName = returnTypeName + self.readAccess = accessLevel.read.rawValue + self.writeAccess = accessLevel.write.rawValue + self.isAsync = isAsync + self.throws = `throws` + self.genericParameters = genericParameters + self.genericRequirements = genericRequirements + self.attributes = attributes + self.modifiers = modifiers + self.annotations = annotations + self.documentation = documentation + self.definedInTypeName = definedInTypeName } - // sourcery: skipEquality, skipDescription - /// Methods defined in this type only, inluding methods defined in its extensions, - /// but not including methods inherited from superclasses (for classes only) and protocols - public var methods: [Method] { - unique({ $0.rawMethods }, filter: Self.uniqueMethodFilter) + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("parameters = \\(String(describing: self.parameters)), ") + string.append("returnTypeName = \\(String(describing: self.returnTypeName)), ") + string.append("actualReturnTypeName = \\(String(describing: self.actualReturnTypeName)), ") + string.append("isFinal = \\(String(describing: self.isFinal)), ") + string.append("readAccess = \\(String(describing: self.readAccess)), ") + string.append("writeAccess = \\(String(describing: self.writeAccess)), ") + string.append("isAsync = \\(String(describing: self.isAsync)), ") + string.append("`throws` = \\(String(describing: self.throws)), ") + string.append("isMutable = \\(String(describing: self.isMutable)), ") + string.append("annotations = \\(String(describing: self.annotations)), ") + string.append("documentation = \\(String(describing: self.documentation)), ") + string.append("definedInTypeName = \\(String(describing: self.definedInTypeName)), ") + string.append("actualDefinedInTypeName = \\(String(describing: self.actualDefinedInTypeName)), ") + string.append("genericParameters = \\(String(describing: self.genericParameters)), ") + string.append("genericRequirements = \\(String(describing: self.genericRequirements)), ") + string.append("isGeneric = \\(String(describing: self.isGeneric)), ") + string.append("attributes = \\(String(describing: self.attributes)), ") + string.append("modifiers = \\(String(describing: self.modifiers))") + return string } - /// Unfiltered (can contain duplications from extensions) methods defined in this type only, inluding methods defined in its extensions, - /// but not including methods inherited from superclasses (for classes only) and protocols - public var rawMethods: [Method] - - // sourcery: skipEquality, skipDescription - /// All methods defined for this type, including methods defined in extensions, - /// in superclasses (for classes only) and protocols - public var allMethods: [Method] { - return flattenAll({ - $0.methods - }, - isExtension: { $0.definedInType?.isExtension == true }, - filter: { all, extracted in - !all.contains(where: { Self.uniqueMethodFilter($0, rhs: extracted) }) - }) + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? Subscript else { + results.append("Incorrect type ") + return results + } + results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) + results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) + results.append(contentsOf: DiffableResult(identifier: "readAccess").trackDifference(actual: self.readAccess, expected: castObject.readAccess)) + results.append(contentsOf: DiffableResult(identifier: "writeAccess").trackDifference(actual: self.writeAccess, expected: castObject.writeAccess)) + results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) + results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.throws, expected: castObject.throws)) + results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) + results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) + results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) + results.append(contentsOf: DiffableResult(identifier: "genericParameters").trackDifference(actual: self.genericParameters, expected: castObject.genericParameters)) + results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) + results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) + results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) + return results } - private static func uniqueMethodFilter(_ lhs: Method, rhs: Method) -> Bool { - return lhs.name == rhs.name && lhs.isStatic == rhs.isStatic && lhs.isClass == rhs.isClass && lhs.actualReturnTypeName == rhs.actualReturnTypeName + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.parameters) + hasher.combine(self.returnTypeName) + hasher.combine(self.readAccess) + hasher.combine(self.writeAccess) + hasher.combine(self.isAsync) + hasher.combine(self.throws) + hasher.combine(self.annotations) + hasher.combine(self.documentation) + hasher.combine(self.definedInTypeName) + hasher.combine(self.genericParameters) + hasher.combine(self.genericRequirements) + hasher.combine(self.attributes) + hasher.combine(self.modifiers) + return hasher.finalize() } - // sourcery: skipEquality, skipDescription - /// Subscripts defined in this type only, inluding subscripts defined in its extensions, - /// but not including subscripts inherited from superclasses (for classes only) and protocols - public var subscripts: [Subscript] { - unique({ $0.rawSubscripts }, filter: Self.uniqueSubscriptFilter) + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? Subscript else { return false } + if self.parameters != rhs.parameters { return false } + if self.returnTypeName != rhs.returnTypeName { return false } + if self.readAccess != rhs.readAccess { return false } + if self.writeAccess != rhs.writeAccess { return false } + if self.isAsync != rhs.isAsync { return false } + if self.throws != rhs.throws { return false } + if self.annotations != rhs.annotations { return false } + if self.documentation != rhs.documentation { return false } + if self.definedInTypeName != rhs.definedInTypeName { return false } + if self.genericParameters != rhs.genericParameters { return false } + if self.genericRequirements != rhs.genericRequirements { return false } + if self.attributes != rhs.attributes { return false } + if self.modifiers != rhs.modifiers { return false } + return true } - /// Unfiltered (can contain duplications from extensions) Subscripts defined in this type only, inluding subscripts defined in its extensions, - /// but not including subscripts inherited from superclasses (for classes only) and protocols - public var rawSubscripts: [Subscript] +// sourcery:inline:Subscript.AutoCoding - // sourcery: skipEquality, skipDescription - /// All subscripts defined for this type, including subscripts defined in extensions, - /// in superclasses (for classes only) and protocols - public var allSubscripts: [Subscript] { - return flattenAll({ $0.subscripts }, - isExtension: { $0.definedInType?.isExtension == true }, - filter: { all, extracted in - !all.contains(where: { Self.uniqueSubscriptFilter($0, rhs: extracted) }) - }) - } - - private static func uniqueSubscriptFilter(_ lhs: Subscript, rhs: Subscript) -> Bool { - return lhs.parameters == rhs.parameters && lhs.returnTypeName == rhs.returnTypeName && lhs.readAccess == rhs.readAccess && lhs.writeAccess == rhs.writeAccess - } - - // sourcery: skipEquality, skipDescription, skipJSExport - /// Bytes position of the body of this type in its declaration file if available. - public var bodyBytesRange: BytesRange? - - // sourcery: skipEquality, skipDescription, skipJSExport - /// Bytes position of the whole declaration of this type in its declaration file if available. - public var completeDeclarationRange: BytesRange? + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let parameters: [MethodParameter] = aDecoder.decode(forKey: "parameters") else { + withVaList(["parameters"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.parameters = parameters + guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { + withVaList(["returnTypeName"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.returnTypeName = returnTypeName + self.returnType = aDecoder.decode(forKey: "returnType") + guard let readAccess: String = aDecoder.decode(forKey: "readAccess") else { + withVaList(["readAccess"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.readAccess = readAccess + guard let writeAccess: String = aDecoder.decode(forKey: "writeAccess") else { + withVaList(["writeAccess"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.writeAccess = writeAccess + self.isAsync = aDecoder.decode(forKey: "isAsync") + self.`throws` = aDecoder.decode(forKey: "`throws`") + guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { + withVaList(["annotations"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.annotations = annotations + guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { + withVaList(["documentation"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.documentation = documentation + self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") + self.definedInType = aDecoder.decode(forKey: "definedInType") + guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { + withVaList(["attributes"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.attributes = attributes + guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { + withVaList(["modifiers"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.modifiers = modifiers + guard let genericParameters: [GenericParameter] = aDecoder.decode(forKey: "genericParameters") else { + withVaList(["genericParameters"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.genericParameters = genericParameters + guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { + withVaList(["genericRequirements"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.genericRequirements = genericRequirements + } - private func flattenAll(_ extraction: @escaping (Type) -> [T], isExtension: (T) -> Bool, filter: ([T], T) -> Bool) -> [T] { - let all = NSMutableOrderedSet() - let allObjects = extraction(self) + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.parameters, forKey: "parameters") + aCoder.encode(self.returnTypeName, forKey: "returnTypeName") + aCoder.encode(self.returnType, forKey: "returnType") + aCoder.encode(self.readAccess, forKey: "readAccess") + aCoder.encode(self.writeAccess, forKey: "writeAccess") + aCoder.encode(self.isAsync, forKey: "isAsync") + aCoder.encode(self.`throws`, forKey: "`throws`") + aCoder.encode(self.annotations, forKey: "annotations") + aCoder.encode(self.documentation, forKey: "documentation") + aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") + aCoder.encode(self.definedInType, forKey: "definedInType") + aCoder.encode(self.attributes, forKey: "attributes") + aCoder.encode(self.modifiers, forKey: "modifiers") + aCoder.encode(self.genericParameters, forKey: "genericParameters") + aCoder.encode(self.genericRequirements, forKey: "genericRequirements") + } +// sourcery:end - /// The order of importance for properties is: - /// Base class - /// Inheritance - /// Protocol conformance - /// Extension +} +#endif - var extensions = [T]() - var baseObjects = [T]() +"""), + .init(name: "Tuple.swift", content: +""" +#if canImport(ObjectiveC) +import Foundation - allObjects.forEach { - if isExtension($0) { - extensions.append($0) - } else { - baseObjects.append($0) - } - } +/// Describes tuple type +@objcMembers +public final class TupleType: NSObject, SourceryModel, Diffable { - all.addObjects(from: baseObjects) + /// Type name used in declaration + public var name: String - func filteredExtraction(_ target: Type) -> [T] { - // swiftlint:disable:next force_cast - let all = all.array as! [T] - let extracted = extraction(target).filter({ filter(all, $0) }) - return extracted - } + /// Tuple elements + public var elements: [TupleElement] - inherits.values.sorted(by: { $0.name < $1.name }).forEach { all.addObjects(from: filteredExtraction($0)) } - implements.values.sorted(by: { $0.name < $1.name }).forEach { all.addObjects(from: filteredExtraction($0)) } + /// :nodoc: + public init(name: String, elements: [TupleElement]) { + self.name = name + self.elements = elements + } - // swiftlint:disable:next force_cast - let array = all.array as! [T] - all.addObjects(from: extensions.filter({ filter(array, $0) })) + /// :nodoc: + public init(elements: [TupleElement]) { + self.name = elements.asSource + self.elements = elements + } - return all.array.compactMap { $0 as? T } + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("name = \\(String(describing: self.name)), ") + string.append("elements = \\(String(describing: self.elements))") + return string } - private func unique(_ extraction: @escaping (Type) -> [T], filter: (T, T) -> Bool) -> [T] { - let all = NSMutableOrderedSet() - for nextItem in extraction(self) { - // swiftlint:disable:next force_cast - if !all.contains(where: { filter($0 as! T, nextItem) }) { - all.add(nextItem) - } + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? TupleType else { + results.append("Incorrect type ") + return results } + results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) + results.append(contentsOf: DiffableResult(identifier: "elements").trackDifference(actual: self.elements, expected: castObject.elements)) + return results + } - return all.array.compactMap { $0 as? T } + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.name) + hasher.combine(self.elements) + return hasher.finalize() } - /// All initializers defined in this type - public var initializers: [Method] { - return methods.filter { $0.isInitializer } + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? TupleType else { return false } + if self.name != rhs.name { return false } + if self.elements != rhs.elements { return false } + return true } - /// All annotations for this type - public var annotations: Annotations = [:] +// sourcery:inline:TupleType.AutoCoding - public var documentation: Documentation = [] + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let name: String = aDecoder.decode(forKey: "name") else { + withVaList(["name"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.name = name + guard let elements: [TupleElement] = aDecoder.decode(forKey: "elements") else { + withVaList(["elements"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.elements = elements + } - /// Static variables defined in this type - public var staticVariables: [Variable] { - return variables.filter { $0.isStatic } - } + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.elements, forKey: "elements") + } +// sourcery:end +} - /// Static methods defined in this type - public var staticMethods: [Method] { - return methods.filter { $0.isStatic } - } +/// Describes tuple type element +@objcMembers +public final class TupleElement: NSObject, SourceryModel, Typed, Diffable { - /// Class methods defined in this type - public var classMethods: [Method] { - return methods.filter { $0.isClass } - } + /// Tuple element name + public let name: String? - /// Instance variables defined in this type - public var instanceVariables: [Variable] { - return variables.filter { !$0.isStatic } - } + /// Tuple element type name + public var typeName: TypeName - /// Instance methods defined in this type - public var instanceMethods: [Method] { - return methods.filter { !$0.isStatic && !$0.isClass } - } + // sourcery: skipEquality, skipDescription + /// Tuple element type, if known + public var type: Type? - /// Computed instance variables defined in this type - public var computedVariables: [Variable] { - return variables.filter { $0.isComputed && !$0.isStatic } + /// :nodoc: + public init(name: String? = nil, typeName: TypeName, type: Type? = nil) { + self.name = name + self.typeName = typeName + self.type = type } - /// Stored instance variables defined in this type - public var storedVariables: [Variable] { - return variables.filter { !$0.isComputed && !$0.isStatic } + public var asSource: String { + // swiftlint:disable:next force_unwrapping + "\\(name != nil ? "\\(name!): " : "")\\(typeName.asSource)" } - /// Names of types this type inherits from (for classes only) and protocols it implements, in order of definition - public var inheritedTypes: [String] { - didSet { - based.removeAll() - inheritedTypes.forEach { name in - self.based[name] = name - } + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("name = \\(String(describing: self.name)), ") + string.append("typeName = \\(String(describing: self.typeName)), ") + string.append("asSource = \\(String(describing: self.asSource))") + return string + } + + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? TupleElement else { + results.append("Incorrect type ") + return results } + results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) + results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) + return results } - // sourcery: skipEquality, skipDescription - /// Names of types or protocols this type inherits from, including unknown (not scanned) types - public var based = [String: String]() + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.name) + hasher.combine(self.typeName) + return hasher.finalize() + } - // sourcery: skipEquality, skipDescription - /// Types this type inherits from or implements, including unknown (not scanned) types with extensions defined - public var basedTypes = [String: Type]() + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? TupleElement else { return false } + if self.name != rhs.name { return false } + if self.typeName != rhs.typeName { return false } + return true + } - /// Types this type inherits from - public var inherits = [String: Type]() +// sourcery:inline:TupleElement.AutoCoding - // sourcery: skipEquality, skipDescription - /// Protocols this type implements - public var implements: [String: Type] = [:] + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + self.name = aDecoder.decode(forKey: "name") + guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { + withVaList(["typeName"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.typeName = typeName + self.type = aDecoder.decode(forKey: "type") + } - /// Contained types - public var containedTypes: [Type] { - didSet { - containedTypes.forEach { - containedType[$0.localName] = $0 - $0.parent = self - } + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.typeName, forKey: "typeName") + aCoder.encode(self.type, forKey: "type") } +// sourcery:end +} + +extension Array where Element == TupleElement { + public var asSource: String { + "(\\(map { $0.asSource }.joined(separator: ", ")))" } - // sourcery: skipEquality, skipDescription - /// Contained types groupd by their names - public private(set) var containedType: [String: Type] = [:] + public var asTypeName: String { + "(\\(map { $0.typeName.asSource }.joined(separator: ", ")))" + } +} +#endif - /// Name of parent type (for contained types only) - public private(set) var parentName: String? +"""), + .init(name: "Type.swift", content: +""" +// +// Created by Krzysztof Zablocki on 11/09/2016. +// Copyright (c) 2016 Pixle. All rights reserved. +// +#if canImport(ObjectiveC) +import Foundation - // sourcery: skipEquality, skipDescription - /// Parent type, if known (for contained types only) - public var parent: Type? { - didSet { - parentName = parent?.name - } - } +/// :nodoc: +public typealias AttributeList = [String: [Attribute]] - // sourcery: skipJSExport - /// :nodoc: - public var parentTypes: AnyIterator { - var next: Type? = self - return AnyIterator { - next = next?.parent - return next - } - } +/// Defines Swift type - // sourcery: skipEquality, skipDescription - /// Superclass type, if known (only for classes) - public var supertype: Type? +@objcMembers +public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable { - /// Type attributes, i.e. `@objc` - public var attributes: AttributeList + /// :nodoc: + public var module: String? - /// Type modifiers, i.e. `private`, `final` - public var modifiers: [SourceryModifier] + /// Imports that existed in the file that contained this type declaration + public var imports: [Import] = [] - /// Path to file where the type is defined - // sourcery: skipDescription, skipEquality, skipJSExport - public var path: String? { - didSet { - if let path = path { - fileName = (path as NSString).lastPathComponent - } - } + // sourcery: skipEquality + /// Imports existed in all files containing this type and all its super classes/protocols + public var allImports: [Import] { + return self.unique({ $0.gatherAllImports() }, filter: { $0 == $1 }) } - /// Directory to file where the type is defined - // sourcery: skipDescription, skipEquality, skipJSExport - public var directory: String? { - get { - return (path as? NSString)?.deletingLastPathComponent + private func gatherAllImports() -> [Import] { + var allImports: [Import] = Array(self.imports) + + self.basedTypes.values.forEach { (basedType) in + allImports.append(contentsOf: basedType.imports) } + return allImports } - /// list of generic requirements - public var genericRequirements: [GenericRequirement] { + // All local typealiases + /// :nodoc: + public var typealiases: [String: Typealias] { didSet { - isGeneric = isGeneric || !genericRequirements.isEmpty + typealiases.values.forEach { $0.parent = self } } } - /// File name where the type was defined - public var fileName: String? + // sourcery: skipJSExport + /// Whether declaration is an extension of some type + public var isExtension: Bool - /// :nodoc: - public init(name: String = "", - parent: Type? = nil, - accessLevel: AccessLevel = .internal, - isExtension: Bool = false, - variables: [Variable] = [], - methods: [Method] = [], - subscripts: [Subscript] = [], - inheritedTypes: [String] = [], - containedTypes: [Type] = [], - typealiases: [Typealias] = [], - genericRequirements: [GenericRequirement] = [], - attributes: AttributeList = [:], - modifiers: [SourceryModifier] = [], - annotations: [String: NSObject] = [:], - documentation: [String] = [], - isGeneric: Bool = false, - implements: [String: Type] = [:]) { - self.localName = name - self.accessLevel = accessLevel.rawValue - self.isExtension = isExtension - self.rawVariables = variables - self.rawMethods = methods - self.rawSubscripts = subscripts - self.inheritedTypes = inheritedTypes - self.containedTypes = containedTypes - self.typealiases = [:] - self.parent = parent - self.parentName = parent?.name - self.attributes = attributes - self.modifiers = modifiers - self.annotations = annotations - self.documentation = documentation - self.isGeneric = isGeneric - self.genericRequirements = genericRequirements - self.implements = implements - super.init() - containedTypes.forEach { - containedType[$0.localName] = $0 - $0.parent = self - } - inheritedTypes.forEach { name in - self.based[name] = name - } - typealiases.forEach({ - $0.parent = self - self.typealiases[$0.aliasName] = $0 - }) + // sourcery: forceEquality + /// Kind of type declaration, i.e. `enum`, `struct`, `class`, `protocol` or `extension` + public var kind: String { isExtension ? "extension" : "unknown" } + + /// Type access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` + public let accessLevel: String + + /// Type name in global scope. For inner types includes the name of its containing type, i.e. `Type.Inner` + public var name: String { + guard let parentName = parent?.name else { return localName } + return "\\(parentName).\\(localName)" } - /// :nodoc: - public func extend(_ type: Type) { - type.annotations.forEach { self.annotations[$0.key] = $0.value } - type.inherits.forEach { self.inherits[$0.key] = $0.value } - type.implements.forEach { self.implements[$0.key] = $0.value } - self.inheritedTypes += type.inheritedTypes - self.containedTypes += type.containedTypes + // sourcery: skipCoding + /// Whether the type has been resolved as unknown extension + public var isUnknownExtension: Bool = false - self.rawVariables += type.rawVariables - self.rawMethods += type.rawMethods - self.rawSubscripts += type.rawSubscripts + // sourcery: skipDescription + /// Global type name including module name, unless it's an extension of unknown type + public var globalName: String { + guard let module = module, !isUnknownExtension else { return name } + return "\\(module).\\(name)" } - /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "module = \\(String(describing: self.module)), " - string += "imports = \\(String(describing: self.imports)), " - string += "allImports = \\(String(describing: self.allImports)), " - string += "typealiases = \\(String(describing: self.typealiases)), " - string += "isExtension = \\(String(describing: self.isExtension)), " - string += "kind = \\(String(describing: self.kind)), " - string += "accessLevel = \\(String(describing: self.accessLevel)), " - string += "name = \\(String(describing: self.name)), " - string += "isUnknownExtension = \\(String(describing: self.isUnknownExtension)), " - string += "isGeneric = \\(String(describing: self.isGeneric)), " - string += "localName = \\(String(describing: self.localName)), " - string += "rawVariables = \\(String(describing: self.rawVariables)), " - string += "rawMethods = \\(String(describing: self.rawMethods)), " - string += "rawSubscripts = \\(String(describing: self.rawSubscripts)), " - string += "initializers = \\(String(describing: self.initializers)), " - string += "annotations = \\(String(describing: self.annotations)), " - string += "documentation = \\(String(describing: self.documentation)), " - string += "staticVariables = \\(String(describing: self.staticVariables)), " - string += "staticMethods = \\(String(describing: self.staticMethods)), " - string += "classMethods = \\(String(describing: self.classMethods)), " - string += "instanceVariables = \\(String(describing: self.instanceVariables)), " - string += "instanceMethods = \\(String(describing: self.instanceMethods)), " - string += "computedVariables = \\(String(describing: self.computedVariables)), " - string += "storedVariables = \\(String(describing: self.storedVariables)), " - string += "inheritedTypes = \\(String(describing: self.inheritedTypes)), " - string += "inherits = \\(String(describing: self.inherits)), " - string += "containedTypes = \\(String(describing: self.containedTypes)), " - string += "parentName = \\(String(describing: self.parentName)), " - string += "parentTypes = \\(String(describing: self.parentTypes)), " - string += "attributes = \\(String(describing: self.attributes)), " - string += "modifiers = \\(String(describing: self.modifiers)), " - string += "fileName = \\(String(describing: self.fileName)), " - string += "genericRequirements = \\(String(describing: self.genericRequirements))" - return string + /// Whether type is generic + public var isGeneric: Bool + + /// Type name in its own scope. + public var localName: String + + // sourcery: skipEquality, skipDescription + /// Variables defined in this type only, inluding variables defined in its extensions, + /// but not including variables inherited from superclasses (for classes only) and protocols + public var variables: [Variable] { + unique({ $0.rawVariables }, filter: Self.uniqueVariableFilter) } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? Type else { - results.append("Incorrect type ") - return results - } - results.append(contentsOf: DiffableResult(identifier: "module").trackDifference(actual: self.module, expected: castObject.module)) - results.append(contentsOf: DiffableResult(identifier: "imports").trackDifference(actual: self.imports, expected: castObject.imports)) - results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) - results.append(contentsOf: DiffableResult(identifier: "isExtension").trackDifference(actual: self.isExtension, expected: castObject.isExtension)) - results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) - results.append(contentsOf: DiffableResult(identifier: "isUnknownExtension").trackDifference(actual: self.isUnknownExtension, expected: castObject.isUnknownExtension)) - results.append(contentsOf: DiffableResult(identifier: "isGeneric").trackDifference(actual: self.isGeneric, expected: castObject.isGeneric)) - results.append(contentsOf: DiffableResult(identifier: "localName").trackDifference(actual: self.localName, expected: castObject.localName)) - results.append(contentsOf: DiffableResult(identifier: "rawVariables").trackDifference(actual: self.rawVariables, expected: castObject.rawVariables)) - results.append(contentsOf: DiffableResult(identifier: "rawMethods").trackDifference(actual: self.rawMethods, expected: castObject.rawMethods)) - results.append(contentsOf: DiffableResult(identifier: "rawSubscripts").trackDifference(actual: self.rawSubscripts, expected: castObject.rawSubscripts)) - results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) - results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) - results.append(contentsOf: DiffableResult(identifier: "inheritedTypes").trackDifference(actual: self.inheritedTypes, expected: castObject.inheritedTypes)) - results.append(contentsOf: DiffableResult(identifier: "inherits").trackDifference(actual: self.inherits, expected: castObject.inherits)) - results.append(contentsOf: DiffableResult(identifier: "containedTypes").trackDifference(actual: self.containedTypes, expected: castObject.containedTypes)) - results.append(contentsOf: DiffableResult(identifier: "parentName").trackDifference(actual: self.parentName, expected: castObject.parentName)) - results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) - results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) - results.append(contentsOf: DiffableResult(identifier: "fileName").trackDifference(actual: self.fileName, expected: castObject.fileName)) - results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) - return results + /// Unfiltered (can contain duplications from extensions) variables defined in this type only, inluding variables defined in its extensions, + /// but not including variables inherited from superclasses (for classes only) and protocols + public var rawVariables: [Variable] + + // sourcery: skipEquality, skipDescription + /// All variables defined for this type, including variables defined in extensions, + /// in superclasses (for classes only) and protocols + public var allVariables: [Variable] { + return flattenAll({ + return $0.variables + }, + isExtension: { $0.definedInType?.isExtension == true }, + filter: { all, extracted in + !all.contains(where: { Self.uniqueVariableFilter($0, rhs: extracted) }) + }) } - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.module) - hasher.combine(self.imports) - hasher.combine(self.typealiases) - hasher.combine(self.isExtension) - hasher.combine(self.accessLevel) - hasher.combine(self.isUnknownExtension) - hasher.combine(self.isGeneric) - hasher.combine(self.localName) - hasher.combine(self.rawVariables) - hasher.combine(self.rawMethods) - hasher.combine(self.rawSubscripts) - hasher.combine(self.annotations) - hasher.combine(self.documentation) - hasher.combine(self.inheritedTypes) - hasher.combine(self.inherits) - hasher.combine(self.containedTypes) - hasher.combine(self.parentName) - hasher.combine(self.attributes) - hasher.combine(self.modifiers) - hasher.combine(self.fileName) - hasher.combine(self.genericRequirements) - hasher.combine(kind) - return hasher.finalize() + private static func uniqueVariableFilter(_ lhs: Variable, rhs: Variable) -> Bool { + return lhs.name == rhs.name && lhs.isStatic == rhs.isStatic && lhs.typeName == rhs.typeName } - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? Type else { return false } - if self.module != rhs.module { return false } - if self.imports != rhs.imports { return false } - if self.typealiases != rhs.typealiases { return false } - if self.isExtension != rhs.isExtension { return false } - if self.accessLevel != rhs.accessLevel { return false } - if self.isUnknownExtension != rhs.isUnknownExtension { return false } - if self.isGeneric != rhs.isGeneric { return false } - if self.localName != rhs.localName { return false } - if self.rawVariables != rhs.rawVariables { return false } - if self.rawMethods != rhs.rawMethods { return false } - if self.rawSubscripts != rhs.rawSubscripts { return false } - if self.annotations != rhs.annotations { return false } - if self.documentation != rhs.documentation { return false } - if self.inheritedTypes != rhs.inheritedTypes { return false } - if self.inherits != rhs.inherits { return false } - if self.containedTypes != rhs.containedTypes { return false } - if self.parentName != rhs.parentName { return false } - if self.attributes != rhs.attributes { return false } - if self.modifiers != rhs.modifiers { return false } - if self.fileName != rhs.fileName { return false } - if self.kind != rhs.kind { return false } - if self.genericRequirements != rhs.genericRequirements { return false } - return true + // sourcery: skipEquality, skipDescription + /// Methods defined in this type only, inluding methods defined in its extensions, + /// but not including methods inherited from superclasses (for classes only) and protocols + public var methods: [Method] { + unique({ $0.rawMethods }, filter: Self.uniqueMethodFilter) } -// sourcery:inline:Type.AutoCoding + /// Unfiltered (can contain duplications from extensions) methods defined in this type only, inluding methods defined in its extensions, + /// but not including methods inherited from superclasses (for classes only) and protocols + public var rawMethods: [Method] - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - self.module = aDecoder.decode(forKey: "module") - guard let imports: [Import] = aDecoder.decode(forKey: "imports") else { - withVaList(["imports"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.imports = imports - guard let typealiases: [String: Typealias] = aDecoder.decode(forKey: "typealiases") else { - withVaList(["typealiases"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.typealiases = typealiases - self.isExtension = aDecoder.decode(forKey: "isExtension") - guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { - withVaList(["accessLevel"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.accessLevel = accessLevel - self.isGeneric = aDecoder.decode(forKey: "isGeneric") - guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { - withVaList(["genericRequirements"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.genericRequirements = genericRequirements - guard let localName: String = aDecoder.decode(forKey: "localName") else { - withVaList(["localName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.localName = localName - guard let rawVariables: [Variable] = aDecoder.decode(forKey: "rawVariables") else { - withVaList(["rawVariables"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.rawVariables = rawVariables - guard let rawMethods: [Method] = aDecoder.decode(forKey: "rawMethods") else { - withVaList(["rawMethods"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.rawMethods = rawMethods - guard let rawSubscripts: [Subscript] = aDecoder.decode(forKey: "rawSubscripts") else { - withVaList(["rawSubscripts"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.rawSubscripts = rawSubscripts - self.bodyBytesRange = aDecoder.decode(forKey: "bodyBytesRange") - self.completeDeclarationRange = aDecoder.decode(forKey: "completeDeclarationRange") - guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { - withVaList(["annotations"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.annotations = annotations - guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { - withVaList(["documentation"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.documentation = documentation - guard let inheritedTypes: [String] = aDecoder.decode(forKey: "inheritedTypes") else { - withVaList(["inheritedTypes"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.inheritedTypes = inheritedTypes - guard let based: [String: String] = aDecoder.decode(forKey: "based") else { - withVaList(["based"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.based = based - guard let basedTypes: [String: Type] = aDecoder.decode(forKey: "basedTypes") else { - withVaList(["basedTypes"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.basedTypes = basedTypes - guard let inherits: [String: Type] = aDecoder.decode(forKey: "inherits") else { - withVaList(["inherits"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.inherits = inherits - guard let implements: [String: Type] = aDecoder.decode(forKey: "implements") else { - withVaList(["implements"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.implements = implements - guard let containedTypes: [Type] = aDecoder.decode(forKey: "containedTypes") else { - withVaList(["containedTypes"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.containedTypes = containedTypes - guard let containedType: [String: Type] = aDecoder.decode(forKey: "containedType") else { - withVaList(["containedType"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.containedType = containedType - self.parentName = aDecoder.decode(forKey: "parentName") - self.parent = aDecoder.decode(forKey: "parent") - self.supertype = aDecoder.decode(forKey: "supertype") - guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { - withVaList(["attributes"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.attributes = attributes - guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { - withVaList(["modifiers"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.modifiers = modifiers - self.path = aDecoder.decode(forKey: "path") - self.fileName = aDecoder.decode(forKey: "fileName") - } + // sourcery: skipEquality, skipDescription + /// All methods defined for this type, including methods defined in extensions, + /// in superclasses (for classes only) and protocols + public var allMethods: [Method] { + return flattenAll({ + $0.methods + }, + isExtension: { $0.definedInType?.isExtension == true }, + filter: { all, extracted in + !all.contains(where: { Self.uniqueMethodFilter($0, rhs: extracted) }) + }) + } - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.module, forKey: "module") - aCoder.encode(self.imports, forKey: "imports") - aCoder.encode(self.typealiases, forKey: "typealiases") - aCoder.encode(self.isExtension, forKey: "isExtension") - aCoder.encode(self.accessLevel, forKey: "accessLevel") - aCoder.encode(self.isGeneric, forKey: "isGeneric") - aCoder.encode(self.localName, forKey: "localName") - aCoder.encode(self.rawVariables, forKey: "rawVariables") - aCoder.encode(self.rawMethods, forKey: "rawMethods") - aCoder.encode(self.rawSubscripts, forKey: "rawSubscripts") - aCoder.encode(self.bodyBytesRange, forKey: "bodyBytesRange") - aCoder.encode(self.completeDeclarationRange, forKey: "completeDeclarationRange") - aCoder.encode(self.annotations, forKey: "annotations") - aCoder.encode(self.documentation, forKey: "documentation") - aCoder.encode(self.inheritedTypes, forKey: "inheritedTypes") - aCoder.encode(self.based, forKey: "based") - aCoder.encode(self.basedTypes, forKey: "basedTypes") - aCoder.encode(self.inherits, forKey: "inherits") - aCoder.encode(self.implements, forKey: "implements") - aCoder.encode(self.containedTypes, forKey: "containedTypes") - aCoder.encode(self.containedType, forKey: "containedType") - aCoder.encode(self.parentName, forKey: "parentName") - aCoder.encode(self.parent, forKey: "parent") - aCoder.encode(self.supertype, forKey: "supertype") - aCoder.encode(self.attributes, forKey: "attributes") - aCoder.encode(self.modifiers, forKey: "modifiers") - aCoder.encode(self.path, forKey: "path") - aCoder.encode(self.fileName, forKey: "fileName") - aCoder.encode(self.genericRequirements, forKey: "genericRequirements") - } -// sourcery:end + private static func uniqueMethodFilter(_ lhs: Method, rhs: Method) -> Bool { + return lhs.name == rhs.name && lhs.isStatic == rhs.isStatic && lhs.isClass == rhs.isClass && lhs.actualReturnTypeName == rhs.actualReturnTypeName + } -} + // sourcery: skipEquality, skipDescription + /// Subscripts defined in this type only, inluding subscripts defined in its extensions, + /// but not including subscripts inherited from superclasses (for classes only) and protocols + public var subscripts: [Subscript] { + unique({ $0.rawSubscripts }, filter: Self.uniqueSubscriptFilter) + } -extension Type { + /// Unfiltered (can contain duplications from extensions) Subscripts defined in this type only, inluding subscripts defined in its extensions, + /// but not including subscripts inherited from superclasses (for classes only) and protocols + public var rawSubscripts: [Subscript] - // sourcery: skipDescription, skipJSExport - /// :nodoc: - var isClass: Bool { - let isNotClass = self is Struct || self is Enum || self is Protocol - return !isNotClass && !isExtension + // sourcery: skipEquality, skipDescription + /// All subscripts defined for this type, including subscripts defined in extensions, + /// in superclasses (for classes only) and protocols + public var allSubscripts: [Subscript] { + return flattenAll({ $0.subscripts }, + isExtension: { $0.definedInType?.isExtension == true }, + filter: { all, extracted in + !all.contains(where: { Self.uniqueSubscriptFilter($0, rhs: extracted) }) + }) } -} - -/// Extends type so that inner types can be accessed via KVC e.g. Parent.Inner.Children -extension Type { - /// :nodoc: - override public func value(forUndefinedKey key: String) -> Any? { - if let innerType = containedTypes.lazy.filter({ $0.localName == key }).first { - return innerType - } - return super.value(forUndefinedKey: key) + private static func uniqueSubscriptFilter(_ lhs: Subscript, rhs: Subscript) -> Bool { + return lhs.parameters == rhs.parameters && lhs.returnTypeName == rhs.returnTypeName && lhs.readAccess == rhs.readAccess && lhs.writeAccess == rhs.writeAccess } -} -"""), - .init(name: "TypeName.swift", content: -""" -// -// Created by Krzysztof Zabłocki on 25/12/2016. -// Copyright (c) 2016 Pixle. All rights reserved. -// + // sourcery: skipEquality, skipDescription, skipJSExport + /// Bytes position of the body of this type in its declaration file if available. + public var bodyBytesRange: BytesRange? -import Foundation + // sourcery: skipEquality, skipDescription, skipJSExport + /// Bytes position of the whole declaration of this type in its declaration file if available. + public var completeDeclarationRange: BytesRange? -/// Describes name of the type used in typed declaration (variable, method parameter or return value etc.) -@objcMembers -public final class TypeName: NSObject, SourceryModelWithoutDescription, LosslessStringConvertible, Diffable { - /// :nodoc: - public init(name: String, - actualTypeName: TypeName? = nil, - unwrappedTypeName: String? = nil, - attributes: AttributeList = [:], - isOptional: Bool = false, - isImplicitlyUnwrappedOptional: Bool = false, - tuple: TupleType? = nil, - array: ArrayType? = nil, - dictionary: DictionaryType? = nil, - closure: ClosureType? = nil, - set: SetType? = nil, - generic: GenericType? = nil, - isProtocolComposition: Bool = false) { + private func flattenAll(_ extraction: @escaping (Type) -> [T], isExtension: (T) -> Bool, filter: ([T], T) -> Bool) -> [T] { + let all = NSMutableOrderedSet() + let allObjects = extraction(self) - let optionalSuffix: String - // TODO: TBR - if !name.hasPrefix("Optional<") && !name.contains(" where ") { - if isOptional { - optionalSuffix = "?" - } else if isImplicitlyUnwrappedOptional { - optionalSuffix = "!" + /// The order of importance for properties is: + /// Base class + /// Inheritance + /// Protocol conformance + /// Extension + + var extensions = [T]() + var baseObjects = [T]() + + allObjects.forEach { + if isExtension($0) { + extensions.append($0) } else { - optionalSuffix = "" + baseObjects.append($0) } - } else { - optionalSuffix = "" } - self.name = name + optionalSuffix - self.actualTypeName = actualTypeName - self.unwrappedTypeName = unwrappedTypeName ?? name - self.tuple = tuple - self.array = array - self.dictionary = dictionary - self.closure = closure - self.generic = generic - self.isOptional = isOptional || isImplicitlyUnwrappedOptional - self.isImplicitlyUnwrappedOptional = isImplicitlyUnwrappedOptional - self.isProtocolComposition = isProtocolComposition - self.set = set - self.attributes = attributes - self.modifiers = [] - super.init() - } - - /// Type name used in declaration - public var name: String + all.addObjects(from: baseObjects) - /// The generics of this TypeName - public var generic: GenericType? + func filteredExtraction(_ target: Type) -> [T] { + // swiftlint:disable:next force_cast + let all = all.array as! [T] + let extracted = extraction(target).filter({ filter(all, $0) }) + return extracted + } - /// Whether this TypeName is generic - public var isGeneric: Bool { - actualTypeName?.generic != nil || generic != nil - } + inherits.values.sorted(by: { $0.name < $1.name }).forEach { all.addObjects(from: filteredExtraction($0)) } + implements.values.sorted(by: { $0.name < $1.name }).forEach { all.addObjects(from: filteredExtraction($0)) } - /// Whether this TypeName is protocol composition - public var isProtocolComposition: Bool + // swiftlint:disable:next force_cast + let array = all.array as! [T] + all.addObjects(from: extensions.filter({ filter(array, $0) })) - // sourcery: skipEquality - /// Actual type name if given type name is a typealias - public var actualTypeName: TypeName? + return all.array.compactMap { $0 as? T } + } - /// Type name attributes, i.e. `@escaping` - public var attributes: AttributeList + private func unique(_ extraction: @escaping (Type) -> [T], filter: (T, T) -> Bool) -> [T] { + let all = NSMutableOrderedSet() + for nextItem in extraction(self) { + // swiftlint:disable:next force_cast + if !all.contains(where: { filter($0 as! T, nextItem) }) { + all.add(nextItem) + } + } - /// Modifiers, i.e. `escaping` - public var modifiers: [SourceryModifier] + return all.array.compactMap { $0 as? T } + } - // sourcery: skipEquality - /// Whether type is optional - public let isOptional: Bool + /// All initializers defined in this type + public var initializers: [Method] { + return methods.filter { $0.isInitializer } + } - // sourcery: skipEquality - /// Whether type is implicitly unwrapped optional - public let isImplicitlyUnwrappedOptional: Bool + /// All annotations for this type + public var annotations: Annotations = [:] - // sourcery: skipEquality - /// Type name without attributes and optional type information - public var unwrappedTypeName: String + public var documentation: Documentation = [] - // sourcery: skipEquality - /// Whether type is void (`Void` or `()`) - public var isVoid: Bool { - return name == "Void" || name == "()" || unwrappedTypeName == "Void" + /// Static variables defined in this type + public var staticVariables: [Variable] { + return variables.filter { $0.isStatic } } - /// Whether type is a tuple - public var isTuple: Bool { - actualTypeName?.tuple != nil || tuple != nil + /// Static methods defined in this type + public var staticMethods: [Method] { + return methods.filter { $0.isStatic } } - /// Tuple type data - public var tuple: TupleType? - - /// Whether type is an array - public var isArray: Bool { - actualTypeName?.array != nil || array != nil + /// Class methods defined in this type + public var classMethods: [Method] { + return methods.filter { $0.isClass } } - /// Array type data - public var array: ArrayType? - - /// Whether type is a dictionary - public var isDictionary: Bool { - actualTypeName?.dictionary != nil || dictionary != nil + /// Instance variables defined in this type + public var instanceVariables: [Variable] { + return variables.filter { !$0.isStatic } } - /// Dictionary type data - public var dictionary: DictionaryType? - - /// Whether type is a closure - public var isClosure: Bool { - actualTypeName?.closure != nil || closure != nil + /// Instance methods defined in this type + public var instanceMethods: [Method] { + return methods.filter { !$0.isStatic && !$0.isClass } } - /// Closure type data - public var closure: ClosureType? - - /// Whether type is a Set - public var isSet: Bool { - actualTypeName?.set != nil || set != nil + /// Computed instance variables defined in this type + public var computedVariables: [Variable] { + return variables.filter { $0.isComputed && !$0.isStatic } } - /// Set type data - public var set: SetType? - - /// Prints typename as it would appear on definition - public var asSource: String { - // TODO: TBR special treatment - let specialTreatment = isOptional && name.hasPrefix("Optional<") - - var description = ( - attributes.flatMap({ $0.value }).map({ $0.asSource }).sorted() + - modifiers.map({ $0.asSource }) + - [specialTreatment ? name : unwrappedTypeName] - ).joined(separator: " ") + /// Stored instance variables defined in this type + public var storedVariables: [Variable] { + return variables.filter { !$0.isComputed && !$0.isStatic } + } - if let _ = self.dictionary { // array and dictionary cases are covered by the unwrapped type name -// description.append(dictionary.asSource) - } else if let _ = self.array { -// description.append(array.asSource) - } else if let _ = self.generic { -// let arguments = generic.typeParameters -// .map({ $0.typeName.asSource }) -// .joined(separator: ", ") -// description.append("<\\(arguments)>") - } - if !specialTreatment { - if isImplicitlyUnwrappedOptional { - description.append("!") - } else if isOptional { - description.append("?") + /// Names of types this type inherits from (for classes only) and protocols it implements, in order of definition + public var inheritedTypes: [String] { + didSet { + based.removeAll() + inheritedTypes.forEach { name in + self.based[name] = name } } - - return description - } - - public override var description: String { - ( - attributes.flatMap({ $0.value }).map({ $0.asSource }).sorted() + - modifiers.map({ $0.asSource }) + - [name] - ).joined(separator: " ") } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? TypeName else { - results.append("Incorrect type ") - return results - } - results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "generic").trackDifference(actual: self.generic, expected: castObject.generic)) - results.append(contentsOf: DiffableResult(identifier: "isProtocolComposition").trackDifference(actual: self.isProtocolComposition, expected: castObject.isProtocolComposition)) - results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) - results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) - results.append(contentsOf: DiffableResult(identifier: "tuple").trackDifference(actual: self.tuple, expected: castObject.tuple)) - results.append(contentsOf: DiffableResult(identifier: "array").trackDifference(actual: self.array, expected: castObject.array)) - results.append(contentsOf: DiffableResult(identifier: "dictionary").trackDifference(actual: self.dictionary, expected: castObject.dictionary)) - results.append(contentsOf: DiffableResult(identifier: "closure").trackDifference(actual: self.closure, expected: castObject.closure)) - results.append(contentsOf: DiffableResult(identifier: "set").trackDifference(actual: self.set, expected: castObject.set)) - return results - } - - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.name) - hasher.combine(self.generic) - hasher.combine(self.isProtocolComposition) - hasher.combine(self.attributes) - hasher.combine(self.modifiers) - hasher.combine(self.tuple) - hasher.combine(self.array) - hasher.combine(self.dictionary) - hasher.combine(self.closure) - hasher.combine(self.set) - return hasher.finalize() - } - - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? TypeName else { return false } - if self.name != rhs.name { return false } - if self.generic != rhs.generic { return false } - if self.isProtocolComposition != rhs.isProtocolComposition { return false } - if self.attributes != rhs.attributes { return false } - if self.modifiers != rhs.modifiers { return false } - if self.tuple != rhs.tuple { return false } - if self.array != rhs.array { return false } - if self.dictionary != rhs.dictionary { return false } - if self.closure != rhs.closure { return false } - if self.set != rhs.set { return false } - return true - } - -// sourcery:inline:TypeName.AutoCoding + // sourcery: skipEquality, skipDescription + /// Names of types or protocols this type inherits from, including unknown (not scanned) types + public var based = [String: String]() - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { - withVaList(["name"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.name = name - self.generic = aDecoder.decode(forKey: "generic") - self.isProtocolComposition = aDecoder.decode(forKey: "isProtocolComposition") - self.actualTypeName = aDecoder.decode(forKey: "actualTypeName") - guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { - withVaList(["attributes"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.attributes = attributes - guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { - withVaList(["modifiers"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.modifiers = modifiers - self.isOptional = aDecoder.decode(forKey: "isOptional") - self.isImplicitlyUnwrappedOptional = aDecoder.decode(forKey: "isImplicitlyUnwrappedOptional") - guard let unwrappedTypeName: String = aDecoder.decode(forKey: "unwrappedTypeName") else { - withVaList(["unwrappedTypeName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.unwrappedTypeName = unwrappedTypeName - self.tuple = aDecoder.decode(forKey: "tuple") - self.array = aDecoder.decode(forKey: "array") - self.dictionary = aDecoder.decode(forKey: "dictionary") - self.closure = aDecoder.decode(forKey: "closure") - self.set = aDecoder.decode(forKey: "set") - } + // sourcery: skipEquality, skipDescription + /// Types this type inherits from or implements, including unknown (not scanned) types with extensions defined + public var basedTypes = [String: Type]() - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.generic, forKey: "generic") - aCoder.encode(self.isProtocolComposition, forKey: "isProtocolComposition") - aCoder.encode(self.actualTypeName, forKey: "actualTypeName") - aCoder.encode(self.attributes, forKey: "attributes") - aCoder.encode(self.modifiers, forKey: "modifiers") - aCoder.encode(self.isOptional, forKey: "isOptional") - aCoder.encode(self.isImplicitlyUnwrappedOptional, forKey: "isImplicitlyUnwrappedOptional") - aCoder.encode(self.unwrappedTypeName, forKey: "unwrappedTypeName") - aCoder.encode(self.tuple, forKey: "tuple") - aCoder.encode(self.array, forKey: "array") - aCoder.encode(self.dictionary, forKey: "dictionary") - aCoder.encode(self.closure, forKey: "closure") - aCoder.encode(self.set, forKey: "set") - } -// sourcery:end + /// Types this type inherits from + public var inherits = [String: Type]() // sourcery: skipEquality, skipDescription - /// :nodoc: - public override var debugDescription: String { - return name - } - - public convenience init(_ description: String) { - self.init(name: description, actualTypeName: nil) - } -} + /// Protocols this type implements + public var implements: [String: Type] = [:] -extension TypeName { - public static func unknown(description: String?, attributes: AttributeList = [:]) -> TypeName { - if let description = description { - Log.astWarning("Unknown type, please add type attribution to \\(description)") - } else { - Log.astWarning("Unknown type, please add type attribution") + /// Contained types + public var containedTypes: [Type] { + didSet { + containedTypes.forEach { + containedType[$0.localName] = $0 + $0.parent = self + } } - return TypeName(name: "UnknownTypeSoAddTypeAttributionToVariable", attributes: attributes) } -} - -"""), - .init(name: "Typealias.swift", content: -""" -import Foundation - -// sourcery: skipJSExport -/// :nodoc: -@objcMembers -public final class Typealias: NSObject, Typed, SourceryModel, Diffable { - // New typealias name - public let aliasName: String - - // Target name - public let typeName: TypeName // sourcery: skipEquality, skipDescription - public var type: Type? + /// Contained types groupd by their names + public private(set) var containedType: [String: Type] = [:] - /// module in which this typealias was declared - public var module: String? + /// Name of parent type (for contained types only) + public private(set) var parentName: String? // sourcery: skipEquality, skipDescription + /// Parent type, if known (for contained types only) public var parent: Type? { didSet { parentName = parent?.name } } - /// Type access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` - public let accessLevel: String - - var parentName: String? - - public var name: String { - if let parentName = parent?.name { - return "\\(module != nil ? "\\(module!)." : "")\\(parentName).\\(aliasName)" - } else { - return "\\(module != nil ? "\\(module!)." : "")\\(aliasName)" + // sourcery: skipJSExport + /// :nodoc: + public var parentTypes: AnyIterator { + var next: Type? = self + return AnyIterator { + next = next?.parent + return next } } - public init(aliasName: String = "", typeName: TypeName, accessLevel: AccessLevel = .internal, parent: Type? = nil, module: String? = nil) { - self.aliasName = aliasName - self.typeName = typeName - self.accessLevel = accessLevel.rawValue - self.parent = parent - self.parentName = parent?.name - self.module = module - } + // sourcery: skipEquality, skipDescription + /// Superclass type, if known (only for classes) + public var supertype: Type? - /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "aliasName = \\(String(describing: self.aliasName)), " - string += "typeName = \\(String(describing: self.typeName)), " - string += "module = \\(String(describing: self.module)), " - string += "accessLevel = \\(String(describing: self.accessLevel)), " - string += "parentName = \\(String(describing: self.parentName)), " - string += "name = \\(String(describing: self.name))" - return string - } + /// Type attributes, i.e. `@objc` + public var attributes: AttributeList - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? Typealias else { - results.append("Incorrect type ") - return results + /// Type modifiers, i.e. `private`, `final` + public var modifiers: [SourceryModifier] + + /// Path to file where the type is defined + // sourcery: skipDescription, skipEquality, skipJSExport + public var path: String? { + didSet { + if let path = path { + fileName = (path as NSString).lastPathComponent + } } - results.append(contentsOf: DiffableResult(identifier: "aliasName").trackDifference(actual: self.aliasName, expected: castObject.aliasName)) - results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) - results.append(contentsOf: DiffableResult(identifier: "module").trackDifference(actual: self.module, expected: castObject.module)) - results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) - results.append(contentsOf: DiffableResult(identifier: "parentName").trackDifference(actual: self.parentName, expected: castObject.parentName)) - return results } - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.aliasName) - hasher.combine(self.typeName) - hasher.combine(self.module) - hasher.combine(self.accessLevel) - hasher.combine(self.parentName) - return hasher.finalize() + /// Directory to file where the type is defined + // sourcery: skipDescription, skipEquality, skipJSExport + public var directory: String? { + get { + return (path as? NSString)?.deletingLastPathComponent + } } - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? Typealias else { return false } - if self.aliasName != rhs.aliasName { return false } - if self.typeName != rhs.typeName { return false } - if self.module != rhs.module { return false } - if self.accessLevel != rhs.accessLevel { return false } - if self.parentName != rhs.parentName { return false } - return true + /// list of generic requirements + public var genericRequirements: [GenericRequirement] { + didSet { + isGeneric = isGeneric || !genericRequirements.isEmpty + } } -// sourcery:inline:Typealias.AutoCoding + /// File name where the type was defined + public var fileName: String? - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let aliasName: String = aDecoder.decode(forKey: "aliasName") else { - withVaList(["aliasName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.aliasName = aliasName - guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { - withVaList(["typeName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.typeName = typeName - self.type = aDecoder.decode(forKey: "type") - self.module = aDecoder.decode(forKey: "module") - self.parent = aDecoder.decode(forKey: "parent") - guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { - withVaList(["accessLevel"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.accessLevel = accessLevel - self.parentName = aDecoder.decode(forKey: "parentName") + /// :nodoc: + public init(name: String = "", + parent: Type? = nil, + accessLevel: AccessLevel = .internal, + isExtension: Bool = false, + variables: [Variable] = [], + methods: [Method] = [], + subscripts: [Subscript] = [], + inheritedTypes: [String] = [], + containedTypes: [Type] = [], + typealiases: [Typealias] = [], + genericRequirements: [GenericRequirement] = [], + attributes: AttributeList = [:], + modifiers: [SourceryModifier] = [], + annotations: [String: NSObject] = [:], + documentation: [String] = [], + isGeneric: Bool = false, + implements: [String: Type] = [:]) { + self.localName = name + self.accessLevel = accessLevel.rawValue + self.isExtension = isExtension + self.rawVariables = variables + self.rawMethods = methods + self.rawSubscripts = subscripts + self.inheritedTypes = inheritedTypes + self.containedTypes = containedTypes + self.typealiases = [:] + self.parent = parent + self.parentName = parent?.name + self.attributes = attributes + self.modifiers = modifiers + self.annotations = annotations + self.documentation = documentation + self.isGeneric = isGeneric + self.genericRequirements = genericRequirements + self.implements = implements + super.init() + containedTypes.forEach { + containedType[$0.localName] = $0 + $0.parent = self } - - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.aliasName, forKey: "aliasName") - aCoder.encode(self.typeName, forKey: "typeName") - aCoder.encode(self.type, forKey: "type") - aCoder.encode(self.module, forKey: "module") - aCoder.encode(self.parent, forKey: "parent") - aCoder.encode(self.accessLevel, forKey: "accessLevel") - aCoder.encode(self.parentName, forKey: "parentName") + inheritedTypes.forEach { name in + self.based[name] = name } -// sourcery:end -} - -"""), - .init(name: "Typed.generated.swift", content: -""" -// Generated using Sourcery 2.0.3 — https://github.com/krzysztofzablocki/Sourcery -// DO NOT EDIT -// swiftlint:disable vertical_whitespace - - -extension AssociatedValue { - /// Whether type is optional. Shorthand for `typeName.isOptional` - public var isOptional: Bool { return typeName.isOptional } - /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` - public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } - /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` - public var unwrappedTypeName: String { return typeName.unwrappedTypeName } - /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` - public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } - /// Whether type is a tuple. Shorthand for `typeName.isTuple` - public var isTuple: Bool { return typeName.isTuple } - /// Whether type is a closure. Shorthand for `typeName.isClosure` - public var isClosure: Bool { return typeName.isClosure } - /// Whether type is an array. Shorthand for `typeName.isArray` - public var isArray: Bool { return typeName.isArray } - /// Whether type is a set. Shorthand for `typeName.isSet` - public var isSet: Bool { return typeName.isSet } - /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` - public var isDictionary: Bool { return typeName.isDictionary } -} -extension ClosureParameter { - /// Whether type is optional. Shorthand for `typeName.isOptional` - public var isOptional: Bool { return typeName.isOptional } - /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` - public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } - /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` - public var unwrappedTypeName: String { return typeName.unwrappedTypeName } - /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` - public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } - /// Whether type is a tuple. Shorthand for `typeName.isTuple` - public var isTuple: Bool { return typeName.isTuple } - /// Whether type is a closure. Shorthand for `typeName.isClosure` - public var isClosure: Bool { return typeName.isClosure } - /// Whether type is an array. Shorthand for `typeName.isArray` - public var isArray: Bool { return typeName.isArray } - /// Whether type is a set. Shorthand for `typeName.isSet` - public var isSet: Bool { return typeName.isSet } - /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` - public var isDictionary: Bool { return typeName.isDictionary } -} -extension MethodParameter { - /// Whether type is optional. Shorthand for `typeName.isOptional` - public var isOptional: Bool { return typeName.isOptional } - /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` - public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } - /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` - public var unwrappedTypeName: String { return typeName.unwrappedTypeName } - /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` - public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } - /// Whether type is a tuple. Shorthand for `typeName.isTuple` - public var isTuple: Bool { return typeName.isTuple } - /// Whether type is a closure. Shorthand for `typeName.isClosure` - public var isClosure: Bool { return typeName.isClosure } - /// Whether type is an array. Shorthand for `typeName.isArray` - public var isArray: Bool { return typeName.isArray } - /// Whether type is a set. Shorthand for `typeName.isSet` - public var isSet: Bool { return typeName.isSet } - /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` - public var isDictionary: Bool { return typeName.isDictionary } -} -extension TupleElement { - /// Whether type is optional. Shorthand for `typeName.isOptional` - public var isOptional: Bool { return typeName.isOptional } - /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` - public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } - /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` - public var unwrappedTypeName: String { return typeName.unwrappedTypeName } - /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` - public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } - /// Whether type is a tuple. Shorthand for `typeName.isTuple` - public var isTuple: Bool { return typeName.isTuple } - /// Whether type is a closure. Shorthand for `typeName.isClosure` - public var isClosure: Bool { return typeName.isClosure } - /// Whether type is an array. Shorthand for `typeName.isArray` - public var isArray: Bool { return typeName.isArray } - /// Whether type is a set. Shorthand for `typeName.isSet` - public var isSet: Bool { return typeName.isSet } - /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` - public var isDictionary: Bool { return typeName.isDictionary } -} -extension Typealias { - /// Whether type is optional. Shorthand for `typeName.isOptional` - public var isOptional: Bool { return typeName.isOptional } - /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` - public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } - /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` - public var unwrappedTypeName: String { return typeName.unwrappedTypeName } - /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` - public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } - /// Whether type is a tuple. Shorthand for `typeName.isTuple` - public var isTuple: Bool { return typeName.isTuple } - /// Whether type is a closure. Shorthand for `typeName.isClosure` - public var isClosure: Bool { return typeName.isClosure } - /// Whether type is an array. Shorthand for `typeName.isArray` - public var isArray: Bool { return typeName.isArray } - /// Whether type is a set. Shorthand for `typeName.isSet` - public var isSet: Bool { return typeName.isSet } - /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` - public var isDictionary: Bool { return typeName.isDictionary } -} -extension Variable { - /// Whether type is optional. Shorthand for `typeName.isOptional` - public var isOptional: Bool { return typeName.isOptional } - /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` - public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } - /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` - public var unwrappedTypeName: String { return typeName.unwrappedTypeName } - /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` - public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } - /// Whether type is a tuple. Shorthand for `typeName.isTuple` - public var isTuple: Bool { return typeName.isTuple } - /// Whether type is a closure. Shorthand for `typeName.isClosure` - public var isClosure: Bool { return typeName.isClosure } - /// Whether type is an array. Shorthand for `typeName.isArray` - public var isArray: Bool { return typeName.isArray } - /// Whether type is a set. Shorthand for `typeName.isSet` - public var isSet: Bool { return typeName.isSet } - /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` - public var isDictionary: Bool { return typeName.isDictionary } -} + typealiases.forEach({ + $0.parent = self + self.typealiases[$0.aliasName] = $0 + }) + } -"""), - .init(name: "Typed.swift", content: -""" -import Foundation + /// :nodoc: + public func extend(_ type: Type) { + type.annotations.forEach { self.annotations[$0.key] = $0.value } + type.inherits.forEach { self.inherits[$0.key] = $0.value } + type.implements.forEach { self.implements[$0.key] = $0.value } + self.inheritedTypes += type.inheritedTypes + self.containedTypes += type.containedTypes -/// Descibes typed declaration, i.e. variable, method parameter, tuple element, enum case associated value -public protocol Typed { + self.rawVariables += type.rawVariables + self.rawMethods += type.rawMethods + self.rawSubscripts += type.rawSubscripts + } - // sourcery: skipEquality, skipDescription - /// Type, if known - var type: Type? { get } + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + let type: Type.Type = Swift.type(of: self) + var string = "\\(type): " + string.append("module = \\(String(describing: self.module)), ") + string.append("imports = \\(String(describing: self.imports)), ") + string.append("allImports = \\(String(describing: self.allImports)), ") + string.append("typealiases = \\(String(describing: self.typealiases)), ") + string.append("isExtension = \\(String(describing: self.isExtension)), ") + string.append("kind = \\(String(describing: self.kind)), ") + string.append("accessLevel = \\(String(describing: self.accessLevel)), ") + string.append("name = \\(String(describing: self.name)), ") + string.append("isUnknownExtension = \\(String(describing: self.isUnknownExtension)), ") + string.append("isGeneric = \\(String(describing: self.isGeneric)), ") + string.append("localName = \\(String(describing: self.localName)), ") + string.append("rawVariables = \\(String(describing: self.rawVariables)), ") + string.append("rawMethods = \\(String(describing: self.rawMethods)), ") + string.append("rawSubscripts = \\(String(describing: self.rawSubscripts)), ") + string.append("initializers = \\(String(describing: self.initializers)), ") + string.append("annotations = \\(String(describing: self.annotations)), ") + string.append("documentation = \\(String(describing: self.documentation)), ") + string.append("staticVariables = \\(String(describing: self.staticVariables)), ") + string.append("staticMethods = \\(String(describing: self.staticMethods)), ") + string.append("classMethods = \\(String(describing: self.classMethods)), ") + string.append("instanceVariables = \\(String(describing: self.instanceVariables)), ") + string.append("instanceMethods = \\(String(describing: self.instanceMethods)), ") + string.append("computedVariables = \\(String(describing: self.computedVariables)), ") + string.append("storedVariables = \\(String(describing: self.storedVariables)), ") + string.append("inheritedTypes = \\(String(describing: self.inheritedTypes)), ") + string.append("inherits = \\(String(describing: self.inherits)), ") + string.append("containedTypes = \\(String(describing: self.containedTypes)), ") + string.append("parentName = \\(String(describing: self.parentName)), ") + string.append("parentTypes = \\(String(describing: self.parentTypes)), ") + string.append("attributes = \\(String(describing: self.attributes)), ") + string.append("modifiers = \\(String(describing: self.modifiers)), ") + string.append("fileName = \\(String(describing: self.fileName)), ") + string.append("genericRequirements = \\(String(describing: self.genericRequirements))") + return string + } - // sourcery: skipEquality, skipDescription - /// Type name - var typeName: TypeName { get } - - // sourcery: skipEquality, skipDescription - /// Whether type is optional - var isOptional: Bool { get } - - // sourcery: skipEquality, skipDescription - /// Whether type is implicitly unwrapped optional - var isImplicitlyUnwrappedOptional: Bool { get } - - // sourcery: skipEquality, skipDescription - /// Type name without attributes and optional type information - var unwrappedTypeName: String { get } -} - -"""), - .init(name: "Variable.swift", content: -""" -// -// Created by Krzysztof Zablocki on 13/09/2016. -// Copyright (c) 2016 Pixle. All rights reserved. -// - -import Foundation - -/// :nodoc: -public typealias SourceryVariable = Variable - -/// Defines variable -@objcMembers -public final class Variable: NSObject, SourceryModel, Typed, Annotated, Documented, Definition, Diffable { - - /// Variable name - public let name: String - - /// Variable type name - public let typeName: TypeName - - // sourcery: skipEquality, skipDescription - /// Variable type, if known, i.e. if the type is declared in the scanned sources. - /// For explanation, see - public var type: Type? - - /// Whether variable is computed and not stored - public let isComputed: Bool - - /// Whether variable is async - public let isAsync: Bool - - /// Whether variable throws - public let `throws`: Bool - - /// Whether variable is static - public let isStatic: Bool - - /// Variable read access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` - public let readAccess: String - - /// Variable write access, i.e. `internal`, `private`, `fileprivate`, `public`, `open`. - /// For immutable variables this value is empty string - public let writeAccess: String - - /// composed access level - /// sourcery: skipJSExport - public var accessLevel: (read: AccessLevel, write: AccessLevel) { - (read: AccessLevel(rawValue: readAccess) ?? .none, AccessLevel(rawValue: writeAccess) ?? .none) - } - - /// Whether variable is mutable or not - public var isMutable: Bool { - return writeAccess != AccessLevel.none.rawValue - } - - /// Variable default value expression - public var defaultValue: String? - - /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 - public var annotations: Annotations = [:] - - public var documentation: Documentation = [] - - /// Variable attributes, i.e. `@IBOutlet`, `@IBInspectable` - public var attributes: AttributeList - - /// Modifiers, i.e. `private` - public var modifiers: [SourceryModifier] - - /// Whether variable is final or not - public var isFinal: Bool { - return modifiers.contains { $0.name == Attribute.Identifier.final.rawValue } - } - - /// Whether variable is lazy or not - public var isLazy: Bool { - return modifiers.contains { $0.name == Attribute.Identifier.lazy.rawValue } - } - - /// Whether variable is dynamic or not - public var isDynamic: Bool { - modifiers.contains { $0.name == Attribute.Identifier.dynamic.rawValue } - } - - /// Reference to type name where the variable is defined, - /// nil if defined outside of any `enum`, `struct`, `class` etc - public internal(set) var definedInTypeName: TypeName? - - /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` - public var actualDefinedInTypeName: TypeName? { - return definedInTypeName?.actualTypeName ?? definedInTypeName - } - - // sourcery: skipEquality, skipDescription - /// Reference to actual type where the object is defined, - /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown - public var definedInType: Type? - - /// :nodoc: - public init(name: String = "", - typeName: TypeName, - type: Type? = nil, - accessLevel: (read: AccessLevel, write: AccessLevel) = (.internal, .internal), - isComputed: Bool = false, - isAsync: Bool = false, - `throws`: Bool = false, - isStatic: Bool = false, - defaultValue: String? = nil, - attributes: AttributeList = [:], - modifiers: [SourceryModifier] = [], - annotations: [String: NSObject] = [:], - documentation: [String] = [], - definedInTypeName: TypeName? = nil) { - - self.name = name - self.typeName = typeName - self.type = type - self.isComputed = isComputed - self.isAsync = isAsync - self.`throws` = `throws` - self.isStatic = isStatic - self.defaultValue = defaultValue - self.readAccess = accessLevel.read.rawValue - self.writeAccess = accessLevel.write.rawValue - self.attributes = attributes - self.modifiers = modifiers - self.annotations = annotations - self.documentation = documentation - self.definedInTypeName = definedInTypeName - } + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? Type else { + results.append("Incorrect type ") + return results + } + results.append(contentsOf: DiffableResult(identifier: "module").trackDifference(actual: self.module, expected: castObject.module)) + results.append(contentsOf: DiffableResult(identifier: "imports").trackDifference(actual: self.imports, expected: castObject.imports)) + results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) + results.append(contentsOf: DiffableResult(identifier: "isExtension").trackDifference(actual: self.isExtension, expected: castObject.isExtension)) + results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) + results.append(contentsOf: DiffableResult(identifier: "isUnknownExtension").trackDifference(actual: self.isUnknownExtension, expected: castObject.isUnknownExtension)) + results.append(contentsOf: DiffableResult(identifier: "isGeneric").trackDifference(actual: self.isGeneric, expected: castObject.isGeneric)) + results.append(contentsOf: DiffableResult(identifier: "localName").trackDifference(actual: self.localName, expected: castObject.localName)) + results.append(contentsOf: DiffableResult(identifier: "rawVariables").trackDifference(actual: self.rawVariables, expected: castObject.rawVariables)) + results.append(contentsOf: DiffableResult(identifier: "rawMethods").trackDifference(actual: self.rawMethods, expected: castObject.rawMethods)) + results.append(contentsOf: DiffableResult(identifier: "rawSubscripts").trackDifference(actual: self.rawSubscripts, expected: castObject.rawSubscripts)) + results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) + results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) + results.append(contentsOf: DiffableResult(identifier: "inheritedTypes").trackDifference(actual: self.inheritedTypes, expected: castObject.inheritedTypes)) + results.append(contentsOf: DiffableResult(identifier: "inherits").trackDifference(actual: self.inherits, expected: castObject.inherits)) + results.append(contentsOf: DiffableResult(identifier: "containedTypes").trackDifference(actual: self.containedTypes, expected: castObject.containedTypes)) + results.append(contentsOf: DiffableResult(identifier: "parentName").trackDifference(actual: self.parentName, expected: castObject.parentName)) + results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) + results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) + results.append(contentsOf: DiffableResult(identifier: "fileName").trackDifference(actual: self.fileName, expected: castObject.fileName)) + results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) + return results + } /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "name = \\(String(describing: self.name)), " - string += "typeName = \\(String(describing: self.typeName)), " - string += "isComputed = \\(String(describing: self.isComputed)), " - string += "isAsync = \\(String(describing: self.isAsync)), " - string += "`throws` = \\(String(describing: self.`throws`)), " - string += "isStatic = \\(String(describing: self.isStatic)), " - string += "readAccess = \\(String(describing: self.readAccess)), " - string += "writeAccess = \\(String(describing: self.writeAccess)), " - string += "accessLevel = \\(String(describing: self.accessLevel)), " - string += "isMutable = \\(String(describing: self.isMutable)), " - string += "defaultValue = \\(String(describing: self.defaultValue)), " - string += "annotations = \\(String(describing: self.annotations)), " - string += "documentation = \\(String(describing: self.documentation)), " - string += "attributes = \\(String(describing: self.attributes)), " - string += "modifiers = \\(String(describing: self.modifiers)), " - string += "isFinal = \\(String(describing: self.isFinal)), " - string += "isLazy = \\(String(describing: self.isLazy)), " - string += "isDynamic = \\(String(describing: self.isDynamic)), " - string += "definedInTypeName = \\(String(describing: self.definedInTypeName)), " - string += "actualDefinedInTypeName = \\(String(describing: self.actualDefinedInTypeName))" - return string - } - - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? Variable else { - results.append("Incorrect type ") - return results - } - results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) - results.append(contentsOf: DiffableResult(identifier: "isComputed").trackDifference(actual: self.isComputed, expected: castObject.isComputed)) - results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) - results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) - results.append(contentsOf: DiffableResult(identifier: "isStatic").trackDifference(actual: self.isStatic, expected: castObject.isStatic)) - results.append(contentsOf: DiffableResult(identifier: "readAccess").trackDifference(actual: self.readAccess, expected: castObject.readAccess)) - results.append(contentsOf: DiffableResult(identifier: "writeAccess").trackDifference(actual: self.writeAccess, expected: castObject.writeAccess)) - results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) - results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) - results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) - results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) - results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) - results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) - return results - } - + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() - hasher.combine(self.name) - hasher.combine(self.typeName) - hasher.combine(self.isComputed) - hasher.combine(self.isAsync) - hasher.combine(self.`throws`) - hasher.combine(self.isStatic) - hasher.combine(self.readAccess) - hasher.combine(self.writeAccess) - hasher.combine(self.defaultValue) + hasher.combine(self.module) + hasher.combine(self.imports) + hasher.combine(self.typealiases) + hasher.combine(self.isExtension) + hasher.combine(self.accessLevel) + hasher.combine(self.isUnknownExtension) + hasher.combine(self.isGeneric) + hasher.combine(self.localName) + hasher.combine(self.rawVariables) + hasher.combine(self.rawMethods) + hasher.combine(self.rawSubscripts) hasher.combine(self.annotations) hasher.combine(self.documentation) + hasher.combine(self.inheritedTypes) + hasher.combine(self.inherits) + hasher.combine(self.containedTypes) + hasher.combine(self.parentName) hasher.combine(self.attributes) hasher.combine(self.modifiers) - hasher.combine(self.definedInTypeName) + hasher.combine(self.fileName) + hasher.combine(self.genericRequirements) + hasher.combine(kind) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? Variable else { return false } - if self.name != rhs.name { return false } - if self.typeName != rhs.typeName { return false } - if self.isComputed != rhs.isComputed { return false } - if self.isAsync != rhs.isAsync { return false } - if self.`throws` != rhs.`throws` { return false } - if self.isStatic != rhs.isStatic { return false } - if self.readAccess != rhs.readAccess { return false } - if self.writeAccess != rhs.writeAccess { return false } - if self.defaultValue != rhs.defaultValue { return false } + guard let rhs = object as? Type else { return false } + if self.module != rhs.module { return false } + if self.imports != rhs.imports { return false } + if self.typealiases != rhs.typealiases { return false } + if self.isExtension != rhs.isExtension { return false } + if self.accessLevel != rhs.accessLevel { return false } + if self.isUnknownExtension != rhs.isUnknownExtension { return false } + if self.isGeneric != rhs.isGeneric { return false } + if self.localName != rhs.localName { return false } + if self.rawVariables != rhs.rawVariables { return false } + if self.rawMethods != rhs.rawMethods { return false } + if self.rawSubscripts != rhs.rawSubscripts { return false } if self.annotations != rhs.annotations { return false } if self.documentation != rhs.documentation { return false } + if self.inheritedTypes != rhs.inheritedTypes { return false } + if self.inherits != rhs.inherits { return false } + if self.containedTypes != rhs.containedTypes { return false } + if self.parentName != rhs.parentName { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } - if self.definedInTypeName != rhs.definedInTypeName { return false } + if self.fileName != rhs.fileName { return false } + if self.kind != rhs.kind { return false } + if self.genericRequirements != rhs.genericRequirements { return false } return true } -// sourcery:inline:Variable.AutoCoding +// sourcery:inline:Type.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { - withVaList(["name"]) { arguments in + self.module = aDecoder.decode(forKey: "module") + guard let imports: [Import] = aDecoder.decode(forKey: "imports") else { + withVaList(["imports"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.name = name - guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { - withVaList(["typeName"]) { arguments in + }; self.imports = imports + guard let typealiases: [String: Typealias] = aDecoder.decode(forKey: "typealiases") else { + withVaList(["typealiases"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.typeName = typeName - self.type = aDecoder.decode(forKey: "type") - self.isComputed = aDecoder.decode(forKey: "isComputed") - self.isAsync = aDecoder.decode(forKey: "isAsync") - self.`throws` = aDecoder.decode(forKey: "`throws`") - self.isStatic = aDecoder.decode(forKey: "isStatic") - guard let readAccess: String = aDecoder.decode(forKey: "readAccess") else { - withVaList(["readAccess"]) { arguments in + }; self.typealiases = typealiases + self.isExtension = aDecoder.decode(forKey: "isExtension") + guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { + withVaList(["accessLevel"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.readAccess = readAccess - guard let writeAccess: String = aDecoder.decode(forKey: "writeAccess") else { - withVaList(["writeAccess"]) { arguments in + }; self.accessLevel = accessLevel + self.isGeneric = aDecoder.decode(forKey: "isGeneric") + guard let localName: String = aDecoder.decode(forKey: "localName") else { + withVaList(["localName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.writeAccess = writeAccess - self.defaultValue = aDecoder.decode(forKey: "defaultValue") - guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { + }; self.localName = localName + guard let rawVariables: [Variable] = aDecoder.decode(forKey: "rawVariables") else { + withVaList(["rawVariables"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.rawVariables = rawVariables + guard let rawMethods: [Method] = aDecoder.decode(forKey: "rawMethods") else { + withVaList(["rawMethods"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.rawMethods = rawMethods + guard let rawSubscripts: [Subscript] = aDecoder.decode(forKey: "rawSubscripts") else { + withVaList(["rawSubscripts"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.rawSubscripts = rawSubscripts + self.bodyBytesRange = aDecoder.decode(forKey: "bodyBytesRange") + self.completeDeclarationRange = aDecoder.decode(forKey: "completeDeclarationRange") + guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations - guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { + guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation - guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { + guard let inheritedTypes: [String] = aDecoder.decode(forKey: "inheritedTypes") else { + withVaList(["inheritedTypes"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.inheritedTypes = inheritedTypes + guard let based: [String: String] = aDecoder.decode(forKey: "based") else { + withVaList(["based"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.based = based + guard let basedTypes: [String: Type] = aDecoder.decode(forKey: "basedTypes") else { + withVaList(["basedTypes"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.basedTypes = basedTypes + guard let inherits: [String: Type] = aDecoder.decode(forKey: "inherits") else { + withVaList(["inherits"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.inherits = inherits + guard let implements: [String: Type] = aDecoder.decode(forKey: "implements") else { + withVaList(["implements"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.implements = implements + guard let containedTypes: [Type] = aDecoder.decode(forKey: "containedTypes") else { + withVaList(["containedTypes"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.containedTypes = containedTypes + guard let containedType: [String: Type] = aDecoder.decode(forKey: "containedType") else { + withVaList(["containedType"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.containedType = containedType + self.parentName = aDecoder.decode(forKey: "parentName") + self.parent = aDecoder.decode(forKey: "parent") + self.supertype = aDecoder.decode(forKey: "supertype") + guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes - guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { + guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers - self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") - self.definedInType = aDecoder.decode(forKey: "definedInType") + self.path = aDecoder.decode(forKey: "path") + guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { + withVaList(["genericRequirements"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.genericRequirements = genericRequirements + self.fileName = aDecoder.decode(forKey: "fileName") } /// :nodoc: public func encode(with aCoder: NSCoder) { - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.typeName, forKey: "typeName") - aCoder.encode(self.type, forKey: "type") - aCoder.encode(self.isComputed, forKey: "isComputed") - aCoder.encode(self.isAsync, forKey: "isAsync") - aCoder.encode(self.`throws`, forKey: "`throws`") - aCoder.encode(self.isStatic, forKey: "isStatic") - aCoder.encode(self.readAccess, forKey: "readAccess") - aCoder.encode(self.writeAccess, forKey: "writeAccess") - aCoder.encode(self.defaultValue, forKey: "defaultValue") + aCoder.encode(self.module, forKey: "module") + aCoder.encode(self.imports, forKey: "imports") + aCoder.encode(self.typealiases, forKey: "typealiases") + aCoder.encode(self.isExtension, forKey: "isExtension") + aCoder.encode(self.accessLevel, forKey: "accessLevel") + aCoder.encode(self.isGeneric, forKey: "isGeneric") + aCoder.encode(self.localName, forKey: "localName") + aCoder.encode(self.rawVariables, forKey: "rawVariables") + aCoder.encode(self.rawMethods, forKey: "rawMethods") + aCoder.encode(self.rawSubscripts, forKey: "rawSubscripts") + aCoder.encode(self.bodyBytesRange, forKey: "bodyBytesRange") + aCoder.encode(self.completeDeclarationRange, forKey: "completeDeclarationRange") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") + aCoder.encode(self.inheritedTypes, forKey: "inheritedTypes") + aCoder.encode(self.based, forKey: "based") + aCoder.encode(self.basedTypes, forKey: "basedTypes") + aCoder.encode(self.inherits, forKey: "inherits") + aCoder.encode(self.implements, forKey: "implements") + aCoder.encode(self.containedTypes, forKey: "containedTypes") + aCoder.encode(self.containedType, forKey: "containedType") + aCoder.encode(self.parentName, forKey: "parentName") + aCoder.encode(self.parent, forKey: "parent") + aCoder.encode(self.supertype, forKey: "supertype") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") - aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") - aCoder.encode(self.definedInType, forKey: "definedInType") + aCoder.encode(self.path, forKey: "path") + aCoder.encode(self.genericRequirements, forKey: "genericRequirements") + aCoder.encode(self.fileName, forKey: "fileName") } // sourcery:end + +} + +extension Type { + + // sourcery: skipDescription, skipJSExport + /// :nodoc: + var isClass: Bool { + let isNotClass = self is Struct || self is Enum || self is Protocol + return !isNotClass && !isExtension + } +} + +/// Extends type so that inner types can be accessed via KVC e.g. Parent.Inner.Children +extension Type { + /// :nodoc: + override public func value(forUndefinedKey key: String) -> Any? { + if let innerType = containedTypes.lazy.filter({ $0.localName == key }).first { + return innerType + } + + return super.value(forUndefinedKey: key) + } +} +#endif + +"""), + .init(name: "TypeName.swift", content: +""" +// +// Created by Krzysztof Zabłocki on 25/12/2016. +// Copyright (c) 2016 Pixle. All rights reserved. +// +#if canImport(ObjectiveC) +import Foundation + +/// Describes name of the type used in typed declaration (variable, method parameter or return value etc.) +@objcMembers +public final class TypeName: NSObject, SourceryModelWithoutDescription, LosslessStringConvertible, Diffable { + /// :nodoc: + public init(name: String, + actualTypeName: TypeName? = nil, + unwrappedTypeName: String? = nil, + attributes: AttributeList = [:], + isOptional: Bool = false, + isImplicitlyUnwrappedOptional: Bool = false, + tuple: TupleType? = nil, + array: ArrayType? = nil, + dictionary: DictionaryType? = nil, + closure: ClosureType? = nil, + set: SetType? = nil, + generic: GenericType? = nil, + isProtocolComposition: Bool = false) { + + let optionalSuffix: String + // TODO: TBR + let hasPrefix: Bool = name.hasPrefix("Optional<") as Bool + let containsName: Bool = name.contains(" where ") as Bool + if !hasPrefix && !containsName { + if isOptional { + optionalSuffix = "?" + } else if isImplicitlyUnwrappedOptional { + optionalSuffix = "!" + } else { + optionalSuffix = "" + } + } else { + optionalSuffix = "" + } + + self.name = name + optionalSuffix + self.actualTypeName = actualTypeName + self.unwrappedTypeName = unwrappedTypeName ?? name + self.tuple = tuple + self.array = array + self.dictionary = dictionary + self.closure = closure + self.generic = generic + self.isOptional = isOptional || isImplicitlyUnwrappedOptional + self.isImplicitlyUnwrappedOptional = isImplicitlyUnwrappedOptional + self.isProtocolComposition = isProtocolComposition + self.set = set + self.attributes = attributes + self.modifiers = [] + super.init() + } + + /// Type name used in declaration + public var name: String + + /// The generics of this TypeName + public var generic: GenericType? + + /// Whether this TypeName is generic + public var isGeneric: Bool { + actualTypeName?.generic != nil || generic != nil + } + + /// Whether this TypeName is protocol composition + public var isProtocolComposition: Bool + + // sourcery: skipEquality + /// Actual type name if given type name is a typealias + public var actualTypeName: TypeName? + + /// Type name attributes, i.e. `@escaping` + public var attributes: AttributeList + + /// Modifiers, i.e. `escaping` + public var modifiers: [SourceryModifier] + + // sourcery: skipEquality + /// Whether type is optional + public let isOptional: Bool + + // sourcery: skipEquality + /// Whether type is implicitly unwrapped optional + public let isImplicitlyUnwrappedOptional: Bool + + // sourcery: skipEquality + /// Type name without attributes and optional type information + public var unwrappedTypeName: String + + // sourcery: skipEquality + /// Whether type is void (`Void` or `()`) + public var isVoid: Bool { + return name == "Void" || name == "()" || unwrappedTypeName == "Void" + } + + /// Whether type is a tuple + public var isTuple: Bool { + actualTypeName?.tuple != nil || tuple != nil + } + + /// Tuple type data + public var tuple: TupleType? + + /// Whether type is an array + public var isArray: Bool { + actualTypeName?.array != nil || array != nil + } + + /// Array type data + public var array: ArrayType? + + /// Whether type is a dictionary + public var isDictionary: Bool { + actualTypeName?.dictionary != nil || dictionary != nil + } + + /// Dictionary type data + public var dictionary: DictionaryType? + + /// Whether type is a closure + public var isClosure: Bool { + actualTypeName?.closure != nil || closure != nil + } + + /// Closure type data + public var closure: ClosureType? + + /// Whether type is a Set + public var isSet: Bool { + actualTypeName?.set != nil || set != nil + } + + /// Set type data + public var set: SetType? + + /// Prints typename as it would appear on definition + public var asSource: String { + // TODO: TBR special treatment + let specialTreatment: Bool = isOptional && name.hasPrefix("Optional<") + + let attributeValues: [Attribute] = attributes.flatMap { $0.value } + let attributeValuesUnsorted: [String] = attributeValues.map { $0.asSource } + var attributes: [String] = attributeValuesUnsorted.sorted() + attributes.append(contentsOf: modifiers.map({ $0.asSource })) + attributes.append(contentsOf: [specialTreatment ? name : unwrappedTypeName]) + var description = attributes.joined(separator: " ") + +// if let _ = self.dictionary { // array and dictionary cases are covered by the unwrapped type name +// description.append(dictionary.asSource) +// } else if let _ = self.array { +// description.append(array.asSource) +// } else if let _ = self.generic { +// let arguments = generic.typeParameters +// .map({ $0.typeName.asSource }) +// .joined(separator: ", ") +// description.append("<\\(arguments)>") +// } + if !specialTreatment { + if isImplicitlyUnwrappedOptional { + description.append("!") + } else if isOptional { + description.append("?") + } + } + + return description + } + + public override var description: String { + var description: [String] = attributes.flatMap({ $0.value }).map({ $0.asSource }).sorted() + description.append(contentsOf: modifiers.map({ $0.asSource })) + description.append(contentsOf: [name]) + return description.joined(separator: " ") + } + + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? TypeName else { + results.append("Incorrect type ") + return results + } + results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) + results.append(contentsOf: DiffableResult(identifier: "generic").trackDifference(actual: self.generic, expected: castObject.generic)) + results.append(contentsOf: DiffableResult(identifier: "isProtocolComposition").trackDifference(actual: self.isProtocolComposition, expected: castObject.isProtocolComposition)) + results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) + results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) + results.append(contentsOf: DiffableResult(identifier: "tuple").trackDifference(actual: self.tuple, expected: castObject.tuple)) + results.append(contentsOf: DiffableResult(identifier: "array").trackDifference(actual: self.array, expected: castObject.array)) + results.append(contentsOf: DiffableResult(identifier: "dictionary").trackDifference(actual: self.dictionary, expected: castObject.dictionary)) + results.append(contentsOf: DiffableResult(identifier: "closure").trackDifference(actual: self.closure, expected: castObject.closure)) + results.append(contentsOf: DiffableResult(identifier: "set").trackDifference(actual: self.set, expected: castObject.set)) + return results + } + + + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.name) + hasher.combine(self.generic) + hasher.combine(self.isProtocolComposition) + hasher.combine(self.attributes) + hasher.combine(self.modifiers) + hasher.combine(self.tuple) + hasher.combine(self.array) + hasher.combine(self.dictionary) + hasher.combine(self.closure) + hasher.combine(self.set) + return hasher.finalize() + } + + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? TypeName else { return false } + if self.name != rhs.name { return false } + if self.generic != rhs.generic { return false } + if self.isProtocolComposition != rhs.isProtocolComposition { return false } + if self.attributes != rhs.attributes { return false } + if self.modifiers != rhs.modifiers { return false } + if self.tuple != rhs.tuple { return false } + if self.array != rhs.array { return false } + if self.dictionary != rhs.dictionary { return false } + if self.closure != rhs.closure { return false } + if self.set != rhs.set { return false } + return true + } + +// sourcery:inline:TypeName.AutoCoding + + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let name: String = aDecoder.decode(forKey: "name") else { + withVaList(["name"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.name = name + self.generic = aDecoder.decode(forKey: "generic") + self.isProtocolComposition = aDecoder.decode(forKey: "isProtocolComposition") + self.actualTypeName = aDecoder.decode(forKey: "actualTypeName") + guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { + withVaList(["attributes"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.attributes = attributes + guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { + withVaList(["modifiers"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.modifiers = modifiers + self.isOptional = aDecoder.decode(forKey: "isOptional") + self.isImplicitlyUnwrappedOptional = aDecoder.decode(forKey: "isImplicitlyUnwrappedOptional") + guard let unwrappedTypeName: String = aDecoder.decode(forKey: "unwrappedTypeName") else { + withVaList(["unwrappedTypeName"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.unwrappedTypeName = unwrappedTypeName + self.tuple = aDecoder.decode(forKey: "tuple") + self.array = aDecoder.decode(forKey: "array") + self.dictionary = aDecoder.decode(forKey: "dictionary") + self.closure = aDecoder.decode(forKey: "closure") + self.set = aDecoder.decode(forKey: "set") + } + + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.generic, forKey: "generic") + aCoder.encode(self.isProtocolComposition, forKey: "isProtocolComposition") + aCoder.encode(self.actualTypeName, forKey: "actualTypeName") + aCoder.encode(self.attributes, forKey: "attributes") + aCoder.encode(self.modifiers, forKey: "modifiers") + aCoder.encode(self.isOptional, forKey: "isOptional") + aCoder.encode(self.isImplicitlyUnwrappedOptional, forKey: "isImplicitlyUnwrappedOptional") + aCoder.encode(self.unwrappedTypeName, forKey: "unwrappedTypeName") + aCoder.encode(self.tuple, forKey: "tuple") + aCoder.encode(self.array, forKey: "array") + aCoder.encode(self.dictionary, forKey: "dictionary") + aCoder.encode(self.closure, forKey: "closure") + aCoder.encode(self.set, forKey: "set") + } +// sourcery:end + + // sourcery: skipEquality, skipDescription + /// :nodoc: + public override var debugDescription: String { + return name + } + + public convenience init(_ description: String) { + self.init(name: description, actualTypeName: nil) + } +} + +extension TypeName { + public static func unknown(description: String?, attributes: AttributeList = [:]) -> TypeName { + if let description = description { + Log.astWarning("Unknown type, please add type attribution to \\(description)") + } else { + Log.astWarning("Unknown type, please add type attribution") + } + return TypeName(name: "UnknownTypeSoAddTypeAttributionToVariable", attributes: attributes) + } +} +#endif + +"""), + .init(name: "Types.swift", content: +""" +// +// Created by Krzysztof Zablocki on 31/12/2016. +// Copyright (c) 2016 Pixle. All rights reserved. +// + +#if canImport(ObjectiveC) +import Foundation + +// sourcery: skipJSExport +/// Collection of scanned types for accessing in templates +@objcMembers +public final class Types: NSObject, SourceryModel, Diffable { + + /// :nodoc: + public let types: [Type] + + /// All known typealiases + public let typealiases: [Typealias] + + /// :nodoc: + public init(types: [Type], typealiases: [Typealias] = []) { + self.types = types + self.typealiases = typealiases + } + + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("types = \\(String(describing: self.types)), ") + string.append("typealiases = \\(String(describing: self.typealiases))") + return string + } + + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? Types else { + results.append("Incorrect type ") + return results + } + results.append(contentsOf: DiffableResult(identifier: "types").trackDifference(actual: self.types, expected: castObject.types)) + results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) + return results + } + + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.types) + hasher.combine(self.typealiases) + return hasher.finalize() + } + + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? Types else { return false } + if self.types != rhs.types { return false } + if self.typealiases != rhs.typealiases { return false } + return true + } + +// sourcery:inline:Types.AutoCoding + + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let types: [Type] = aDecoder.decode(forKey: "types") else { + withVaList(["types"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.types = types + guard let typealiases: [Typealias] = aDecoder.decode(forKey: "typealiases") else { + withVaList(["typealiases"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.typealiases = typealiases + } + + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.types, forKey: "types") + aCoder.encode(self.typealiases, forKey: "typealiases") + } +// sourcery:end + + // sourcery: skipDescription, skipEquality, skipCoding + /// :nodoc: + public lazy internal(set) var typesByName: [String: Type] = { + var typesByName = [String: Type]() + self.types.forEach { typesByName[$0.globalName] = $0 } + return typesByName + }() + + // sourcery: skipDescription, skipEquality, skipCoding + /// :nodoc: + public lazy internal(set) var typesaliasesByName: [String: Typealias] = { + var typesaliasesByName = [String: Typealias]() + self.typealiases.forEach { typesaliasesByName[$0.name] = $0 } + return typesaliasesByName + }() + + // sourcery: skipDescription, skipEquality, skipCoding + /// All known types, excluding protocols or protocol compositions. + public lazy internal(set) var all: [Type] = { + return self.types.filter { !($0 is Protocol || $0 is ProtocolComposition) } + }() + + // sourcery: skipDescription, skipEquality, skipCoding + /// All known protocols + public lazy internal(set) var protocols: [Protocol] = { + return self.types.compactMap { $0 as? Protocol } + }() + + // sourcery: skipDescription, skipEquality, skipCoding + /// All known protocol compositions + public lazy internal(set) var protocolCompositions: [ProtocolComposition] = { + return self.types.compactMap { $0 as? ProtocolComposition } + }() + + // sourcery: skipDescription, skipEquality, skipCoding + /// All known classes + public lazy internal(set) var classes: [Class] = { + return self.all.compactMap { $0 as? Class } + }() + + // sourcery: skipDescription, skipEquality, skipCoding + /// All known structs + public lazy internal(set) var structs: [Struct] = { + return self.all.compactMap { $0 as? Struct } + }() + + // sourcery: skipDescription, skipEquality, skipCoding + /// All known enums + public lazy internal(set) var enums: [Enum] = { + return self.all.compactMap { $0 as? Enum } + }() + + // sourcery: skipDescription, skipEquality, skipCoding + /// All known extensions + public lazy internal(set) var extensions: [Type] = { + return self.all.compactMap { $0.isExtension ? $0 : nil } + }() + + // sourcery: skipDescription, skipEquality, skipCoding + /// Types based on any other type, grouped by its name, even if they are not known. + /// `types.based.MyType` returns list of types based on `MyType` + public lazy internal(set) var based: TypesCollection = { + TypesCollection( + types: self.types, + collection: { Array($0.based.keys) } + ) + }() + + // sourcery: skipDescription, skipEquality, skipCoding + /// Classes inheriting from any known class, grouped by its name. + /// `types.inheriting.MyClass` returns list of types inheriting from `MyClass` + public lazy internal(set) var inheriting: TypesCollection = { + TypesCollection( + types: self.types, + collection: { Array($0.inherits.keys) }, + validate: { type in + guard type is Class else { + throw "\\(type.name) is not a class and should be used with `implementing` or `based`" + } + }) + }() + + // sourcery: skipDescription, skipEquality, skipCoding + /// Types implementing known protocol, grouped by its name. + /// `types.implementing.MyProtocol` returns list of types implementing `MyProtocol` + public lazy internal(set) var implementing: TypesCollection = { + TypesCollection( + types: self.types, + collection: { Array($0.implements.keys) }, + validate: { type in + guard type is Protocol else { + throw "\\(type.name) is a class and should be used with `inheriting` or `based`" + } + }) + }() +} +#endif + +"""), + .init(name: "TypesCollection.swift", content: +""" +// +// Created by Krzysztof Zablocki on 31/12/2016. +// Copyright (c) 2016 Pixle. All rights reserved. +// +#if canImport(ObjectiveC) +import Foundation + +/// :nodoc: +@objcMembers +public class TypesCollection: NSObject, AutoJSExport { + // sourcery:begin: skipJSExport + let all: [Type] + let types: [String: [Type]] + let validate: ((Type) throws -> Void)? + // sourcery:end + + init(types: [Type], collection: (Type) -> [String], validate: ((Type) throws -> Void)? = nil) { + self.all = types + var content = [String: [Type]]() + self.all.forEach { type in + collection(type).forEach { name in + var list = content[name] ?? [Type]() + list.append(type) + content[name] = list + } + } + self.types = content + self.validate = validate + } + + public func types(forKey key: String) throws -> [Type] { + // In some configurations, the types are keyed by "ModuleName.TypeName" + var longKey: String? + + if let validate = validate { + guard let type = all.first(where: { $0.name == key }) else { + throw "Unknown type \\(key), should be used with `based`" + } + + try validate(type) + + if let module = type.module { + longKey = [module, type.name].joined(separator: ".") + } + } + + // If we find the types directly, return them + if let types = types[key] { + return types + } + + // if we find a types for the longKey, return them + if let longKey = longKey, let types = types[longKey] { + return types + } + + return [] + } + + /// :nodoc: + override public func value(forKey key: String) -> Any? { + do { + return try types(forKey: key) + } catch { + Log.error(error) + return nil + } + } + + /// :nodoc: + public subscript(_ key: String) -> [Type] { + do { + return try types(forKey: key) + } catch { + Log.error(error) + return [] + } + } + + override public func responds(to aSelector: Selector!) -> Bool { + return true + } +} +#endif + +"""), + .init(name: "Variable.swift", content: +""" +// +// Created by Krzysztof Zablocki on 13/09/2016. +// Copyright (c) 2016 Pixle. All rights reserved. +// +#if canImport(ObjectiveC) +import Foundation + +/// :nodoc: +public typealias SourceryVariable = Variable + +/// Defines variable +@objcMembers +public final class Variable: NSObject, SourceryModel, Typed, Annotated, Documented, Definition, Diffable { + + /// Variable name + public let name: String + + /// Variable type name + public let typeName: TypeName + + // sourcery: skipEquality, skipDescription + /// Variable type, if known, i.e. if the type is declared in the scanned sources. + /// For explanation, see + public var type: Type? + + /// Whether variable is computed and not stored + public let isComputed: Bool + + /// Whether variable is async + public let isAsync: Bool + + /// Whether variable throws + public let `throws`: Bool + + /// Whether variable is static + public let isStatic: Bool + + /// Variable read access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` + public let readAccess: String + + /// Variable write access, i.e. `internal`, `private`, `fileprivate`, `public`, `open`. + /// For immutable variables this value is empty string + public let writeAccess: String + + /// composed access level + /// sourcery: skipJSExport + public var accessLevel: (read: AccessLevel, write: AccessLevel) { + (read: AccessLevel(rawValue: readAccess) ?? .none, AccessLevel(rawValue: writeAccess) ?? .none) + } + + /// Whether variable is mutable or not + public var isMutable: Bool { + return writeAccess != AccessLevel.none.rawValue + } + + /// Variable default value expression + public var defaultValue: String? + + /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 + public var annotations: Annotations = [:] + + public var documentation: Documentation = [] + + /// Variable attributes, i.e. `@IBOutlet`, `@IBInspectable` + public var attributes: AttributeList + + /// Modifiers, i.e. `private` + public var modifiers: [SourceryModifier] + + /// Whether variable is final or not + public var isFinal: Bool { + return modifiers.contains { $0.name == Attribute.Identifier.final.rawValue } + } + + /// Whether variable is lazy or not + public var isLazy: Bool { + return modifiers.contains { $0.name == Attribute.Identifier.lazy.rawValue } + } + + /// Whether variable is dynamic or not + public var isDynamic: Bool { + modifiers.contains { $0.name == Attribute.Identifier.dynamic.rawValue } + } + + /// Reference to type name where the variable is defined, + /// nil if defined outside of any `enum`, `struct`, `class` etc + public internal(set) var definedInTypeName: TypeName? + + /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` + public var actualDefinedInTypeName: TypeName? { + return definedInTypeName?.actualTypeName ?? definedInTypeName + } + + // sourcery: skipEquality, skipDescription + /// Reference to actual type where the object is defined, + /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown + public var definedInType: Type? + + /// :nodoc: + public init(name: String = "", + typeName: TypeName, + type: Type? = nil, + accessLevel: (read: AccessLevel, write: AccessLevel) = (.internal, .internal), + isComputed: Bool = false, + isAsync: Bool = false, + `throws`: Bool = false, + isStatic: Bool = false, + defaultValue: String? = nil, + attributes: AttributeList = [:], + modifiers: [SourceryModifier] = [], + annotations: [String: NSObject] = [:], + documentation: [String] = [], + definedInTypeName: TypeName? = nil) { + + self.name = name + self.typeName = typeName + self.type = type + self.isComputed = isComputed + self.isAsync = isAsync + self.`throws` = `throws` + self.isStatic = isStatic + self.defaultValue = defaultValue + self.readAccess = accessLevel.read.rawValue + self.writeAccess = accessLevel.write.rawValue + self.attributes = attributes + self.modifiers = modifiers + self.annotations = annotations + self.documentation = documentation + self.definedInTypeName = definedInTypeName + } + + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("name = \\(String(describing: self.name)), ") + string.append("typeName = \\(String(describing: self.typeName)), ") + string.append("isComputed = \\(String(describing: self.isComputed)), ") + string.append("isAsync = \\(String(describing: self.isAsync)), ") + string.append("`throws` = \\(String(describing: self.`throws`)), ") + string.append("isStatic = \\(String(describing: self.isStatic)), ") + string.append("readAccess = \\(String(describing: self.readAccess)), ") + string.append("writeAccess = \\(String(describing: self.writeAccess)), ") + string.append("accessLevel = \\(String(describing: self.accessLevel)), ") + string.append("isMutable = \\(String(describing: self.isMutable)), ") + string.append("defaultValue = \\(String(describing: self.defaultValue)), ") + string.append("annotations = \\(String(describing: self.annotations)), ") + string.append("documentation = \\(String(describing: self.documentation)), ") + string.append("attributes = \\(String(describing: self.attributes)), ") + string.append("modifiers = \\(String(describing: self.modifiers)), ") + string.append("isFinal = \\(String(describing: self.isFinal)), ") + string.append("isLazy = \\(String(describing: self.isLazy)), ") + string.append("isDynamic = \\(String(describing: self.isDynamic)), ") + string.append("definedInTypeName = \\(String(describing: self.definedInTypeName)), ") + string.append("actualDefinedInTypeName = \\(String(describing: self.actualDefinedInTypeName))") + return string + } + + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? Variable else { + results.append("Incorrect type ") + return results + } + results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) + results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) + results.append(contentsOf: DiffableResult(identifier: "type").trackDifference(actual: self.type, expected: castObject.type)) + results.append(contentsOf: DiffableResult(identifier: "isComputed").trackDifference(actual: self.isComputed, expected: castObject.isComputed)) + results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) + results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) + results.append(contentsOf: DiffableResult(identifier: "isStatic").trackDifference(actual: self.isStatic, expected: castObject.isStatic)) + results.append(contentsOf: DiffableResult(identifier: "readAccess").trackDifference(actual: self.readAccess, expected: castObject.readAccess)) + results.append(contentsOf: DiffableResult(identifier: "writeAccess").trackDifference(actual: self.writeAccess, expected: castObject.writeAccess)) + results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) + results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) + results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) + results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) + results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) + results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) + return results + } + + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.name) + hasher.combine(self.typeName) + hasher.combine(self.isComputed) + hasher.combine(self.isAsync) + hasher.combine(self.`throws`) + hasher.combine(self.isStatic) + hasher.combine(self.readAccess) + hasher.combine(self.writeAccess) + hasher.combine(self.defaultValue) + hasher.combine(self.annotations) + hasher.combine(self.documentation) + hasher.combine(self.attributes) + hasher.combine(self.modifiers) + hasher.combine(self.definedInTypeName) + return hasher.finalize() + } + + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? Variable else { return false } + if self.name != rhs.name { return false } + if self.typeName != rhs.typeName { return false } + if self.isComputed != rhs.isComputed { return false } + if self.isAsync != rhs.isAsync { return false } + if self.`throws` != rhs.`throws` { return false } + if self.isStatic != rhs.isStatic { return false } + if self.readAccess != rhs.readAccess { return false } + if self.writeAccess != rhs.writeAccess { return false } + if self.defaultValue != rhs.defaultValue { return false } + if self.annotations != rhs.annotations { return false } + if self.documentation != rhs.documentation { return false } + if self.attributes != rhs.attributes { return false } + if self.modifiers != rhs.modifiers { return false } + if self.definedInTypeName != rhs.definedInTypeName { return false } + return true + } + +// sourcery:inline:Variable.AutoCoding + + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let name: String = aDecoder.decode(forKey: "name") else { + withVaList(["name"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.name = name + guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { + withVaList(["typeName"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.typeName = typeName + self.type = aDecoder.decode(forKey: "type") + self.isComputed = aDecoder.decode(forKey: "isComputed") + self.isAsync = aDecoder.decode(forKey: "isAsync") + self.`throws` = aDecoder.decode(forKey: "`throws`") + self.isStatic = aDecoder.decode(forKey: "isStatic") + guard let readAccess: String = aDecoder.decode(forKey: "readAccess") else { + withVaList(["readAccess"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.readAccess = readAccess + guard let writeAccess: String = aDecoder.decode(forKey: "writeAccess") else { + withVaList(["writeAccess"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.writeAccess = writeAccess + self.defaultValue = aDecoder.decode(forKey: "defaultValue") + guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { + withVaList(["annotations"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.annotations = annotations + guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { + withVaList(["documentation"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.documentation = documentation + guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { + withVaList(["attributes"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.attributes = attributes + guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { + withVaList(["modifiers"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.modifiers = modifiers + self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") + self.definedInType = aDecoder.decode(forKey: "definedInType") + } + + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.typeName, forKey: "typeName") + aCoder.encode(self.type, forKey: "type") + aCoder.encode(self.isComputed, forKey: "isComputed") + aCoder.encode(self.isAsync, forKey: "isAsync") + aCoder.encode(self.`throws`, forKey: "`throws`") + aCoder.encode(self.isStatic, forKey: "isStatic") + aCoder.encode(self.readAccess, forKey: "readAccess") + aCoder.encode(self.writeAccess, forKey: "writeAccess") + aCoder.encode(self.defaultValue, forKey: "defaultValue") + aCoder.encode(self.annotations, forKey: "annotations") + aCoder.encode(self.documentation, forKey: "documentation") + aCoder.encode(self.attributes, forKey: "attributes") + aCoder.encode(self.modifiers, forKey: "modifiers") + aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") + aCoder.encode(self.definedInType, forKey: "definedInType") + } +// sourcery:end +} +#endif + +"""), + .init(name: "AutoHashable.generated.swift", content: +""" +// Generated using Sourcery 1.3.1 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT +// swiftlint:disable all + + +// MARK: - AutoHashable for classes, protocols, structs + +// MARK: - AutoHashable for Enums + +"""), + .init(name: "Coding.generated.swift", content: +""" +// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT +// swiftlint:disable vertical_whitespace trailing_newline + +import Foundation + + +extension NSCoder { + + @nonobjc func decode(forKey: String) -> String? { + return self.maybeDecode(forKey: forKey) as String? + } + + @nonobjc func decode(forKey: String) -> TypeName? { + return self.maybeDecode(forKey: forKey) as TypeName? + } + + @nonobjc func decode(forKey: String) -> AccessLevel? { + return self.maybeDecode(forKey: forKey) as AccessLevel? + } + + @nonobjc func decode(forKey: String) -> Bool { + return self.decodeBool(forKey: forKey) + } + + @nonobjc func decode(forKey: String) -> Int { + return self.decodeInteger(forKey: forKey) + } + + func decode(forKey: String) -> E? { + return maybeDecode(forKey: forKey) as E? + } + + fileprivate func maybeDecode(forKey: String) -> E? { + guard let object = self.decodeObject(forKey: forKey) else { + return nil + } + + return object as? E + } + +} + +extension ArrayType: NSCoding {} + +extension AssociatedType: NSCoding {} + +extension AssociatedValue: NSCoding {} + +extension Attribute: NSCoding {} + +extension BytesRange: NSCoding {} + + +extension ClosureParameter: NSCoding {} + +extension ClosureType: NSCoding {} + +extension DictionaryType: NSCoding {} + + +extension EnumCase: NSCoding {} + +extension FileParserResult: NSCoding {} + +extension GenericParameter: NSCoding {} + +extension GenericRequirement: NSCoding {} + +extension GenericType: NSCoding {} + +extension GenericTypeParameter: NSCoding {} + +extension Import: NSCoding {} + +extension Method: NSCoding {} + +extension MethodParameter: NSCoding {} + +extension Modifier: NSCoding {} + + + +extension SetType: NSCoding {} + + +extension Subscript: NSCoding {} + +extension TupleElement: NSCoding {} + +extension TupleType: NSCoding {} + +extension Type: NSCoding {} + +extension TypeName: NSCoding {} + +extension Typealias: NSCoding {} + +extension Types: NSCoding {} + +extension Variable: NSCoding {} + + +"""), + .init(name: "JSExport.generated.swift", content: +""" +// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT +// swiftlint:disable vertical_whitespace trailing_newline + +#if canImport(JavaScriptCore) +import JavaScriptCore + +@objc protocol ActorAutoJSExport: JSExport { + var kind: String { get } + var isFinal: Bool { get } + var module: String? { get } + var imports: [Import] { get } + var allImports: [Import] { get } + var typealiases: [String: Typealias] { get } + var accessLevel: String { get } + var name: String { get } + var isUnknownExtension: Bool { get } + var globalName: String { get } + var isGeneric: Bool { get } + var localName: String { get } + var variables: [Variable] { get } + var rawVariables: [Variable] { get } + var allVariables: [Variable] { get } + var methods: [Method] { get } + var rawMethods: [Method] { get } + var allMethods: [Method] { get } + var subscripts: [Subscript] { get } + var rawSubscripts: [Subscript] { get } + var allSubscripts: [Subscript] { get } + var initializers: [Method] { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var staticVariables: [Variable] { get } + var staticMethods: [Method] { get } + var classMethods: [Method] { get } + var instanceVariables: [Variable] { get } + var instanceMethods: [Method] { get } + var computedVariables: [Variable] { get } + var storedVariables: [Variable] { get } + var inheritedTypes: [String] { get } + var based: [String: String] { get } + var basedTypes: [String: Type] { get } + var inherits: [String: Type] { get } + var implements: [String: Type] { get } + var containedTypes: [Type] { get } + var containedType: [String: Type] { get } + var parentName: String? { get } + var parent: Type? { get } + var supertype: Type? { get } + var attributes: AttributeList { get } + var modifiers: [SourceryModifier] { get } + var genericRequirements: [GenericRequirement] { get } + var fileName: String? { get } +} + +extension Actor: ActorAutoJSExport {} + +@objc protocol ArrayTypeAutoJSExport: JSExport { + var name: String { get } + var elementTypeName: TypeName { get } + var elementType: Type? { get } + var asGeneric: GenericType { get } + var asSource: String { get } +} + +extension ArrayType: ArrayTypeAutoJSExport {} + +@objc protocol AssociatedTypeAutoJSExport: JSExport { + var name: String { get } + var typeName: TypeName? { get } + var type: Type? { get } +} + +extension AssociatedType: AssociatedTypeAutoJSExport {} + +@objc protocol AssociatedValueAutoJSExport: JSExport { + var localName: String? { get } + var externalName: String? { get } + var typeName: TypeName { get } + var type: Type? { get } + var defaultValue: String? { get } + var annotations: Annotations { get } + var isOptional: Bool { get } + var isImplicitlyUnwrappedOptional: Bool { get } + var unwrappedTypeName: String { get } +} + +extension AssociatedValue: AssociatedValueAutoJSExport {} + +@objc protocol AttributeAutoJSExport: JSExport { + var name: String { get } + var arguments: [String: NSObject] { get } + var asSource: String { get } + var description: String { get } +} + +extension Attribute: AttributeAutoJSExport {} + +@objc protocol BytesRangeAutoJSExport: JSExport { + var offset: Int64 { get } + var length: Int64 { get } +} + +extension BytesRange: BytesRangeAutoJSExport {} + +@objc protocol ClassAutoJSExport: JSExport { + var kind: String { get } + var isFinal: Bool { get } + var module: String? { get } + var imports: [Import] { get } + var allImports: [Import] { get } + var typealiases: [String: Typealias] { get } + var accessLevel: String { get } + var name: String { get } + var isUnknownExtension: Bool { get } + var globalName: String { get } + var isGeneric: Bool { get } + var localName: String { get } + var variables: [Variable] { get } + var rawVariables: [Variable] { get } + var allVariables: [Variable] { get } + var methods: [Method] { get } + var rawMethods: [Method] { get } + var allMethods: [Method] { get } + var subscripts: [Subscript] { get } + var rawSubscripts: [Subscript] { get } + var allSubscripts: [Subscript] { get } + var initializers: [Method] { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var staticVariables: [Variable] { get } + var staticMethods: [Method] { get } + var classMethods: [Method] { get } + var instanceVariables: [Variable] { get } + var instanceMethods: [Method] { get } + var computedVariables: [Variable] { get } + var storedVariables: [Variable] { get } + var inheritedTypes: [String] { get } + var based: [String: String] { get } + var basedTypes: [String: Type] { get } + var inherits: [String: Type] { get } + var implements: [String: Type] { get } + var containedTypes: [Type] { get } + var containedType: [String: Type] { get } + var parentName: String? { get } + var parent: Type? { get } + var supertype: Type? { get } + var attributes: AttributeList { get } + var modifiers: [SourceryModifier] { get } + var genericRequirements: [GenericRequirement] { get } + var fileName: String? { get } +} + +extension Class: ClassAutoJSExport {} + +@objc protocol ClosureParameterAutoJSExport: JSExport { + var argumentLabel: String? { get } + var name: String? { get } + var typeName: TypeName { get } + var `inout`: Bool { get } + var type: Type? { get } + var isVariadic: Bool { get } + var typeAttributes: AttributeList { get } + var defaultValue: String? { get } + var annotations: Annotations { get } + var asSource: String { get } + var isOptional: Bool { get } + var isImplicitlyUnwrappedOptional: Bool { get } + var unwrappedTypeName: String { get } +} + +extension ClosureParameter: ClosureParameterAutoJSExport {} + +@objc protocol ClosureTypeAutoJSExport: JSExport { + var name: String { get } + var parameters: [ClosureParameter] { get } + var returnTypeName: TypeName { get } + var actualReturnTypeName: TypeName { get } + var returnType: Type? { get } + var isOptionalReturnType: Bool { get } + var isImplicitlyUnwrappedOptionalReturnType: Bool { get } + var unwrappedReturnTypeName: String { get } + var isAsync: Bool { get } + var asyncKeyword: String? { get } + var `throws`: Bool { get } + var throwsOrRethrowsKeyword: String? { get } + var asSource: String { get } +} + +extension ClosureType: ClosureTypeAutoJSExport {} + +@objc protocol DictionaryTypeAutoJSExport: JSExport { + var name: String { get } + var valueTypeName: TypeName { get } + var valueType: Type? { get } + var keyTypeName: TypeName { get } + var keyType: Type? { get } + var asGeneric: GenericType { get } + var asSource: String { get } +} + +extension DictionaryType: DictionaryTypeAutoJSExport {} + +@objc protocol EnumAutoJSExport: JSExport { + var kind: String { get } + var cases: [EnumCase] { get } + var rawTypeName: TypeName? { get } + var hasRawType: Bool { get } + var rawType: Type? { get } + var based: [String: String] { get } + var hasAssociatedValues: Bool { get } + var module: String? { get } + var imports: [Import] { get } + var allImports: [Import] { get } + var typealiases: [String: Typealias] { get } + var accessLevel: String { get } + var name: String { get } + var isUnknownExtension: Bool { get } + var globalName: String { get } + var isGeneric: Bool { get } + var localName: String { get } + var variables: [Variable] { get } + var rawVariables: [Variable] { get } + var allVariables: [Variable] { get } + var methods: [Method] { get } + var rawMethods: [Method] { get } + var allMethods: [Method] { get } + var subscripts: [Subscript] { get } + var rawSubscripts: [Subscript] { get } + var allSubscripts: [Subscript] { get } + var initializers: [Method] { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var staticVariables: [Variable] { get } + var staticMethods: [Method] { get } + var classMethods: [Method] { get } + var instanceVariables: [Variable] { get } + var instanceMethods: [Method] { get } + var computedVariables: [Variable] { get } + var storedVariables: [Variable] { get } + var inheritedTypes: [String] { get } + var basedTypes: [String: Type] { get } + var inherits: [String: Type] { get } + var implements: [String: Type] { get } + var containedTypes: [Type] { get } + var containedType: [String: Type] { get } + var parentName: String? { get } + var parent: Type? { get } + var supertype: Type? { get } + var attributes: AttributeList { get } + var modifiers: [SourceryModifier] { get } + var genericRequirements: [GenericRequirement] { get } + var fileName: String? { get } +} + +extension Enum: EnumAutoJSExport {} + +@objc protocol EnumCaseAutoJSExport: JSExport { + var name: String { get } + var rawValue: String? { get } + var associatedValues: [AssociatedValue] { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var indirect: Bool { get } + var hasAssociatedValue: Bool { get } +} + +extension EnumCase: EnumCaseAutoJSExport {} + + +@objc protocol GenericParameterAutoJSExport: JSExport { + var name: String { get } + var inheritedTypeName: TypeName? { get } +} + +extension GenericParameter: GenericParameterAutoJSExport {} + +@objc protocol GenericRequirementAutoJSExport: JSExport { + var leftType: AssociatedType { get } + var rightType: GenericTypeParameter { get } + var relationship: String { get } + var relationshipSyntax: String { get } +} + +extension GenericRequirement: GenericRequirementAutoJSExport {} + +@objc protocol GenericTypeAutoJSExport: JSExport { + var name: String { get } + var typeParameters: [GenericTypeParameter] { get } + var asSource: String { get } + var description: String { get } +} + +extension GenericType: GenericTypeAutoJSExport {} + +@objc protocol GenericTypeParameterAutoJSExport: JSExport { + var typeName: TypeName { get } + var type: Type? { get } +} + +extension GenericTypeParameter: GenericTypeParameterAutoJSExport {} + +@objc protocol ImportAutoJSExport: JSExport { + var kind: String? { get } + var path: String { get } + var description: String { get } + var moduleName: String { get } +} + +extension Import: ImportAutoJSExport {} + +@objc protocol MethodAutoJSExport: JSExport { + var name: String { get } + var selectorName: String { get } + var shortName: String { get } + var callName: String { get } + var parameters: [MethodParameter] { get } + var returnTypeName: TypeName { get } + var actualReturnTypeName: TypeName { get } + var returnType: Type? { get } + var isOptionalReturnType: Bool { get } + var isImplicitlyUnwrappedOptionalReturnType: Bool { get } + var unwrappedReturnTypeName: String { get } + var isAsync: Bool { get } + var `throws`: Bool { get } + var `rethrows`: Bool { get } + var accessLevel: String { get } + var isStatic: Bool { get } + var isClass: Bool { get } + var isInitializer: Bool { get } + var isDeinitializer: Bool { get } + var isFailableInitializer: Bool { get } + var isConvenienceInitializer: Bool { get } + var isRequired: Bool { get } + var isFinal: Bool { get } + var isMutating: Bool { get } + var isGeneric: Bool { get } + var isOptional: Bool { get } + var isNonisolated: Bool { get } + var isDynamic: Bool { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var definedInTypeName: TypeName? { get } + var actualDefinedInTypeName: TypeName? { get } + var definedInType: Type? { get } + var attributes: AttributeList { get } + var modifiers: [SourceryModifier] { get } + var genericRequirements: [GenericRequirement] { get } +} + +extension Method: MethodAutoJSExport {} + +@objc protocol MethodParameterAutoJSExport: JSExport { + var argumentLabel: String? { get } + var name: String { get } + var typeName: TypeName { get } + var `inout`: Bool { get } + var isVariadic: Bool { get } + var type: Type? { get } + var typeAttributes: AttributeList { get } + var defaultValue: String? { get } + var annotations: Annotations { get } + var asSource: String { get } + var isOptional: Bool { get } + var isImplicitlyUnwrappedOptional: Bool { get } + var unwrappedTypeName: String { get } +} + +extension MethodParameter: MethodParameterAutoJSExport {} + +@objc protocol ModifierAutoJSExport: JSExport { + var name: String { get } + var detail: String? { get } + var asSource: String { get } +} + +extension Modifier: ModifierAutoJSExport {} + +@objc protocol ProtocolAutoJSExport: JSExport { + var kind: String { get } + var associatedTypes: [String: AssociatedType] { get } + var genericRequirements: [GenericRequirement] { get } + var module: String? { get } + var imports: [Import] { get } + var allImports: [Import] { get } + var typealiases: [String: Typealias] { get } + var accessLevel: String { get } + var name: String { get } + var isUnknownExtension: Bool { get } + var globalName: String { get } + var isGeneric: Bool { get } + var localName: String { get } + var variables: [Variable] { get } + var rawVariables: [Variable] { get } + var allVariables: [Variable] { get } + var methods: [Method] { get } + var rawMethods: [Method] { get } + var allMethods: [Method] { get } + var subscripts: [Subscript] { get } + var rawSubscripts: [Subscript] { get } + var allSubscripts: [Subscript] { get } + var initializers: [Method] { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var staticVariables: [Variable] { get } + var staticMethods: [Method] { get } + var classMethods: [Method] { get } + var instanceVariables: [Variable] { get } + var instanceMethods: [Method] { get } + var computedVariables: [Variable] { get } + var storedVariables: [Variable] { get } + var inheritedTypes: [String] { get } + var based: [String: String] { get } + var basedTypes: [String: Type] { get } + var inherits: [String: Type] { get } + var implements: [String: Type] { get } + var containedTypes: [Type] { get } + var containedType: [String: Type] { get } + var parentName: String? { get } + var parent: Type? { get } + var supertype: Type? { get } + var attributes: AttributeList { get } + var modifiers: [SourceryModifier] { get } + var fileName: String? { get } +} + +extension Protocol: ProtocolAutoJSExport {} + +@objc protocol ProtocolCompositionAutoJSExport: JSExport { + var kind: String { get } + var composedTypeNames: [TypeName] { get } + var composedTypes: [Type]? { get } + var module: String? { get } + var imports: [Import] { get } + var allImports: [Import] { get } + var typealiases: [String: Typealias] { get } + var accessLevel: String { get } + var name: String { get } + var isUnknownExtension: Bool { get } + var globalName: String { get } + var isGeneric: Bool { get } + var localName: String { get } + var variables: [Variable] { get } + var rawVariables: [Variable] { get } + var allVariables: [Variable] { get } + var methods: [Method] { get } + var rawMethods: [Method] { get } + var allMethods: [Method] { get } + var subscripts: [Subscript] { get } + var rawSubscripts: [Subscript] { get } + var allSubscripts: [Subscript] { get } + var initializers: [Method] { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var staticVariables: [Variable] { get } + var staticMethods: [Method] { get } + var classMethods: [Method] { get } + var instanceVariables: [Variable] { get } + var instanceMethods: [Method] { get } + var computedVariables: [Variable] { get } + var storedVariables: [Variable] { get } + var inheritedTypes: [String] { get } + var based: [String: String] { get } + var basedTypes: [String: Type] { get } + var inherits: [String: Type] { get } + var implements: [String: Type] { get } + var containedTypes: [Type] { get } + var containedType: [String: Type] { get } + var parentName: String? { get } + var parent: Type? { get } + var supertype: Type? { get } + var attributes: AttributeList { get } + var modifiers: [SourceryModifier] { get } + var genericRequirements: [GenericRequirement] { get } + var fileName: String? { get } +} + +extension ProtocolComposition: ProtocolCompositionAutoJSExport {} + +@objc protocol SetTypeAutoJSExport: JSExport { + var name: String { get } + var elementTypeName: TypeName { get } + var elementType: Type? { get } + var asGeneric: GenericType { get } + var asSource: String { get } +} + +extension SetType: SetTypeAutoJSExport {} + + + +@objc protocol StructAutoJSExport: JSExport { + var kind: String { get } + var module: String? { get } + var imports: [Import] { get } + var allImports: [Import] { get } + var typealiases: [String: Typealias] { get } + var accessLevel: String { get } + var name: String { get } + var isUnknownExtension: Bool { get } + var globalName: String { get } + var isGeneric: Bool { get } + var localName: String { get } + var variables: [Variable] { get } + var rawVariables: [Variable] { get } + var allVariables: [Variable] { get } + var methods: [Method] { get } + var rawMethods: [Method] { get } + var allMethods: [Method] { get } + var subscripts: [Subscript] { get } + var rawSubscripts: [Subscript] { get } + var allSubscripts: [Subscript] { get } + var initializers: [Method] { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var staticVariables: [Variable] { get } + var staticMethods: [Method] { get } + var classMethods: [Method] { get } + var instanceVariables: [Variable] { get } + var instanceMethods: [Method] { get } + var computedVariables: [Variable] { get } + var storedVariables: [Variable] { get } + var inheritedTypes: [String] { get } + var based: [String: String] { get } + var basedTypes: [String: Type] { get } + var inherits: [String: Type] { get } + var implements: [String: Type] { get } + var containedTypes: [Type] { get } + var containedType: [String: Type] { get } + var parentName: String? { get } + var parent: Type? { get } + var supertype: Type? { get } + var attributes: AttributeList { get } + var modifiers: [SourceryModifier] { get } + var genericRequirements: [GenericRequirement] { get } + var fileName: String? { get } +} + +extension Struct: StructAutoJSExport {} + +@objc protocol SubscriptAutoJSExport: JSExport { + var parameters: [MethodParameter] { get } + var returnTypeName: TypeName { get } + var actualReturnTypeName: TypeName { get } + var returnType: Type? { get } + var isOptionalReturnType: Bool { get } + var isImplicitlyUnwrappedOptionalReturnType: Bool { get } + var unwrappedReturnTypeName: String { get } + var isFinal: Bool { get } + var readAccess: String { get } + var writeAccess: String { get } + var isAsync: Bool { get } + var `throws`: Bool { get } + var isMutable: Bool { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var definedInTypeName: TypeName? { get } + var actualDefinedInTypeName: TypeName? { get } + var definedInType: Type? { get } + var attributes: AttributeList { get } + var modifiers: [SourceryModifier] { get } + var genericParameters: [GenericParameter] { get } + var genericRequirements: [GenericRequirement] { get } + var isGeneric: Bool { get } +} + +extension Subscript: SubscriptAutoJSExport {} + +@objc protocol TemplateContextAutoJSExport: JSExport { + var functions: [SourceryMethod] { get } + var types: Types { get } + var argument: [String: NSObject] { get } + var type: [String: Type] { get } + var stencilContext: [String: Any] { get } + var jsContext: [String: Any] { get } +} + +extension TemplateContext: TemplateContextAutoJSExport {} + +@objc protocol TupleElementAutoJSExport: JSExport { + var name: String? { get } + var typeName: TypeName { get } + var type: Type? { get } + var asSource: String { get } + var isOptional: Bool { get } + var isImplicitlyUnwrappedOptional: Bool { get } + var unwrappedTypeName: String { get } +} + +extension TupleElement: TupleElementAutoJSExport {} + +@objc protocol TupleTypeAutoJSExport: JSExport { + var name: String { get } + var elements: [TupleElement] { get } +} + +extension TupleType: TupleTypeAutoJSExport {} + +@objc protocol TypeAutoJSExport: JSExport { + var module: String? { get } + var imports: [Import] { get } + var allImports: [Import] { get } + var typealiases: [String: Typealias] { get } + var kind: String { get } + var accessLevel: String { get } + var name: String { get } + var isUnknownExtension: Bool { get } + var globalName: String { get } + var isGeneric: Bool { get } + var localName: String { get } + var variables: [Variable] { get } + var rawVariables: [Variable] { get } + var allVariables: [Variable] { get } + var methods: [Method] { get } + var rawMethods: [Method] { get } + var allMethods: [Method] { get } + var subscripts: [Subscript] { get } + var rawSubscripts: [Subscript] { get } + var allSubscripts: [Subscript] { get } + var initializers: [Method] { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var staticVariables: [Variable] { get } + var staticMethods: [Method] { get } + var classMethods: [Method] { get } + var instanceVariables: [Variable] { get } + var instanceMethods: [Method] { get } + var computedVariables: [Variable] { get } + var storedVariables: [Variable] { get } + var inheritedTypes: [String] { get } + var based: [String: String] { get } + var basedTypes: [String: Type] { get } + var inherits: [String: Type] { get } + var implements: [String: Type] { get } + var containedTypes: [Type] { get } + var containedType: [String: Type] { get } + var parentName: String? { get } + var parent: Type? { get } + var supertype: Type? { get } + var attributes: AttributeList { get } + var modifiers: [SourceryModifier] { get } + var genericRequirements: [GenericRequirement] { get } + var fileName: String? { get } +} + +extension Type: TypeAutoJSExport {} + +@objc protocol TypeNameAutoJSExport: JSExport { + var name: String { get } + var generic: GenericType? { get } + var isGeneric: Bool { get } + var isProtocolComposition: Bool { get } + var actualTypeName: TypeName? { get } + var attributes: AttributeList { get } + var modifiers: [SourceryModifier] { get } + var isOptional: Bool { get } + var isImplicitlyUnwrappedOptional: Bool { get } + var unwrappedTypeName: String { get } + var isVoid: Bool { get } + var isTuple: Bool { get } + var tuple: TupleType? { get } + var isArray: Bool { get } + var array: ArrayType? { get } + var isDictionary: Bool { get } + var dictionary: DictionaryType? { get } + var isClosure: Bool { get } + var closure: ClosureType? { get } + var isSet: Bool { get } + var set: SetType? { get } + var asSource: String { get } + var description: String { get } + var debugDescription: String { get } +} + +extension TypeName: TypeNameAutoJSExport {} + +@objc protocol TypealiasAutoJSExport: JSExport { + var aliasName: String { get } + var typeName: TypeName { get } + var type: Type? { get } + var module: String? { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var parent: Type? { get } + var accessLevel: String { get } + var parentName: String? { get } + var name: String { get } + var isOptional: Bool { get } + var isImplicitlyUnwrappedOptional: Bool { get } + var unwrappedTypeName: String { get } +} + +extension Typealias: TypealiasAutoJSExport {} + + +@objc protocol TypesCollectionAutoJSExport: JSExport { +} + +extension TypesCollection: TypesCollectionAutoJSExport {} + +@objc protocol VariableAutoJSExport: JSExport { + var name: String { get } + var typeName: TypeName { get } + var type: Type? { get } + var isComputed: Bool { get } + var isAsync: Bool { get } + var `throws`: Bool { get } + var isStatic: Bool { get } + var readAccess: String { get } + var writeAccess: String { get } + var isMutable: Bool { get } + var defaultValue: String? { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var attributes: AttributeList { get } + var modifiers: [SourceryModifier] { get } + var isFinal: Bool { get } + var isLazy: Bool { get } + var isDynamic: Bool { get } + var definedInTypeName: TypeName? { get } + var actualDefinedInTypeName: TypeName? { get } + var definedInType: Type? { get } + var isOptional: Bool { get } + var isImplicitlyUnwrappedOptional: Bool { get } + var unwrappedTypeName: String { get } +} + +extension Variable: VariableAutoJSExport {} + + +#endif +"""), + .init(name: "Typed.generated.swift", content: +""" +// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT +// swiftlint:disable vertical_whitespace + + +extension AssociatedValue { + /// Whether type is optional. Shorthand for `typeName.isOptional` + public var isOptional: Bool { return typeName.isOptional } + /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` + public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } + /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` + public var unwrappedTypeName: String { return typeName.unwrappedTypeName } + /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` + public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } + /// Whether type is a tuple. Shorthand for `typeName.isTuple` + public var isTuple: Bool { return typeName.isTuple } + /// Whether type is a closure. Shorthand for `typeName.isClosure` + public var isClosure: Bool { return typeName.isClosure } + /// Whether type is an array. Shorthand for `typeName.isArray` + public var isArray: Bool { return typeName.isArray } + /// Whether type is a set. Shorthand for `typeName.isSet` + public var isSet: Bool { return typeName.isSet } + /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` + public var isDictionary: Bool { return typeName.isDictionary } +} +extension ClosureParameter { + /// Whether type is optional. Shorthand for `typeName.isOptional` + public var isOptional: Bool { return typeName.isOptional } + /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` + public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } + /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` + public var unwrappedTypeName: String { return typeName.unwrappedTypeName } + /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` + public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } + /// Whether type is a tuple. Shorthand for `typeName.isTuple` + public var isTuple: Bool { return typeName.isTuple } + /// Whether type is a closure. Shorthand for `typeName.isClosure` + public var isClosure: Bool { return typeName.isClosure } + /// Whether type is an array. Shorthand for `typeName.isArray` + public var isArray: Bool { return typeName.isArray } + /// Whether type is a set. Shorthand for `typeName.isSet` + public var isSet: Bool { return typeName.isSet } + /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` + public var isDictionary: Bool { return typeName.isDictionary } +} +extension MethodParameter { + /// Whether type is optional. Shorthand for `typeName.isOptional` + public var isOptional: Bool { return typeName.isOptional } + /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` + public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } + /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` + public var unwrappedTypeName: String { return typeName.unwrappedTypeName } + /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` + public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } + /// Whether type is a tuple. Shorthand for `typeName.isTuple` + public var isTuple: Bool { return typeName.isTuple } + /// Whether type is a closure. Shorthand for `typeName.isClosure` + public var isClosure: Bool { return typeName.isClosure } + /// Whether type is an array. Shorthand for `typeName.isArray` + public var isArray: Bool { return typeName.isArray } + /// Whether type is a set. Shorthand for `typeName.isSet` + public var isSet: Bool { return typeName.isSet } + /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` + public var isDictionary: Bool { return typeName.isDictionary } +} +extension TupleElement { + /// Whether type is optional. Shorthand for `typeName.isOptional` + public var isOptional: Bool { return typeName.isOptional } + /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` + public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } + /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` + public var unwrappedTypeName: String { return typeName.unwrappedTypeName } + /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` + public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } + /// Whether type is a tuple. Shorthand for `typeName.isTuple` + public var isTuple: Bool { return typeName.isTuple } + /// Whether type is a closure. Shorthand for `typeName.isClosure` + public var isClosure: Bool { return typeName.isClosure } + /// Whether type is an array. Shorthand for `typeName.isArray` + public var isArray: Bool { return typeName.isArray } + /// Whether type is a set. Shorthand for `typeName.isSet` + public var isSet: Bool { return typeName.isSet } + /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` + public var isDictionary: Bool { return typeName.isDictionary } +} +extension Typealias { + /// Whether type is optional. Shorthand for `typeName.isOptional` + public var isOptional: Bool { return typeName.isOptional } + /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` + public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } + /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` + public var unwrappedTypeName: String { return typeName.unwrappedTypeName } + /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` + public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } + /// Whether type is a tuple. Shorthand for `typeName.isTuple` + public var isTuple: Bool { return typeName.isTuple } + /// Whether type is a closure. Shorthand for `typeName.isClosure` + public var isClosure: Bool { return typeName.isClosure } + /// Whether type is an array. Shorthand for `typeName.isArray` + public var isArray: Bool { return typeName.isArray } + /// Whether type is a set. Shorthand for `typeName.isSet` + public var isSet: Bool { return typeName.isSet } + /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` + public var isDictionary: Bool { return typeName.isDictionary } +} +extension Variable { + /// Whether type is optional. Shorthand for `typeName.isOptional` + public var isOptional: Bool { return typeName.isOptional } + /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` + public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } + /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` + public var unwrappedTypeName: String { return typeName.unwrappedTypeName } + /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` + public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } + /// Whether type is a tuple. Shorthand for `typeName.isTuple` + public var isTuple: Bool { return typeName.isTuple } + /// Whether type is a closure. Shorthand for `typeName.isClosure` + public var isClosure: Bool { return typeName.isClosure } + /// Whether type is an array. Shorthand for `typeName.isArray` + public var isArray: Bool { return typeName.isArray } + /// Whether type is a set. Shorthand for `typeName.isSet` + public var isSet: Bool { return typeName.isSet } + /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` + public var isDictionary: Bool { return typeName.isDictionary } } """), diff --git a/SourcerySwift/Sources/SourceryRuntime_Linux.content.generated.swift b/SourcerySwift/Sources/SourceryRuntime_Linux.content.generated.swift index 4f5215a8b..decd40a02 100644 --- a/SourcerySwift/Sources/SourceryRuntime_Linux.content.generated.swift +++ b/SourcerySwift/Sources/SourceryRuntime_Linux.content.generated.swift @@ -11,6 +11,7 @@ import Foundation /// :nodoc: public enum AccessLevel: String { + case `package` = "package" case `internal` = "internal" case `private` = "private" case `fileprivate` = "fileprivate" @@ -19,81 +20,6 @@ public enum AccessLevel: String { case none = "" } -"""), - .init(name: "GenericParameter.swift", content: -""" -import Foundation - -/// Descibes Swift generic parameter -public final class GenericParameter: NSObject, SourceryModel, Diffable { - - /// Generic parameter name - public var name: String - - /// Generic parameter inherited type - public var inheritedTypeName: TypeName? - - /// :nodoc: - public init(name: String, inheritedTypeName: TypeName? = nil) { - self.name = name - self.inheritedTypeName = inheritedTypeName - } - - /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "name = \\(String(describing: self.name)), " - string += "inheritedTypeName = \\(String(describing: self.inheritedTypeName))" - return string - } - - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? GenericParameter else { - results.append("Incorrect type ") - return results - } - results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "inheritedTypeName").trackDifference(actual: self.inheritedTypeName, expected: castObject.inheritedTypeName)) - return results - } - - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.name) - hasher.combine(self.inheritedTypeName) - return hasher.finalize() - } - - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? GenericParameter else { return false } - if self.name != rhs.name { return false } - if self.inheritedTypeName != rhs.inheritedTypeName { return false } - return true - } - -// sourcery:inline:GenericParameter.AutoCoding - - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { - withVaList(["name"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.name = name - self.inheritedTypeName = aDecoder.decode(forKey: "inheritedTypeName") - } - - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.inheritedTypeName, forKey: "inheritedTypeName") - } - -// sourcery:end -} """), .init(name: "Actor.swift", content: """ @@ -101,13 +27,16 @@ import Foundation // sourcery: skipDescription /// Descibes Swift actor +#if canImport(ObjectiveC) +@objc(SwiftActor) @objcMembers +#endif public final class Actor: Type { /// Returns "actor" public override var kind: String { return "actor" } /// Whether type is final public var isFinal: Bool { - return modifiers.contains { $0.name == "final" } + modifiers.contains { $0.name == "final" } } /// :nodoc: @@ -150,11 +79,12 @@ public final class Actor: Type { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = super.description - string += ", " - string += "kind = \\(String(describing: self.kind)), " - string += "isFinal = \\(String(describing: self.isFinal))" + string.append(", ") + string.append("kind = \\(String(describing: self.kind)), ") + string.append("isFinal = \\(String(describing: self.isFinal))") return string } @@ -168,6 +98,8 @@ public final class Actor: Type { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(super.hash) @@ -192,7 +124,7 @@ public final class Actor: Type { super.encode(with: aCoder) } // sourcery:end - + } """), @@ -261,111 +193,15 @@ public extension Array { } } -"""), - .init(name: "Set.swift", content: -""" -import Foundation - -/// Describes set type -public final class SetType: NSObject, SourceryModel, Diffable { - /// Type name used in declaration - public var name: String - - /// Array element type name - public var elementTypeName: TypeName - - // sourcery: skipEquality, skipDescription - /// Array element type, if known - public var elementType: Type? - - /// :nodoc: - public init(name: String, elementTypeName: TypeName, elementType: Type? = nil) { - self.name = name - self.elementTypeName = elementTypeName - self.elementType = elementType - } - - /// Returns array as generic type - public var asGeneric: GenericType { - GenericType(name: "Set", typeParameters: [ - .init(typeName: elementTypeName) - ]) - } - - public var asSource: String { - "[\\(elementTypeName.asSource)]" - } - - /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "name = \\(String(describing: self.name)), " - string += "elementTypeName = \\(String(describing: self.elementTypeName)), " - string += "asGeneric = \\(String(describing: self.asGeneric)), " - string += "asSource = \\(String(describing: self.asSource))" - return string - } - - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? SetType else { - results.append("Incorrect type ") - return results - } - results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "elementTypeName").trackDifference(actual: self.elementTypeName, expected: castObject.elementTypeName)) - return results - } - - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.name) - hasher.combine(self.elementTypeName) - return hasher.finalize() - } - - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? SetType else { return false } - if self.name != rhs.name { return false } - if self.elementTypeName != rhs.elementTypeName { return false } - return true - } - -// sourcery:inline:SetType.AutoCoding - - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { - withVaList(["name"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.name = name - guard let elementTypeName: TypeName = aDecoder.decode(forKey: "elementTypeName") else { - withVaList(["elementTypeName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.elementTypeName = elementTypeName - self.elementType = aDecoder.decode(forKey: "elementType") - } - - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.elementTypeName, forKey: "elementTypeName") - aCoder.encode(self.elementType, forKey: "elementType") - } -// sourcery:end -} - """), .init(name: "Array.swift", content: """ import Foundation /// Describes array type +#if canImport(ObjectiveC) +@objcMembers +#endif public final class ArrayType: NSObject, SourceryModel, Diffable { /// Type name used in declaration public var name: String @@ -396,12 +232,13 @@ public final class ArrayType: NSObject, SourceryModel, Diffable { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " - string += "name = \\(String(describing: self.name)), " - string += "elementTypeName = \\(String(describing: self.elementTypeName)), " - string += "asGeneric = \\(String(describing: self.asGeneric)), " - string += "asSource = \\(String(describing: self.asSource))" + string.append("name = \\(String(describing: self.name)), ") + string.append("elementTypeName = \\(String(describing: self.elementTypeName)), ") + string.append("asGeneric = \\(String(describing: self.asGeneric)), ") + string.append("asSource = \\(String(describing: self.asSource))") return string } @@ -416,6 +253,8 @@ public final class ArrayType: NSObject, SourceryModel, Diffable { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) @@ -435,13 +274,13 @@ public final class ArrayType: NSObject, SourceryModel, Diffable { /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { + guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name - guard let elementTypeName: TypeName = aDecoder.decode(forKey: "elementTypeName") else { + guard let elementTypeName: TypeName = aDecoder.decode(forKey: "elementTypeName") else { withVaList(["elementTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } @@ -460,141 +299,44 @@ public final class ArrayType: NSObject, SourceryModel, Diffable { } """), - .init(name: "NSException_Linux.swift", content: + .init(name: "Attribute.swift", content: """ import Foundation -public class NSException { - static func raise(_ name: String, format: String, arguments: CVaListPointer) { - fatalError ("\\(name) exception: \\(NSString(format: format, arguments: arguments))") - } - - static func raise(_ name: String) { - fatalError("\\(name) exception") - } -} - -public extension NSExceptionName { - static var parseErrorException = "parseErrorException" -} - -"""), - .init(name: "AssociatedType.swift", content: -""" -import Foundation +/// Describes Swift attribute +#if canImport(ObjectiveC) +@objcMembers +#endif +public class Attribute: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJSExport, Diffable { -/// Describes Swift AssociatedType -public final class AssociatedType: NSObject, SourceryModel { - /// Associated type name + /// Attribute name public let name: String - /// Associated type type constraint name, if specified - public let typeName: TypeName? + /// Attribute arguments + public let arguments: [String: NSObject] - // sourcery: skipEquality, skipDescription - /// Associated type constrained type, if known, i.e. if the type is declared in the scanned sources. - public var type: Type? + // sourcery: skipJSExport + let _description: String + // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: - public init(name: String, typeName: TypeName? = nil, type: Type? = nil) { - self.name = name - self.typeName = typeName - self.type = type - } + public var __parserData: Any? /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "name = \\(String(describing: self.name)), " - string += "typeName = \\(String(describing: self.typeName))" - return string + public init(name: String, arguments: [String: NSObject] = [:], description: String? = nil) { + self.name = name + self.arguments = arguments + self._description = description ?? "@\\(name)" } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? AssociatedType else { - results.append("Incorrect type ") - return results - } - results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) - return results + /// TODO: unify `asSource` / `description`? + public var asSource: String { + description } - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.name) - hasher.combine(self.typeName) - return hasher.finalize() - } - - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? AssociatedType else { return false } - if self.name != rhs.name { return false } - if self.typeName != rhs.typeName { return false } - return true - } - -// sourcery:inline:AssociatedType.AutoCoding - - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { - withVaList(["name"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.name = name - self.typeName = aDecoder.decode(forKey: "typeName") - self.type = aDecoder.decode(forKey: "type") - } - - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.typeName, forKey: "typeName") - aCoder.encode(self.type, forKey: "type") - } -// sourcery:end -} - -"""), - .init(name: "Attribute.swift", content: -""" -import Foundation - -/// Describes Swift attribute -public class Attribute: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJSExport, Diffable { - - /// Attribute name - public let name: String - - /// Attribute arguments - public let arguments: [String: NSObject] - - // sourcery: skipJSExport - let _description: String - - // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport - /// :nodoc: - public var __parserData: Any? - - /// :nodoc: - public init(name: String, arguments: [String: NSObject] = [:], description: String? = nil) { - self.name = name - self.arguments = arguments - self._description = description ?? "@\\(name)" - } - - /// TODO: unify `asSource` / `description`? - public var asSource: String { - description - } - - /// Attribute description that can be used in a template. - public override var description: String { - return _description + /// Attribute description that can be used in a template. + public override var description: String { + return _description } /// :nodoc: @@ -623,6 +365,7 @@ public class Attribute: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJ case final case open case lazy + case `package` = "package" case `public` = "public" case `internal` = "internal" case `private` = "private" @@ -726,6 +469,8 @@ public class Attribute: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJ return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) @@ -747,19 +492,19 @@ public class Attribute: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJ /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { + guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name - guard let arguments: [String: NSObject] = aDecoder.decode(forKey: "arguments") else { + guard let arguments: [String: NSObject] = aDecoder.decode(forKey: "arguments") else { withVaList(["arguments"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.arguments = arguments - guard let _description: String = aDecoder.decode(forKey: "_description") else { + guard let _description: String = aDecoder.decode(forKey: "_description") else { withVaList(["_description"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } @@ -777,18 +522,6 @@ public class Attribute: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJ } -"""), - .init(name: "AutoHashable.generated.swift", content: -""" -// Generated using Sourcery 1.3.1 — https://github.com/krzysztofzablocki/Sourcery -// DO NOT EDIT -// swiftlint:disable all - - -// MARK: - AutoHashable for classes, protocols, structs - -// MARK: - AutoHashable for Enums - """), .init(name: "BytesRange.swift", content: """ @@ -800,6 +533,9 @@ public class Attribute: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJ import Foundation /// :nodoc: +#if canImport(ObjectiveC) +@objcMembers +#endif public final class BytesRange: NSObject, SourceryModel, Diffable { public let offset: Int64 @@ -815,6 +551,7 @@ public final class BytesRange: NSObject, SourceryModel, Diffable { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string += "offset = \\(String(describing: self.offset)), " @@ -833,6 +570,8 @@ public final class BytesRange: NSObject, SourceryModel, Diffable { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.offset) @@ -870,13 +609,16 @@ public final class BytesRange: NSObject, SourceryModel, Diffable { import Foundation // sourcery: skipDescription /// Descibes Swift class +#if canImport(ObjectiveC) +@objc(SwiftClass) @objcMembers +#endif public final class Class: Type { /// Returns "class" public override var kind: String { return "class" } - /// Whether type is final + /// Whether type is final public var isFinal: Bool { - return modifiers.contains { $0.name == "final" } + modifiers.contains { $0.name == "final" } } /// :nodoc: @@ -919,11 +661,12 @@ public final class Class: Type { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = super.description - string += ", " - string += "kind = \\(String(describing: self.kind)), " - string += "isFinal = \\(String(describing: self.isFinal))" + string.append(", ") + string.append("kind = \\(String(describing: self.kind)), ") + string.append("isFinal = \\(String(describing: self.isFinal))") return string } @@ -937,6 +680,8 @@ public final class Class: Type { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(super.hash) @@ -965,388 +710,117 @@ public final class Class: Type { } """), - .init(name: "Closure.swift", content: + .init(name: "Composer.swift", content: """ +// +// Created by Krzysztof Zablocki on 31/12/2016. +// Copyright (c) 2016 Pixle. All rights reserved. +// + import Foundation -/// Describes closure type -public final class ClosureType: NSObject, SourceryModel, Diffable { +private func currentTimestamp() -> TimeInterval { + return Date().timeIntervalSince1970 +} - /// Type name used in declaration with stripped whitespaces and new lines - public let name: String +/// Responsible for composing results of `FileParser`. +public enum Composer { - /// List of closure parameters - public let parameters: [ClosureParameter] + /// Performs final processing of discovered types: + /// - extends types with their corresponding extensions; + /// - replaces typealiases with actual types + /// - finds actual types for variables and enums raw values + /// - filters out any private types and extensions + /// + /// - Parameter parserResult: Result of parsing source code. + /// - Returns: Final types and extensions of unknown types. + public static func uniqueTypesAndFunctions(_ parserResult: FileParserResult) -> (types: [Type], functions: [SourceryMethod], typealiases: [Typealias]) { + let composed = ParserResultsComposed(parserResult: parserResult) - /// Return value type name - public let returnTypeName: TypeName + let resolveType = { (typeName: TypeName, containingType: Type?) -> Type? in + return composed.resolveType(typeName: typeName, containingType: containingType) + } - /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` - public var actualReturnTypeName: TypeName { - return returnTypeName.actualTypeName ?? returnTypeName - } + let methodResolveType = { (typeName: TypeName, containingType: Type?, method: Method) -> Type? in + return composed.resolveType(typeName: typeName, containingType: containingType, method: method) + } - // sourcery: skipEquality, skipDescription - /// Actual return value type, if known - public var returnType: Type? + composed.types.parallelPerform { type in + type.variables.forEach { + resolveVariableTypes($0, of: type, resolve: resolveType) + } + type.methods.forEach { + resolveMethodTypes($0, of: type, resolve: methodResolveType) + } + type.subscripts.forEach { + resolveSubscriptTypes($0, of: type, resolve: resolveType) + } - // sourcery: skipEquality, skipDescription - /// Whether return value type is optional - public var isOptionalReturnType: Bool { - return returnTypeName.isOptional - } + if let enumeration = type as? Enum { + resolveEnumTypes(enumeration, types: composed.typeMap, resolve: resolveType) + } - // sourcery: skipEquality, skipDescription - /// Whether return value type is implicitly unwrapped optional - public var isImplicitlyUnwrappedOptionalReturnType: Bool { - return returnTypeName.isImplicitlyUnwrappedOptional - } + if let composition = type as? ProtocolComposition { + resolveProtocolCompositionTypes(composition, resolve: resolveType) + } - // sourcery: skipEquality, skipDescription - /// Return value type name without attributes and optional type information - public var unwrappedReturnTypeName: String { - return returnTypeName.unwrappedTypeName - } + if let sourceryProtocol = type as? SourceryProtocol { + resolveProtocolTypes(sourceryProtocol, resolve: resolveType) + } + } - /// Whether method is async method - public let isAsync: Bool + composed.functions.parallelPerform { function in + resolveMethodTypes(function, of: nil, resolve: methodResolveType) + } - /// async keyword - public let asyncKeyword: String? + updateTypeRelationships(types: composed.types) - /// Whether closure throws - public let `throws`: Bool + return ( + types: composed.types.sorted { $0.globalName < $1.globalName }, + functions: composed.functions.sorted { $0.name < $1.name }, + typealiases: composed.unresolvedTypealiases.values.sorted(by: { $0.name < $1.name }) + ) + } - /// throws or rethrows keyword - public let throwsOrRethrowsKeyword: String? + typealias TypeResolver = (TypeName, Type?) -> Type? + typealias MethodArgumentTypeResolver = (TypeName, Type?, Method) -> Type? - /// :nodoc: - public init(name: String, parameters: [ClosureParameter], returnTypeName: TypeName, returnType: Type? = nil, asyncKeyword: String? = nil, throwsOrRethrowsKeyword: String? = nil) { - self.name = name - self.parameters = parameters - self.returnTypeName = returnTypeName - self.returnType = returnType - self.asyncKeyword = asyncKeyword - self.isAsync = asyncKeyword != nil - self.throwsOrRethrowsKeyword = throwsOrRethrowsKeyword - self.`throws` = throwsOrRethrowsKeyword != nil - } + private static func resolveVariableTypes(_ variable: Variable, of type: Type, resolve: TypeResolver) { + variable.type = resolve(variable.typeName, type) - public var asSource: String { - "\\(parameters.asSource)\\(asyncKeyword != nil ? " \\(asyncKeyword!)" : "")\\(throwsOrRethrowsKeyword != nil ? " \\(throwsOrRethrowsKeyword!)" : "") -> \\(returnTypeName.asSource)" + /// The actual `definedInType` is assigned in `uniqueTypes` but we still + /// need to resolve the type to correctly parse typealiases + /// @see https://github.com/krzysztofzablocki/Sourcery/pull/374 + if let definedInTypeName = variable.definedInTypeName { + _ = resolve(definedInTypeName, type) + } } - /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "name = \\(String(describing: self.name)), " - string += "parameters = \\(String(describing: self.parameters)), " - string += "returnTypeName = \\(String(describing: self.returnTypeName)), " - string += "actualReturnTypeName = \\(String(describing: self.actualReturnTypeName)), " - string += "isAsync = \\(String(describing: self.isAsync)), " - string += "asyncKeyword = \\(String(describing: self.asyncKeyword)), " - string += "`throws` = \\(String(describing: self.`throws`)), " - string += "throwsOrRethrowsKeyword = \\(String(describing: self.throwsOrRethrowsKeyword)), " - string += "asSource = \\(String(describing: self.asSource))" - return string - } + private static func resolveSubscriptTypes(_ subscript: Subscript, of type: Type, resolve: TypeResolver) { + `subscript`.parameters.forEach { (parameter) in + parameter.type = resolve(parameter.typeName, type) + } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? ClosureType else { - results.append("Incorrect type ") - return results + `subscript`.returnType = resolve(`subscript`.returnTypeName, type) + if let definedInTypeName = `subscript`.definedInTypeName { + _ = resolve(definedInTypeName, type) } - results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) - results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) - results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) - results.append(contentsOf: DiffableResult(identifier: "asyncKeyword").trackDifference(actual: self.asyncKeyword, expected: castObject.asyncKeyword)) - results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) - results.append(contentsOf: DiffableResult(identifier: "throwsOrRethrowsKeyword").trackDifference(actual: self.throwsOrRethrowsKeyword, expected: castObject.throwsOrRethrowsKeyword)) - return results } - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.name) - hasher.combine(self.parameters) - hasher.combine(self.returnTypeName) - hasher.combine(self.isAsync) - hasher.combine(self.asyncKeyword) - hasher.combine(self.`throws`) - hasher.combine(self.throwsOrRethrowsKeyword) - return hasher.finalize() - } + private static func resolveMethodTypes(_ method: SourceryMethod, of type: Type?, resolve: MethodArgumentTypeResolver) { + method.parameters.forEach { parameter in + parameter.type = resolve(parameter.typeName, type, method) + } - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? ClosureType else { return false } - if self.name != rhs.name { return false } - if self.parameters != rhs.parameters { return false } - if self.returnTypeName != rhs.returnTypeName { return false } - if self.isAsync != rhs.isAsync { return false } - if self.asyncKeyword != rhs.asyncKeyword { return false } - if self.`throws` != rhs.`throws` { return false } - if self.throwsOrRethrowsKeyword != rhs.throwsOrRethrowsKeyword { return false } - return true - } + /// The actual `definedInType` is assigned in `uniqueTypes` but we still + /// need to resolve the type to correctly parse typealiases + /// @see https://github.com/krzysztofzablocki/Sourcery/pull/374 + var definedInType: Type? + if let definedInTypeName = method.definedInTypeName { + definedInType = resolve(definedInTypeName, type, method) + } -// sourcery:inline:ClosureType.AutoCoding - - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { - withVaList(["name"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.name = name - guard let parameters: [ClosureParameter] = aDecoder.decode(forKey: "parameters") else { - withVaList(["parameters"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.parameters = parameters - guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { - withVaList(["returnTypeName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.returnTypeName = returnTypeName - self.returnType = aDecoder.decode(forKey: "returnType") - self.isAsync = aDecoder.decode(forKey: "isAsync") - self.asyncKeyword = aDecoder.decode(forKey: "asyncKeyword") - self.`throws` = aDecoder.decode(forKey: "`throws`") - self.throwsOrRethrowsKeyword = aDecoder.decode(forKey: "throwsOrRethrowsKeyword") - } - - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.parameters, forKey: "parameters") - aCoder.encode(self.returnTypeName, forKey: "returnTypeName") - aCoder.encode(self.returnType, forKey: "returnType") - aCoder.encode(self.isAsync, forKey: "isAsync") - aCoder.encode(self.asyncKeyword, forKey: "asyncKeyword") - aCoder.encode(self.`throws`, forKey: "`throws`") - aCoder.encode(self.throwsOrRethrowsKeyword, forKey: "throwsOrRethrowsKeyword") - } -// sourcery:end - -} - -"""), - .init(name: "Coding.generated.swift", content: -""" -// Generated using Sourcery 2.0.3 — https://github.com/krzysztofzablocki/Sourcery -// DO NOT EDIT -// swiftlint:disable vertical_whitespace trailing_newline - -import Foundation - - -extension NSCoder { - - @nonobjc func decode(forKey: String) -> String? { - return self.maybeDecode(forKey: forKey) as String? - } - - @nonobjc func decode(forKey: String) -> TypeName? { - return self.maybeDecode(forKey: forKey) as TypeName? - } - - @nonobjc func decode(forKey: String) -> AccessLevel? { - return self.maybeDecode(forKey: forKey) as AccessLevel? - } - - @nonobjc func decode(forKey: String) -> Bool { - return self.decodeBool(forKey: forKey) - } - - @nonobjc func decode(forKey: String) -> Int { - return self.decodeInteger(forKey: forKey) - } - - func decode(forKey: String) -> E? { - return maybeDecode(forKey: forKey) as E? - } - - fileprivate func maybeDecode(forKey: String) -> E? { - guard let object = self.decodeObject(forKey: forKey) else { - return nil - } - - return object as? E - } - -} - -extension ArrayType: NSCoding {} - -extension AssociatedType: NSCoding {} - -extension AssociatedValue: NSCoding {} - -extension Attribute: NSCoding {} - -extension BytesRange: NSCoding {} - - -extension ClosureParameter: NSCoding {} - -extension ClosureType: NSCoding {} - -extension DictionaryType: NSCoding {} - - -extension EnumCase: NSCoding {} - -extension FileParserResult: NSCoding {} - -extension GenericRequirement: NSCoding {} - -extension GenericType: NSCoding {} - -extension GenericTypeParameter: NSCoding {} - -extension GenericParameter: NSCoding {} - -extension Import: NSCoding {} - -extension Method: NSCoding {} - -extension MethodParameter: NSCoding {} - -extension Modifier: NSCoding {} - - - - -extension Subscript: NSCoding {} - -extension TupleElement: NSCoding {} - -extension TupleType: NSCoding {} - -extension Type: NSCoding {} - -extension TypeName: NSCoding {} - -extension Typealias: NSCoding {} - -extension Types: NSCoding {} - -extension Variable: NSCoding {} - - -"""), - .init(name: "Composer.swift", content: -""" -// -// Created by Krzysztof Zablocki on 31/12/2016. -// Copyright (c) 2016 Pixle. All rights reserved. -// - -import Foundation - -private func currentTimestamp() -> TimeInterval { - return Date().timeIntervalSince1970 -} - -/// Responsible for composing results of `FileParser`. -public enum Composer { - - /// Performs final processing of discovered types: - /// - extends types with their corresponding extensions; - /// - replaces typealiases with actual types - /// - finds actual types for variables and enums raw values - /// - filters out any private types and extensions - /// - /// - Parameter parserResult: Result of parsing source code. - /// - Returns: Final types and extensions of unknown types. - public static func uniqueTypesAndFunctions(_ parserResult: FileParserResult) -> (types: [Type], functions: [SourceryMethod], typealiases: [Typealias]) { - let composed = ParserResultsComposed(parserResult: parserResult) - - let resolveType = { (typeName: TypeName, containingType: Type?) -> Type? in - return composed.resolveType(typeName: typeName, containingType: containingType) - } - - composed.types.parallelPerform { type in - type.variables.forEach { - resolveVariableTypes($0, of: type, resolve: resolveType) - } - type.methods.forEach { - resolveMethodTypes($0, of: type, resolve: resolveType) - } - type.subscripts.forEach { - resolveSubscriptTypes($0, of: type, resolve: resolveType) - } - - if let enumeration = type as? Enum { - resolveEnumTypes(enumeration, types: composed.typeMap, resolve: resolveType) - } - - if let composition = type as? ProtocolComposition { - resolveProtocolCompositionTypes(composition, resolve: resolveType) - } - - if let sourceryProtocol = type as? SourceryProtocol { - resolveProtocolTypes(sourceryProtocol, resolve: resolveType) - } - } - - composed.functions.parallelPerform { function in - resolveMethodTypes(function, of: nil, resolve: resolveType) - } - - updateTypeRelationships(types: composed.types) - - return ( - types: composed.types.sorted { $0.globalName < $1.globalName }, - functions: composed.functions.sorted { $0.name < $1.name }, - typealiases: composed.unresolvedTypealiases.values.sorted(by: { $0.name < $1.name }) - ) - } - - typealias TypeResolver = (TypeName, Type?) -> Type? - - private static func resolveVariableTypes(_ variable: Variable, of type: Type, resolve: TypeResolver) { - variable.type = resolve(variable.typeName, type) - - /// The actual `definedInType` is assigned in `uniqueTypes` but we still - /// need to resolve the type to correctly parse typealiases - /// @see https://github.com/krzysztofzablocki/Sourcery/pull/374 - if let definedInTypeName = variable.definedInTypeName { - _ = resolve(definedInTypeName, type) - } - } - - private static func resolveSubscriptTypes(_ subscript: Subscript, of type: Type, resolve: TypeResolver) { - `subscript`.parameters.forEach { (parameter) in - parameter.type = resolve(parameter.typeName, type) - } - - `subscript`.returnType = resolve(`subscript`.returnTypeName, type) - if let definedInTypeName = `subscript`.definedInTypeName { - _ = resolve(definedInTypeName, type) - } - } - - private static func resolveMethodTypes(_ method: SourceryMethod, of type: Type?, resolve: TypeResolver) { - method.parameters.forEach { parameter in - parameter.type = resolve(parameter.typeName, type) - } - - /// The actual `definedInType` is assigned in `uniqueTypes` but we still - /// need to resolve the type to correctly parse typealiases - /// @see https://github.com/krzysztofzablocki/Sourcery/pull/374 - var definedInType: Type? - if let definedInTypeName = method.definedInTypeName { - definedInType = resolve(definedInTypeName, type) - } - - guard !method.returnTypeName.isVoid else { return } + guard !method.returnTypeName.isVoid else { return } if method.isInitializer || method.isFailableInitializer { method.returnType = definedInType @@ -1369,7 +843,7 @@ public enum Composer { } } } else { - method.returnType = resolve(method.returnTypeName, type) + method.returnType = resolve(method.returnTypeName, type, method) } } @@ -1442,6 +916,13 @@ public enum Composer { } private static func findBaseType(for type: Type, name: String, typesByName: [String: Type]) -> Type? { + // special case to check if the type is based on one of the recognized types + // and the superclass has a generic constraint in `name` part of the `TypeName` + var name = name + if name.contains("<") && name.contains(">") { + let parts = name.split(separator: "<") + name = String(parts.first!) + } if let baseType = typesByName[name] { return baseType } @@ -1517,6 +998,9 @@ public protocol Definition: AnyObject { import Foundation /// Describes dictionary type +#if canImport(ObjectiveC) +@objcMembers +#endif public final class DictionaryType: NSObject, SourceryModel, Diffable { /// Type name used in declaration public var name: String @@ -1557,13 +1041,14 @@ public final class DictionaryType: NSObject, SourceryModel, Diffable { } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " - string += "name = \\(String(describing: self.name)), " - string += "valueTypeName = \\(String(describing: self.valueTypeName)), " - string += "keyTypeName = \\(String(describing: self.keyTypeName)), " - string += "asGeneric = \\(String(describing: self.asGeneric)), " - string += "asSource = \\(String(describing: self.asSource))" + string.append("name = \\(String(describing: self.name)), ") + string.append("valueTypeName = \\(String(describing: self.valueTypeName)), ") + string.append("keyTypeName = \\(String(describing: self.keyTypeName)), ") + string.append("asGeneric = \\(String(describing: self.asGeneric)), ") + string.append("asSource = \\(String(describing: self.asSource))") return string } @@ -1579,6 +1064,8 @@ public final class DictionaryType: NSObject, SourceryModel, Diffable { return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) @@ -1600,20 +1087,20 @@ public final class DictionaryType: NSObject, SourceryModel, Diffable { /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { + guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name - guard let valueTypeName: TypeName = aDecoder.decode(forKey: "valueTypeName") else { + guard let valueTypeName: TypeName = aDecoder.decode(forKey: "valueTypeName") else { withVaList(["valueTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.valueTypeName = valueTypeName self.valueType = aDecoder.decode(forKey: "valueType") - guard let keyTypeName: TypeName = aDecoder.decode(forKey: "keyTypeName") else { + guard let keyTypeName: TypeName = aDecoder.decode(forKey: "keyTypeName") else { withVaList(["keyTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } @@ -1674,6 +1161,9 @@ extension NSRange: Diffable { } } +#if canImport(ObjectiveC) +@objcMembers +#endif public class DiffableResult: NSObject, AutoEquatable { // sourcery: skipEquality private var results: [String] @@ -1696,11 +1186,28 @@ public class DiffableResult: NSObject, AutoEquatable { var isEmpty: Bool { return results.isEmpty } - public override var description: String { - guard !results.isEmpty else { return "" } - return "\\(identifier.flatMap { "\\($0) " } ?? "")" + results.joined(separator: "\\n") + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.identifier) + return hasher.finalize() } -} + + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? DiffableResult else { return false } + if self.identifier != rhs.identifier { return false } + return true + } + + public override var description: String { + guard !results.isEmpty else { return "" } + var description = "\\(identifier.flatMap { "\\($0) " } ?? "")" + description.append(results.joined(separator: "\\n")) + return description + } +} public extension DiffableResult { @@ -1719,7 +1226,9 @@ public extension DiffableResult { /// :nodoc: @discardableResult func trackDifference(actual: T?, expected: T?) -> DiffableResult { if actual != expected { - let result = DiffableResult(results: [""]) + let expected = expected.map({ "\\($0)" }) ?? "nil" + let actual = actual.map({ "\\($0)" }) ?? "nil" + let result = DiffableResult(results: [""]) append(contentsOf: result) } return self @@ -1857,5663 +1366,7538 @@ public protocol Documented { } """), - .init(name: "EnumCase.swift", content: + .init(name: "Extensions.swift", content: """ import Foundation -/// Defines enum case -public final class EnumCase: NSObject, SourceryModel, AutoDescription, Annotated, Documented, Diffable { - - /// Enum case name - public let name: String +public extension StringProtocol { + /// Trimms leading and trailing whitespaces and newlines + var trimmed: String { + self.trimmingCharacters(in: .whitespacesAndNewlines) + } +} - /// Enum case raw value, if any - public let rawValue: String? +public extension String { - /// Enum case associated values - public let associatedValues: [AssociatedValue] + /// Returns nil if string is empty + var nilIfEmpty: String? { + if isEmpty { + return nil + } - /// Enum case annotations - public var annotations: Annotations = [:] + return self + } - public var documentation: Documentation = [] + /// Returns nil if string is empty or contains `_` character + var nilIfNotValidParameterName: String? { + if isEmpty { + return nil + } - /// Whether enum case is indirect - public let indirect: Bool + if self == "_" { + return nil + } - /// Whether enum case has associated value - public var hasAssociatedValue: Bool { - return !associatedValues.isEmpty + return self } - // Underlying parser data, never to be used by anything else - // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: - public var __parserData: Any? + /// - Parameter substring: Instance of a substring + /// - Returns: Returns number of times a substring appears in self + func countInstances(of substring: String) -> Int { + guard !substring.isEmpty else { return 0 } + var count = 0 + var searchRange: Range? + while let foundRange = range(of: substring, options: [], range: searchRange) { + count += 1 + searchRange = Range(uncheckedBounds: (lower: foundRange.upperBound, upper: endIndex)) + } + return count + } /// :nodoc: - public init(name: String, rawValue: String? = nil, associatedValues: [AssociatedValue] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], indirect: Bool = false) { - self.name = name - self.rawValue = rawValue - self.associatedValues = associatedValues - self.annotations = annotations - self.documentation = documentation - self.indirect = indirect + /// Removes leading and trailing whitespace from str. Returns false if str was not altered. + @discardableResult + mutating func strip() -> Bool { + let strippedString = stripped() + guard strippedString != self else { return false } + self = strippedString + return true } /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "name = \\(String(describing: self.name)), " - string += "rawValue = \\(String(describing: self.rawValue)), " - string += "associatedValues = \\(String(describing: self.associatedValues)), " - string += "annotations = \\(String(describing: self.annotations)), " - string += "documentation = \\(String(describing: self.documentation)), " - string += "indirect = \\(String(describing: self.indirect)), " - string += "hasAssociatedValue = \\(String(describing: self.hasAssociatedValue))" - return string + /// Returns a copy of str with leading and trailing whitespace removed. + func stripped() -> String { + return String(self.trimmingCharacters(in: .whitespaces)) } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? EnumCase else { - results.append("Incorrect type ") - return results - } - results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "rawValue").trackDifference(actual: self.rawValue, expected: castObject.rawValue)) - results.append(contentsOf: DiffableResult(identifier: "associatedValues").trackDifference(actual: self.associatedValues, expected: castObject.associatedValues)) - results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) - results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) - results.append(contentsOf: DiffableResult(identifier: "indirect").trackDifference(actual: self.indirect, expected: castObject.indirect)) - return results + /// :nodoc: + @discardableResult + mutating func trimPrefix(_ prefix: String) -> Bool { + guard hasPrefix(prefix) else { return false } + self = String(self.suffix(self.count - prefix.count)) + return true } - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.name) - hasher.combine(self.rawValue) - hasher.combine(self.associatedValues) - hasher.combine(self.annotations) - hasher.combine(self.documentation) - hasher.combine(self.indirect) - return hasher.finalize() + /// :nodoc: + func trimmingPrefix(_ prefix: String) -> String { + guard hasPrefix(prefix) else { return self } + return String(self.suffix(self.count - prefix.count)) } /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? EnumCase else { return false } - if self.name != rhs.name { return false } - if self.rawValue != rhs.rawValue { return false } - if self.associatedValues != rhs.associatedValues { return false } - if self.annotations != rhs.annotations { return false } - if self.documentation != rhs.documentation { return false } - if self.indirect != rhs.indirect { return false } + @discardableResult + mutating func trimSuffix(_ suffix: String) -> Bool { + guard hasSuffix(suffix) else { return false } + self = String(self.prefix(self.count - suffix.count)) return true } -// sourcery:inline:EnumCase.AutoCoding - - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { - withVaList(["name"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.name = name - self.rawValue = aDecoder.decode(forKey: "rawValue") - guard let associatedValues: [AssociatedValue] = aDecoder.decode(forKey: "associatedValues") else { - withVaList(["associatedValues"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.associatedValues = associatedValues - guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { - withVaList(["annotations"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.annotations = annotations - guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { - withVaList(["documentation"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.documentation = documentation - self.indirect = aDecoder.decode(forKey: "indirect") - } - - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.rawValue, forKey: "rawValue") - aCoder.encode(self.associatedValues, forKey: "associatedValues") - aCoder.encode(self.annotations, forKey: "annotations") - aCoder.encode(self.documentation, forKey: "documentation") - aCoder.encode(self.indirect, forKey: "indirect") - } -// sourcery:end -} - -"""), - .init(name: "AssociatedValue.swift", content: -""" -// -// Created by Krzysztof Zablocki on 13/09/2016. -// Copyright (c) 2016 Pixle. All rights reserved. -// - -import Foundation - -/// Defines enum case associated value -public final class AssociatedValue: NSObject, SourceryModel, AutoDescription, Typed, Annotated, Diffable { - - /// Associated value local name. - /// This is a name to be used to construct enum case value - public let localName: String? - - /// Associated value external name. - /// This is a name to be used to access value in value-bindig - public let externalName: String? - - /// Associated value type name - public let typeName: TypeName - - // sourcery: skipEquality, skipDescription - /// Associated value type, if known - public var type: Type? - - /// Associated value default value - public let defaultValue: String? + /// :nodoc: + func trimmingSuffix(_ suffix: String) -> String { + guard hasSuffix(suffix) else { return self } + return String(self.prefix(self.count - suffix.count)) + } - /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 - public var annotations: Annotations = [:] + /// :nodoc: + func dropFirstAndLast(_ n: Int = 1) -> String { + return drop(first: n, last: n) + } /// :nodoc: - public init(localName: String?, externalName: String?, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:]) { - self.localName = localName - self.externalName = externalName - self.typeName = typeName - self.type = type - self.defaultValue = defaultValue - self.annotations = annotations + func drop(first: Int, last: Int) -> String { + return String(self.dropFirst(first).dropLast(last)) } - convenience init(name: String? = nil, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:]) { - self.init(localName: name, externalName: name, typeName: typeName, type: type, defaultValue: defaultValue, annotations: annotations) + /// :nodoc: + /// Wraps brackets if needed to make a valid type name + func bracketsBalancing() -> String { + if hasPrefix("(") && hasSuffix(")") { + let unwrapped = dropFirstAndLast() + return unwrapped.commaSeparated().count == 1 ? unwrapped.bracketsBalancing() : self + } else { + let wrapped = "(\\(self))" + return wrapped.isValidTupleName() || !isBracketsBalanced() ? wrapped : self + } } /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "localName = \\(String(describing: self.localName)), " - string += "externalName = \\(String(describing: self.externalName)), " - string += "typeName = \\(String(describing: self.typeName)), " - string += "defaultValue = \\(String(describing: self.defaultValue)), " - string += "annotations = \\(String(describing: self.annotations))" - return string + /// Returns true if given string can represent a valid tuple type name + func isValidTupleName() -> Bool { + guard hasPrefix("(") && hasSuffix(")") else { return false } + let trimmedBracketsName = dropFirstAndLast() + return trimmedBracketsName.isBracketsBalanced() && trimmedBracketsName.commaSeparated().count > 1 } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? AssociatedValue else { - results.append("Incorrect type ") - return results + /// :nodoc: + func isValidArrayName() -> Bool { + if hasPrefix("Array<") { return true } + if hasPrefix("[") && hasSuffix("]") { + return dropFirstAndLast().colonSeparated().count == 1 } - results.append(contentsOf: DiffableResult(identifier: "localName").trackDifference(actual: self.localName, expected: castObject.localName)) - results.append(contentsOf: DiffableResult(identifier: "externalName").trackDifference(actual: self.externalName, expected: castObject.externalName)) - results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) - results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) - results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) - return results + return false } - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.localName) - hasher.combine(self.externalName) - hasher.combine(self.typeName) - hasher.combine(self.defaultValue) - hasher.combine(self.annotations) - return hasher.finalize() + /// :nodoc: + func isValidDictionaryName() -> Bool { + if hasPrefix("Dictionary<") { return true } + if hasPrefix("[") && contains(":") && hasSuffix("]") { + return dropFirstAndLast().colonSeparated().count == 2 + } + return false } /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? AssociatedValue else { return false } - if self.localName != rhs.localName { return false } - if self.externalName != rhs.externalName { return false } - if self.typeName != rhs.typeName { return false } - if self.defaultValue != rhs.defaultValue { return false } - if self.annotations != rhs.annotations { return false } - return true + func isValidClosureName() -> Bool { + return components(separatedBy: "->", excludingDelimiterBetween: (["(", "<"], [")", ">"])).count > 1 } -// sourcery:inline:AssociatedValue.AutoCoding - - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - self.localName = aDecoder.decode(forKey: "localName") - self.externalName = aDecoder.decode(forKey: "externalName") - guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { - withVaList(["typeName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.typeName = typeName - self.type = aDecoder.decode(forKey: "type") - self.defaultValue = aDecoder.decode(forKey: "defaultValue") - guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { - withVaList(["annotations"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.annotations = annotations - } - - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.localName, forKey: "localName") - aCoder.encode(self.externalName, forKey: "externalName") - aCoder.encode(self.typeName, forKey: "typeName") - aCoder.encode(self.type, forKey: "type") - aCoder.encode(self.defaultValue, forKey: "defaultValue") - aCoder.encode(self.annotations, forKey: "annotations") + /// :nodoc: + /// Returns true if all opening brackets are balanced with closed brackets. + func isBracketsBalanced() -> Bool { + var bracketsCount: Int = 0 + for char in self { + if char == "(" { bracketsCount += 1 } else if char == ")" { bracketsCount -= 1 } + if bracketsCount < 0 { return false } } -// sourcery:end - -} + return bracketsCount == 0 + } -"""), - .init(name: "Enum.swift", content: -""" -import Foundation + /// :nodoc: + /// Returns components separated with a comma respecting nested types + func commaSeparated() -> [String] { + return components(separatedBy: ",", excludingDelimiterBetween: ("<[({", "})]>")) + } -/// Defines Swift enum -public final class Enum: Type { + /// :nodoc: + /// Returns components separated with colon respecting nested types + func colonSeparated() -> [String] { + return components(separatedBy: ":", excludingDelimiterBetween: ("<[({", "})]>")) + } - // sourcery: skipDescription - /// Returns "enum" - public override var kind: String { return "enum" } + /// :nodoc: + /// Returns components separated with semicolon respecting nested contexts + func semicolonSeparated() -> [String] { + return components(separatedBy: ";", excludingDelimiterBetween: ("{", "}")) + } - /// Enum cases - public var cases: [EnumCase] + /// :nodoc: + func components(separatedBy delimiter: String, excludingDelimiterBetween between: (open: String, close: String)) -> [String] { + return self.components(separatedBy: delimiter, excludingDelimiterBetween: (between.open.map { String($0) }, between.close.map { String($0) })) + } - /** - Enum raw value type name, if any. This type is removed from enum's `based` and `inherited` types collections. + /// :nodoc: + func components(separatedBy delimiter: String, excludingDelimiterBetween between: (open: [String], close: [String])) -> [String] { + var boundingCharactersCount: Int = 0 + var quotesCount: Int = 0 + var item = "" + var items = [String]() - - important: Unless raw type is specified explicitly via type alias RawValue it will be set to the first type in the inheritance chain. - So if your enum does not have raw value but implements protocols you'll have to specify conformance to these protocols via extension to get enum with nil raw value type and all based and inherited types. - */ - public var rawTypeName: TypeName? { - didSet { - if let rawTypeName = rawTypeName { - hasRawType = true - if let index = inheritedTypes.firstIndex(of: rawTypeName.name) { - inheritedTypes.remove(at: index) + var i = self.startIndex + while i < self.endIndex { + var offset = 1 + defer { + i = self.index(i, offsetBy: offset) + } + var currentlyScannedEnd: Index = self.endIndex + if let endIndex = self.index(i, offsetBy: delimiter.count, limitedBy: self.endIndex) { + currentlyScannedEnd = endIndex + } + let currentlyScanned: String = String(self[i..` + if !((self[i] == ">") as Bool && (item.last == "-") as Bool) { + boundingCharactersCount = max(0, boundingCharactersCount - 1) } + offset = closeString.count + } + if (self[i] == "\\"") as Bool { + quotesCount += 1 + } + + let currentIsDelimiter = (currentlyScanned == delimiter) as Bool + let boundingCountIsZero = (boundingCharactersCount == 0) as Bool + let hasEvenQuotes = (quotesCount % 2 == 0) as Bool + if currentIsDelimiter && boundingCountIsZero && hasEvenQuotes { + items.append(item) + item = "" + i = self.index(i, offsetBy: delimiter.count - 1) } else { - hasRawType = false + let endIndex: Index = self.index(i, offsetBy: offset) + item += self[i.. DiffableResult { + public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() - guard let castObject = object as? Enum else { - results.append("Incorrect type ") + guard let castObject = object as? FileParserResult else { + results.append("Incorrect type ") return results } - results.append(contentsOf: DiffableResult(identifier: "cases").trackDifference(actual: self.cases, expected: castObject.cases)) - results.append(contentsOf: DiffableResult(identifier: "rawTypeName").trackDifference(actual: self.rawTypeName, expected: castObject.rawTypeName)) - results.append(contentsOf: super.diffAgainst(castObject)) + results.append(contentsOf: DiffableResult(identifier: "path").trackDifference(actual: self.path, expected: castObject.path)) + results.append(contentsOf: DiffableResult(identifier: "module").trackDifference(actual: self.module, expected: castObject.module)) + results.append(contentsOf: DiffableResult(identifier: "types").trackDifference(actual: self.types, expected: castObject.types)) + results.append(contentsOf: DiffableResult(identifier: "functions").trackDifference(actual: self.functions, expected: castObject.functions)) + results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) + results.append(contentsOf: DiffableResult(identifier: "inlineRanges").trackDifference(actual: self.inlineRanges, expected: castObject.inlineRanges)) + results.append(contentsOf: DiffableResult(identifier: "inlineIndentations").trackDifference(actual: self.inlineIndentations, expected: castObject.inlineIndentations)) + results.append(contentsOf: DiffableResult(identifier: "modifiedDate").trackDifference(actual: self.modifiedDate, expected: castObject.modifiedDate)) + results.append(contentsOf: DiffableResult(identifier: "sourceryVersion").trackDifference(actual: self.sourceryVersion, expected: castObject.sourceryVersion)) return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() - hasher.combine(self.cases) - hasher.combine(self.rawTypeName) - hasher.combine(super.hash) - return hasher.finalize() - } - - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? Enum else { return false } - if self.cases != rhs.cases { return false } - if self.rawTypeName != rhs.rawTypeName { return false } - return super.isEqual(rhs) + hasher.combine(self.path) + hasher.combine(self.module) + hasher.combine(self.types) + hasher.combine(self.functions) + hasher.combine(self.typealiases) + hasher.combine(self.inlineRanges) + hasher.combine(self.inlineIndentations) + hasher.combine(self.modifiedDate) + hasher.combine(self.sourceryVersion) + return hasher.finalize() } -// sourcery:inline:Enum.AutoCoding + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? FileParserResult else { return false } + if self.path != rhs.path { return false } + if self.module != rhs.module { return false } + if self.types != rhs.types { return false } + if self.functions != rhs.functions { return false } + if self.typealiases != rhs.typealiases { return false } + if self.inlineRanges != rhs.inlineRanges { return false } + if self.inlineIndentations != rhs.inlineIndentations { return false } + if self.modifiedDate != rhs.modifiedDate { return false } + if self.sourceryVersion != rhs.sourceryVersion { return false } + return true + } + +// sourcery:inline:FileParserResult.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let cases: [EnumCase] = aDecoder.decode(forKey: "cases") else { - withVaList(["cases"]) { arguments in + self.path = aDecoder.decode(forKey: "path") + self.module = aDecoder.decode(forKey: "module") + guard let types: [Type] = aDecoder.decode(forKey: "types") else { + withVaList(["types"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.cases = cases - self.rawTypeName = aDecoder.decode(forKey: "rawTypeName") - self.hasRawType = aDecoder.decode(forKey: "hasRawType") - self.rawType = aDecoder.decode(forKey: "rawType") - super.init(coder: aDecoder) + }; self.types = types + guard let functions: [SourceryMethod] = aDecoder.decode(forKey: "functions") else { + withVaList(["functions"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.functions = functions + guard let typealiases: [Typealias] = aDecoder.decode(forKey: "typealiases") else { + withVaList(["typealiases"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.typealiases = typealiases + guard let inlineRanges: [String: NSRange] = aDecoder.decode(forKey: "inlineRanges") else { + withVaList(["inlineRanges"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.inlineRanges = inlineRanges + guard let inlineIndentations: [String: String] = aDecoder.decode(forKey: "inlineIndentations") else { + withVaList(["inlineIndentations"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.inlineIndentations = inlineIndentations + guard let modifiedDate: Date = aDecoder.decode(forKey: "modifiedDate") else { + withVaList(["modifiedDate"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.modifiedDate = modifiedDate + guard let sourceryVersion: String = aDecoder.decode(forKey: "sourceryVersion") else { + withVaList(["sourceryVersion"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.sourceryVersion = sourceryVersion } /// :nodoc: - override public func encode(with aCoder: NSCoder) { - super.encode(with: aCoder) - aCoder.encode(self.cases, forKey: "cases") - aCoder.encode(self.rawTypeName, forKey: "rawTypeName") - aCoder.encode(self.hasRawType, forKey: "hasRawType") - aCoder.encode(self.rawType, forKey: "rawType") + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.path, forKey: "path") + aCoder.encode(self.module, forKey: "module") + aCoder.encode(self.types, forKey: "types") + aCoder.encode(self.functions, forKey: "functions") + aCoder.encode(self.typealiases, forKey: "typealiases") + aCoder.encode(self.inlineRanges, forKey: "inlineRanges") + aCoder.encode(self.inlineIndentations, forKey: "inlineIndentations") + aCoder.encode(self.modifiedDate, forKey: "modifiedDate") + aCoder.encode(self.sourceryVersion, forKey: "sourceryVersion") } // sourcery:end } """), - .init(name: "Extensions.swift", content: + .init(name: "Generic.swift", content: """ import Foundation -public extension StringProtocol { - /// Trimms leading and trailing whitespaces and newlines - var trimmed: String { - self.trimmingCharacters(in: .whitespacesAndNewlines) - } -} +/// Descibes Swift generic type +#if canImport(ObjectiveC) +@objcMembers +#endif +public final class GenericType: NSObject, SourceryModelWithoutDescription, Diffable { + /// The name of the base type, i.e. `Array` for `Array` + public var name: String -public extension String { + /// This generic type parameters + public let typeParameters: [GenericTypeParameter] - /// Returns nil if string is empty - var nilIfEmpty: String? { - if isEmpty { - return nil - } + /// :nodoc: + public init(name: String, typeParameters: [GenericTypeParameter] = []) { + self.name = name + self.typeParameters = typeParameters + } - return self + public var asSource: String { + let arguments = typeParameters + .map({ $0.typeName.asSource }) + .joined(separator: ", ") + return "\\(name)<\\(arguments)>" } - /// Returns nil if string is empty or contains `_` character - var nilIfNotValidParameterName: String? { - if isEmpty { - return nil - } + public override var description: String { + asSource + } - if self == "_" { - return nil + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? GenericType else { + results.append("Incorrect type ") + return results } - - return self + results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) + results.append(contentsOf: DiffableResult(identifier: "typeParameters").trackDifference(actual: self.typeParameters, expected: castObject.typeParameters)) + return results } /// :nodoc: - /// - Parameter substring: Instance of a substring - /// - Returns: Returns number of times a substring appears in self - func countInstances(of substring: String) -> Int { - guard !substring.isEmpty else { return 0 } - var count = 0 - var searchRange: Range? - while let foundRange = range(of: substring, options: [], range: searchRange) { - count += 1 - searchRange = Range(uncheckedBounds: (lower: foundRange.upperBound, upper: endIndex)) - } - return count + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.name) + hasher.combine(self.typeParameters) + return hasher.finalize() } /// :nodoc: - /// Removes leading and trailing whitespace from str. Returns false if str was not altered. - @discardableResult - mutating func strip() -> Bool { - let strippedString = stripped() - guard strippedString != self else { return false } - self = strippedString + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? GenericType else { return false } + if self.name != rhs.name { return false } + if self.typeParameters != rhs.typeParameters { return false } return true - } + } - /// :nodoc: - /// Returns a copy of str with leading and trailing whitespace removed. - func stripped() -> String { - return String(self.trimmingCharacters(in: .whitespaces)) - } +// sourcery:inline:GenericType.AutoCoding - /// :nodoc: - @discardableResult - mutating func trimPrefix(_ prefix: String) -> Bool { - guard hasPrefix(prefix) else { return false } - self = String(self.suffix(self.count - prefix.count)) - return true - } + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let name: String = aDecoder.decode(forKey: "name") else { + withVaList(["name"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.name = name + guard let typeParameters: [GenericTypeParameter] = aDecoder.decode(forKey: "typeParameters") else { + withVaList(["typeParameters"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.typeParameters = typeParameters + } - /// :nodoc: - func trimmingPrefix(_ prefix: String) -> String { - guard hasPrefix(prefix) else { return self } - return String(self.suffix(self.count - prefix.count)) - } + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.typeParameters, forKey: "typeParameters") + } - /// :nodoc: - @discardableResult - mutating func trimSuffix(_ suffix: String) -> Bool { - guard hasSuffix(suffix) else { return false } - self = String(self.prefix(self.count - suffix.count)) - return true - } +// sourcery:end +} - /// :nodoc: - func trimmingSuffix(_ suffix: String) -> String { - guard hasSuffix(suffix) else { return self } - return String(self.prefix(self.count - suffix.count)) - } +"""), + .init(name: "Import.swift", content: +""" +import Foundation - /// :nodoc: - func dropFirstAndLast(_ n: Int = 1) -> String { - return drop(first: n, last: n) - } +/// Defines import type +#if canImport(ObjectiveC) +@objcMembers +#endif +public class Import: NSObject, SourceryModelWithoutDescription, Diffable { + /// Import kind, e.g. class, struct in `import class Module.ClassName` + public var kind: String? + + /// Import path + public var path: String /// :nodoc: - func drop(first: Int, last: Int) -> String { - return String(self.dropFirst(first).dropLast(last)) + public init(path: String, kind: String? = nil) { + self.path = path + self.kind = kind } - /// :nodoc: - /// Wraps brackets if needed to make a valid type name - func bracketsBalancing() -> String { - if hasPrefix("(") && hasSuffix(")") { - let unwrapped = dropFirstAndLast() - return unwrapped.commaSeparated().count == 1 ? unwrapped.bracketsBalancing() : self - } else { - let wrapped = "(\\(self))" - return wrapped.isValidTupleName() || !isBracketsBalanced() ? wrapped : self + /// Full import value e.g. `import struct Module.StructName` + public override var description: String { + if let kind = kind { + return "\\(kind) \\(path)" } + + return path } - /// :nodoc: - /// Returns true if given string can represent a valid tuple type name - func isValidTupleName() -> Bool { - guard hasPrefix("(") && hasSuffix(")") else { return false } - let trimmedBracketsName = dropFirstAndLast() - return trimmedBracketsName.isBracketsBalanced() && trimmedBracketsName.commaSeparated().count > 1 + /// Returns module name from a import, e.g. if you had `import struct Module.Submodule.Struct` it will return `Module.Submodule` + public var moduleName: String { + if kind != nil { + if let idx = path.lastIndex(of: ".") { + return String(path[.. Bool { - if hasPrefix("Array<") { return true } - if hasPrefix("[") && hasSuffix("]") { - return dropFirstAndLast().colonSeparated().count == 1 + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? Import else { + results.append("Incorrect type ") + return results } - return false + results.append(contentsOf: DiffableResult(identifier: "kind").trackDifference(actual: self.kind, expected: castObject.kind)) + results.append(contentsOf: DiffableResult(identifier: "path").trackDifference(actual: self.path, expected: castObject.path)) + return results } /// :nodoc: - func isValidDictionaryName() -> Bool { - if hasPrefix("Dictionary<") { return true } - if hasPrefix("[") && contains(":") && hasSuffix("]") { - return dropFirstAndLast().colonSeparated().count == 2 - } - return false + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.kind) + hasher.combine(self.path) + return hasher.finalize() } /// :nodoc: - func isValidClosureName() -> Bool { - return components(separatedBy: "->", excludingDelimiterBetween: (["(", "<"], [")", ">"])).count > 1 + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? Import else { return false } + if self.kind != rhs.kind { return false } + if self.path != rhs.path { return false } + return true } - /// :nodoc: - /// Returns true if all opening brackets are balanced with closed brackets. - func isBracketsBalanced() -> Bool { - var bracketsCount: Int = 0 - for char in self { - if char == "(" { bracketsCount += 1 } else if char == ")" { bracketsCount -= 1 } - if bracketsCount < 0 { return false } +// sourcery:inline:Import.AutoCoding + + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + self.kind = aDecoder.decode(forKey: "kind") + guard let path: String = aDecoder.decode(forKey: "path") else { + withVaList(["path"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.path = path } - return bracketsCount == 0 + + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.kind, forKey: "kind") + aCoder.encode(self.path, forKey: "path") + } + +// sourcery:end +} + +"""), + .init(name: "Log.swift", content: +""" +//import Darwin +import Foundation + +/// :nodoc: +public enum Log { + + public enum Level: Int { + case errors + case warnings + case info + case verbose } - /// :nodoc: - /// Returns components separated with a comma respecting nested types - func commaSeparated() -> [String] { - return components(separatedBy: ",", excludingDelimiterBetween: ("<[({", "})]>")) + public static var level: Level = .warnings + public static var logBenchmarks: Bool = false + public static var logAST: Bool = false + + public static var stackMessages: Bool = false + public private(set) static var messagesStack = [String]() + + public static func error(_ message: Any) { + log(level: .errors, "error: \\(message)") + // to return error when running swift templates which is done in a different process + if ProcessInfo.processInfo.processName != "Sourcery" { + fputs("\\(message)", stderr) + } } - /// :nodoc: - /// Returns components separated with colon respecting nested types - func colonSeparated() -> [String] { - return components(separatedBy: ":", excludingDelimiterBetween: ("<[({", "})]>")) + public static func warning(_ message: Any) { + log(level: .warnings, "warning: \\(message)") } - /// :nodoc: - /// Returns components separated with semicolon respecting nested contexts - func semicolonSeparated() -> [String] { - return components(separatedBy: ";", excludingDelimiterBetween: ("{", "}")) + public static func astWarning(_ message: Any) { + guard logAST else { return } + log(level: .warnings, "ast warning: \\(message)") } - /// :nodoc: - func components(separatedBy delimiter: String, excludingDelimiterBetween between: (open: String, close: String)) -> [String] { - return self.components(separatedBy: delimiter, excludingDelimiterBetween: (between.open.map { String($0) }, between.close.map { String($0) })) + public static func astError(_ message: Any) { + guard logAST else { return } + log(level: .errors, "ast error: \\(message)") } - /// :nodoc: - func components(separatedBy delimiter: String, excludingDelimiterBetween between: (open: [String], close: [String])) -> [String] { - var boundingCharactersCount: Int = 0 - var quotesCount: Int = 0 - var item = "" - var items = [String]() + public static func verbose(_ message: Any) { + log(level: .verbose, message) + } - var i = self.startIndex - while i < self.endIndex { - var offset = 1 - defer { - i = self.index(i, offsetBy: offset) - } - let currentlyScanned = self[i..<(self.index(i, offsetBy: delimiter.count, limitedBy: self.endIndex) ?? self.endIndex)] - if let openString = between.open.first(where: { String(self[i...]).starts(with: $0) }) { - if !(boundingCharactersCount == 0 && String(self[i]) == delimiter) { - boundingCharactersCount += 1 - } - offset = openString.count - } else if let closeString = between.close.first(where: { String(self[i...]).starts(with: $0) }) { - // do not count `->` - if !(self[i] == ">" && item.last == "-") { - boundingCharactersCount = max(0, boundingCharactersCount - 1) - } - offset = closeString.count - } - if self[i] == "\\"" { - quotesCount += 1 - } + public static func info(_ message: Any) { + log(level: .info, message) + } - if currentlyScanned == delimiter && boundingCharactersCount == 0 && quotesCount % 2 == 0 { - items.append(item) - item = "" - i = self.index(i, offsetBy: delimiter.count - 1) - } else { - item += self[i.. DiffableResult { let results = DiffableResult() - guard let castObject = object as? FileParserResult else { - results.append("Incorrect type ") + guard let castObject = object as? Modifier else { + results.append("Incorrect type ") return results } - results.append(contentsOf: DiffableResult(identifier: "path").trackDifference(actual: self.path, expected: castObject.path)) - results.append(contentsOf: DiffableResult(identifier: "module").trackDifference(actual: self.module, expected: castObject.module)) - results.append(contentsOf: DiffableResult(identifier: "types").trackDifference(actual: self.types, expected: castObject.types)) - results.append(contentsOf: DiffableResult(identifier: "functions").trackDifference(actual: self.functions, expected: castObject.functions)) - results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) - results.append(contentsOf: DiffableResult(identifier: "inlineRanges").trackDifference(actual: self.inlineRanges, expected: castObject.inlineRanges)) - results.append(contentsOf: DiffableResult(identifier: "inlineIndentations").trackDifference(actual: self.inlineIndentations, expected: castObject.inlineIndentations)) - results.append(contentsOf: DiffableResult(identifier: "modifiedDate").trackDifference(actual: self.modifiedDate, expected: castObject.modifiedDate)) - results.append(contentsOf: DiffableResult(identifier: "sourceryVersion").trackDifference(actual: self.sourceryVersion, expected: castObject.sourceryVersion)) + results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) + results.append(contentsOf: DiffableResult(identifier: "detail").trackDifference(actual: self.detail, expected: castObject.detail)) return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() - hasher.combine(self.path) - hasher.combine(self.module) - hasher.combine(self.types) - hasher.combine(self.functions) - hasher.combine(self.typealiases) - hasher.combine(self.inlineRanges) - hasher.combine(self.inlineIndentations) - hasher.combine(self.modifiedDate) - hasher.combine(self.sourceryVersion) + hasher.combine(self.name) + hasher.combine(self.detail) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? FileParserResult else { return false } - if self.path != rhs.path { return false } - if self.module != rhs.module { return false } - if self.types != rhs.types { return false } - if self.functions != rhs.functions { return false } - if self.typealiases != rhs.typealiases { return false } - if self.inlineRanges != rhs.inlineRanges { return false } - if self.inlineIndentations != rhs.inlineIndentations { return false } - if self.modifiedDate != rhs.modifiedDate { return false } - if self.sourceryVersion != rhs.sourceryVersion { return false } + guard let rhs = object as? Modifier else { return false } + if self.name != rhs.name { return false } + if self.detail != rhs.detail { return false } return true } -// sourcery:inline:FileParserResult.AutoCoding + // sourcery:inline:Modifier.AutoCoding - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - self.path = aDecoder.decode(forKey: "path") - self.module = aDecoder.decode(forKey: "module") - guard let types: [Type] = aDecoder.decode(forKey: "types") else { - withVaList(["types"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.types = types - guard let functions: [SourceryMethod] = aDecoder.decode(forKey: "functions") else { - withVaList(["functions"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.functions = functions - guard let typealiases: [Typealias] = aDecoder.decode(forKey: "typealiases") else { - withVaList(["typealiases"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.typealiases = typealiases - guard let inlineRanges: [String: NSRange] = aDecoder.decode(forKey: "inlineRanges") else { - withVaList(["inlineRanges"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.inlineRanges = inlineRanges - guard let inlineIndentations: [String: String] = aDecoder.decode(forKey: "inlineIndentations") else { - withVaList(["inlineIndentations"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.inlineIndentations = inlineIndentations - guard let modifiedDate: Date = aDecoder.decode(forKey: "modifiedDate") else { - withVaList(["modifiedDate"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.modifiedDate = modifiedDate - guard let sourceryVersion: String = aDecoder.decode(forKey: "sourceryVersion") else { - withVaList(["sourceryVersion"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.sourceryVersion = sourceryVersion - } + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let name: String = aDecoder.decode(forKey: "name") else { + withVaList(["name"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.name = name + self.detail = aDecoder.decode(forKey: "detail") + } - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.path, forKey: "path") - aCoder.encode(self.module, forKey: "module") - aCoder.encode(self.types, forKey: "types") - aCoder.encode(self.functions, forKey: "functions") - aCoder.encode(self.typealiases, forKey: "typealiases") - aCoder.encode(self.inlineRanges, forKey: "inlineRanges") - aCoder.encode(self.inlineIndentations, forKey: "inlineIndentations") - aCoder.encode(self.modifiedDate, forKey: "modifiedDate") - aCoder.encode(self.sourceryVersion, forKey: "sourceryVersion") - } -// sourcery:end + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.detail, forKey: "detail") + } + // sourcery:end } """), - .init(name: "Generic.swift", content: + .init(name: "ParserResultsComposed.swift", content: """ +// +// Created by Krzysztof Zablocki on 31/12/2016. +// Copyright (c) 2016 Pixle. All rights reserved. +// + import Foundation -/// Descibes Swift generic type -public final class GenericType: NSObject, SourceryModelWithoutDescription, Diffable { - /// The name of the base type, i.e. `Array` for `Array` - public var name: String +internal struct ParserResultsComposed { + private(set) var typeMap = [String: Type]() + private(set) var modules = [String: [String: Type]]() + private(set) var types = [Type]() - /// This generic type parameters - public let typeParameters: [GenericTypeParameter] + let parsedTypes: [Type] + let functions: [SourceryMethod] + let resolvedTypealiases: [String: Typealias] + let unresolvedTypealiases: [String: Typealias] - /// :nodoc: - public init(name: String, typeParameters: [GenericTypeParameter] = []) { - self.name = name - self.typeParameters = typeParameters - } + init(parserResult: FileParserResult) { + // TODO: This logic should really be more complicated + // For any resolution we need to be looking at accessLevel and module boundaries + // e.g. there might be a typealias `private typealias Something = MyType` in one module and same name in another with public modifier, one could be accessed and the other could not + self.functions = parserResult.functions + let aliases = Self.typealiases(parserResult) + resolvedTypealiases = aliases.resolved + unresolvedTypealiases = aliases.unresolved + parsedTypes = parserResult.types - public var asSource: String { - let arguments = typeParameters - .map({ $0.typeName.asSource }) - .joined(separator: ", ") - return "\\(name)<\\(arguments)>" - } + // set definedInType for all methods and variables + parsedTypes + .forEach { type in + type.variables.forEach { $0.definedInType = type } + type.methods.forEach { $0.definedInType = type } + type.subscripts.forEach { $0.definedInType = type } + } - public override var description: String { - asSource - } + // map all known types to their names + parsedTypes + .filter { !$0.isExtension } + .forEach { + typeMap[$0.globalName] = $0 + if let module = $0.module { + var typesByModules = modules[module, default: [:]] + typesByModules[$0.name] = $0 + modules[module] = typesByModules + } + } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? GenericType else { - results.append("Incorrect type ") - return results + /// Resolve typealiases + let typealiases = Array(unresolvedTypealiases.values) + typealiases.forEach { alias in + alias.type = resolveType(typeName: alias.typeName, containingType: alias.parent) } - results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "typeParameters").trackDifference(actual: self.typeParameters, expected: castObject.typeParameters)) - return results + + types = unifyTypes() } - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.name) - hasher.combine(self.typeParameters) - return hasher.finalize() + private func resolveExtensionOfNestedType(_ type: Type) { + var components = type.localName.components(separatedBy: ".") + let rootName = type.module ?? components.removeFirst() // Module/parent name + if let moduleTypes = modules[rootName], let baseType = moduleTypes[components.joined(separator: ".")] ?? moduleTypes[type.localName] { + type.localName = baseType.localName + type.module = baseType.module + type.parent = baseType.parent + } else { + for _import in type.imports { + let parentKey = "\\(rootName).\\(components.joined(separator: "."))" + let parentKeyFull = "\\(_import.moduleName).\\(parentKey)" + if let moduleTypes = modules[_import.moduleName], let baseType = moduleTypes[parentKey] ?? moduleTypes[parentKeyFull] { + type.localName = baseType.localName + type.module = baseType.module + type.parent = baseType.parent + return + } + } + } } - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? GenericType else { return false } - if self.name != rhs.name { return false } - if self.typeParameters != rhs.typeParameters { return false } - return true + // if it had contained types, they might have been fully defined and so their name has to be noted in uniques + private mutating func rewriteChildren(of type: Type) { + // child is never an extension so no need to check + for child in type.containedTypes { + typeMap[child.globalName] = child + rewriteChildren(of: child) + } } -// sourcery:inline:GenericType.AutoCoding + private mutating func unifyTypes() -> [Type] { + /// Resolve actual names of extensions, as they could have been done on typealias and note updated child names in uniques if needed + parsedTypes + .filter { $0.isExtension } + .forEach { (type: Type) in + let oldName = type.globalName - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { - withVaList(["name"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + let hasDotInLocalName = type.localName.contains(".") as Bool + if let _ = type.parent, hasDotInLocalName { + resolveExtensionOfNestedType(type) } - fatalError() - }; self.name = name - guard let typeParameters: [GenericTypeParameter] = aDecoder.decode(forKey: "typeParameters") else { - withVaList(["typeParameters"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + + if let resolved = resolveGlobalName(for: oldName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases)?.name { + var moduleName: String = "" + if let module = type.module { + moduleName = "\\(module)." + } + type.localName = resolved.replacingOccurrences(of: moduleName, with: "") + } else { + return } - fatalError() - }; self.typeParameters = typeParameters - } - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.typeParameters, forKey: "typeParameters") - } + // nothing left to do + guard oldName != type.globalName else { + return + } + rewriteChildren(of: type) + } -// sourcery:end -} + // extend all types with their extensions + parsedTypes.forEach { type in + type.inheritedTypes = type.inheritedTypes.map { inheritedName in + resolveGlobalName(for: inheritedName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases)?.name ?? inheritedName + } -/// Descibes Swift generic type parameter -public final class GenericTypeParameter: NSObject, SourceryModel, Diffable { + let uniqueType = typeMap[type.globalName] ?? // this check will only fail on an extension? + typeFromComposedName(type.name, modules: modules) ?? // this can happen for an extension on unknown type, this case should probably be handled by the inferTypeNameFromModules + (inferTypeNameFromModules(from: type.localName, containedInType: type.parent, uniqueTypes: typeMap, modules: modules).flatMap { typeMap[$0] }) - /// Generic parameter type name - public var typeName: TypeName + guard let current = uniqueType else { + assert(type.isExtension, "Type \\(type.globalName) should be extension") - // sourcery: skipEquality, skipDescription - /// Generic parameter type, if known - public var type: Type? + // for unknown types we still store their extensions but mark them as unknown + type.isUnknownExtension = true + if let existingType = typeMap[type.globalName] { + existingType.extend(type) + typeMap[type.globalName] = existingType + } else { + typeMap[type.globalName] = type + } - /// :nodoc: - public init(typeName: TypeName, type: Type? = nil) { - self.typeName = typeName - self.type = type - } + let inheritanceClause = type.inheritedTypes.isEmpty ? "" : + ": \\(type.inheritedTypes.joined(separator: ", "))" - /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "typeName = \\(String(describing: self.typeName))" - return string - } + Log.astWarning("Found \\"extension \\(type.name)\\(inheritanceClause)\\" of type for which there is no original type declaration information.") + return + } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? GenericTypeParameter else { - results.append("Incorrect type ") - return results + if current == type { return } + + current.extend(type) + typeMap[current.globalName] = current } - results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) - return results - } - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.typeName) - return hasher.finalize() + let values = typeMap.values + var processed = Set(minimumCapacity: values.count) + return typeMap.values.filter({ + let name = $0.globalName + let wasProcessed = processed.contains(name) + processed.insert(name) + return !wasProcessed + }) } - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? GenericTypeParameter else { return false } - if self.typeName != rhs.typeName { return false } - return true - } + /// returns typealiases map to their full names, with `resolved` removing intermediate + /// typealises and `unresolved` including typealiases that reference other typealiases. + private static func typealiases(_ parserResult: FileParserResult) -> (resolved: [String: Typealias], unresolved: [String: Typealias]) { + var typealiasesByNames = [String: Typealias]() + parserResult.typealiases.forEach { typealiasesByNames[$0.name] = $0 } + parserResult.types.forEach { type in + type.typealiases.forEach({ (_, alias) in + // TODO: should I deal with the fact that alias.name depends on type name but typenames might be updated later on + // maybe just handle non extension case here and extension aliases after resolving them? + typealiasesByNames[alias.name] = alias + }) + } -// sourcery:inline:GenericTypeParameter.AutoCoding + let unresolved = typealiasesByNames - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { - withVaList(["typeName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.typeName = typeName - self.type = aDecoder.decode(forKey: "type") - } + // ! if a typealias leads to another typealias, follow through and replace with final type + typealiasesByNames.forEach { _, alias in + var aliasNamesToReplace = [alias.name] + var finalAlias = alias + while let targetAlias = typealiasesByNames[finalAlias.typeName.name] { + aliasNamesToReplace.append(targetAlias.name) + finalAlias = targetAlias + } - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.typeName, forKey: "typeName") - aCoder.encode(self.type, forKey: "type") + // ! replace all keys + aliasNamesToReplace.forEach { typealiasesByNames[$0] = finalAlias } } -// sourcery:end -} + return (resolved: typealiasesByNames, unresolved: unresolved) + } -"""), - .init(name: "GenericRequirement.swift", content: -""" -import Foundation + /// Resolves type identifier for name + func resolveGlobalName(for type: String, + containingType: Type? = nil, + unique: [String: Type]? = nil, + modules: [String: [String: Type]], + typealiases: [String: Typealias]) -> (name: String, typealias: Typealias?)? { + // if the type exists for this name and isn't an extension just return it's name + // if it's extension we need to check if there aren't other options TODO: verify + if let realType = unique?[type], realType.isExtension == false { + return (name: realType.globalName, typealias: nil) + } -/// modifier can be thing like `private`, `class`, `nonmutating` -/// if a declaration has modifier like `private(set)` it's name will be `private` and detail will be `set` -public class GenericRequirement: NSObject, SourceryModel, Diffable { + if let alias = typealiases[type] { + return (name: alias.type?.globalName ?? alias.typeName.name, typealias: alias) + } - public enum Relationship: String { - case equals - case conformsTo + if let containingType = containingType { + if type == "Self" { + return (name: containingType.globalName, typealias: nil) + } - var syntax: String { - switch self { - case .equals: - return "==" - case .conformsTo: - return ":" + var currentContainer: Type? = containingType + while currentContainer != nil, let parentName = currentContainer?.globalName { + /// TODO: no parent for sure? + /// manually walk the containment tree + if let name = resolveGlobalName(for: "\\(parentName).\\(type)", containingType: nil, unique: unique, modules: modules, typealiases: typealiases) { + return name + } + + currentContainer = currentContainer?.parent } - } - } - public var leftType: AssociatedType - public let rightType: GenericTypeParameter +// if let name = resolveGlobalName(for: "\\(containingType.globalName).\\(type)", containingType: containingType.parent, unique: unique, modules: modules, typealiases: typealiases) { +// return name +// } - /// relationship name - public let relationship: String +// last check it's via module +// if let module = containingType.module, let name = resolveGlobalName(for: "\\(module).\\(type)", containingType: nil, unique: unique, modules: modules, typealiases: typealiases) { +// return name +// } + } - /// Syntax e.g. `==` or `:` - public let relationshipSyntax: String + // TODO: is this needed? + if let inferred = inferTypeNameFromModules(from: type, containedInType: containingType, uniqueTypes: unique ?? [:], modules: modules) { + return (name: inferred, typealias: nil) + } - public init(leftType: AssociatedType, rightType: GenericTypeParameter, relationship: Relationship) { - self.leftType = leftType - self.rightType = rightType - self.relationship = relationship.rawValue - self.relationshipSyntax = relationship.syntax + return typeFromComposedName(type, modules: modules).map { (name: $0.globalName, typealias: nil) } } - /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "leftType = \\(String(describing: self.leftType)), " - string += "rightType = \\(String(describing: self.rightType)), " - string += "relationship = \\(String(describing: self.relationship)), " - string += "relationshipSyntax = \\(String(describing: self.relationshipSyntax))" - return string - } + private func inferTypeNameFromModules(from typeIdentifier: String, containedInType: Type?, uniqueTypes: [String: Type], modules: [String: [String: Type]]) -> String? { + func fullName(for module: String) -> String { + "\\(module).\\(typeIdentifier)" + } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? GenericRequirement else { - results.append("Incorrect type ") - return results + func type(for module: String) -> Type? { + return modules[module]?[typeIdentifier] } - results.append(contentsOf: DiffableResult(identifier: "leftType").trackDifference(actual: self.leftType, expected: castObject.leftType)) - results.append(contentsOf: DiffableResult(identifier: "rightType").trackDifference(actual: self.rightType, expected: castObject.rightType)) - results.append(contentsOf: DiffableResult(identifier: "relationship").trackDifference(actual: self.relationship, expected: castObject.relationship)) - results.append(contentsOf: DiffableResult(identifier: "relationshipSyntax").trackDifference(actual: self.relationshipSyntax, expected: castObject.relationshipSyntax)) - return results - } - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.leftType) - hasher.combine(self.rightType) - hasher.combine(self.relationship) - hasher.combine(self.relationshipSyntax) - return hasher.finalize() - } + func ambiguousErrorMessage(from types: [Type]) -> String? { + Log.astWarning("Ambiguous type \\(typeIdentifier), found \\(types.map { $0.globalName }.joined(separator: ", ")). Specify module name at declaration site to disambiguate.") + return nil + } - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? GenericRequirement else { return false } - if self.leftType != rhs.leftType { return false } - if self.rightType != rhs.rightType { return false } - if self.relationship != rhs.relationship { return false } - if self.relationshipSyntax != rhs.relationshipSyntax { return false } - return true - } + let explicitModulesAtDeclarationSite: [String] = [ + containedInType?.module.map { [$0] } ?? [], // main module for this typename + containedInType?.imports.map { $0.moduleName } ?? [] // imported modules + ] + .flatMap { $0 } - // sourcery:inline:GenericRequirement.AutoCoding + let remainingModules = Set(modules.keys).subtracting(explicitModulesAtDeclarationSite) - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let leftType: AssociatedType = aDecoder.decode(forKey: "leftType") else { - withVaList(["leftType"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.leftType = leftType - guard let rightType: GenericTypeParameter = aDecoder.decode(forKey: "rightType") else { - withVaList(["rightType"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.rightType = rightType - guard let relationship: String = aDecoder.decode(forKey: "relationship") else { - withVaList(["relationship"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.relationship = relationship - guard let relationshipSyntax: String = aDecoder.decode(forKey: "relationshipSyntax") else { - withVaList(["relationshipSyntax"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.relationshipSyntax = relationshipSyntax + /// We need to check whether we can find type in one of the modules but we need to be careful to avoid amibiguity + /// First checking explicit modules available at declaration site (so source module + all imported ones) + /// If there is no ambigiuity there we can assume that module will be resolved by the compiler + /// If that's not the case we look after remaining modules in the application and if the typename has no ambigiuity we use that + /// But if there is more than 1 typename duplication across modules we have no way to resolve what is the compiler going to use so we fail + let moduleSetsToCheck: [[String]] = [ + explicitModulesAtDeclarationSite, + Array(remainingModules) + ] + + for modules in moduleSetsToCheck { + let possibleTypes = modules + .compactMap { type(for: $0) } + + if possibleTypes.count > 1 { + return ambiguousErrorMessage(from: possibleTypes) } - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.leftType, forKey: "leftType") - aCoder.encode(self.rightType, forKey: "rightType") - aCoder.encode(self.relationship, forKey: "relationship") - aCoder.encode(self.relationshipSyntax, forKey: "relationshipSyntax") + if let type = possibleTypes.first { + return type.globalName } - // sourcery:end -} + } -"""), - .init(name: "Import.swift", content: -""" -import Foundation - -/// Defines import type -public class Import: NSObject, SourceryModelWithoutDescription, Diffable { - /// Import kind, e.g. class, struct in `import class Module.ClassName` - public var kind: String? - - /// Import path - public var path: String - - /// :nodoc: - public init(path: String, kind: String? = nil) { - self.path = path - self.kind = kind - } - - /// Full import value e.g. `import struct Module.StructName` - public override var description: String { - if let kind = kind { - return "\\(kind) \\(path)" + // as last result for unknown types / extensions + // try extracting type from unique array + if let module = containedInType?.module { + return uniqueTypes[fullName(for: module)]?.globalName } + return nil + } - return path + func typeFromComposedName(_ name: String, modules: [String: [String: Type]]) -> Type? { + guard name.contains(".") else { return nil } + let nameComponents = name.components(separatedBy: ".") + let moduleName = nameComponents[0] + let typeName = nameComponents.suffix(from: 1).joined(separator: ".") + return modules[moduleName]?[typeName] } - /// Returns module name from a import, e.g. if you had `import struct Module.Submodule.Struct` it will return `Module.Submodule` - public var moduleName: String { - if kind != nil { - if let idx = path.lastIndex(of: ".") { - return String(path[.. Type? { + let resolveTypeWithName = { (typeName: TypeName) -> Type? in + return self.resolveType(typeName: typeName, containingType: containingType) } - } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? Import else { - results.append("Incorrect type ") - return results + let unique = typeMap + + if let name = typeName.actualTypeName { + let resolvedIdentifier = name.generic?.name ?? name.unwrappedTypeName + return unique[resolvedIdentifier] } - results.append(contentsOf: DiffableResult(identifier: "kind").trackDifference(actual: self.kind, expected: castObject.kind)) - results.append(contentsOf: DiffableResult(identifier: "path").trackDifference(actual: self.path, expected: castObject.path)) - return results - } - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.kind) - hasher.combine(self.path) - return hasher.finalize() - } + let retrievedName = actualTypeName(for: typeName, containingType: containingType) + let lookupName = retrievedName ?? typeName - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? Import else { return false } - if self.kind != rhs.kind { return false } - if self.path != rhs.path { return false } - return true - } + if let tuple = lookupName.tuple { + var needsUpdate = false -// sourcery:inline:Import.AutoCoding + tuple.elements.forEach { tupleElement in + tupleElement.type = resolveTypeWithName(tupleElement.typeName) + if tupleElement.typeName.actualTypeName != nil { + needsUpdate = true + } + } - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - self.kind = aDecoder.decode(forKey: "kind") - guard let path: String = aDecoder.decode(forKey: "path") else { - withVaList(["path"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + if needsUpdate || retrievedName != nil { + let tupleCopy = TupleType(name: tuple.name, elements: tuple.elements) + tupleCopy.elements.forEach { + $0.typeName = $0.actualTypeName ?? $0.typeName + $0.typeName.actualTypeName = nil } - fatalError() - }; self.path = path - } + tupleCopy.name = tupleCopy.elements.asTypeName - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.kind, forKey: "kind") - aCoder.encode(self.path, forKey: "path") - } + typeName.tuple = tupleCopy // TODO: really don't like this old behaviour + typeName.actualTypeName = TypeName(name: tupleCopy.name, + isOptional: typeName.isOptional, + isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, + tuple: tupleCopy, + array: lookupName.array, + dictionary: lookupName.dictionary, + closure: lookupName.closure, + set: lookupName.set, + generic: lookupName.generic + ) + } + return nil + } else + if let array = lookupName.array { + array.elementType = resolveTypeWithName(array.elementTypeName) -// sourcery:end -} + if array.elementTypeName.actualTypeName != nil || retrievedName != nil { + let array = ArrayType(name: array.name, elementTypeName: array.elementTypeName, elementType: array.elementType) + array.elementTypeName = array.elementTypeName.actualTypeName ?? array.elementTypeName + array.elementTypeName.actualTypeName = nil + array.name = array.asSource + typeName.array = array // TODO: really don't like this old behaviour + typeName.generic = array.asGeneric // TODO: really don't like this old behaviour -"""), - .init(name: "Log.swift", content: -""" -import Foundation + typeName.actualTypeName = TypeName(name: array.name, + isOptional: typeName.isOptional, + isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, + tuple: lookupName.tuple, + array: array, + dictionary: lookupName.dictionary, + closure: lookupName.closure, + set: lookupName.set, + generic: typeName.generic + ) + } + } else + if let dictionary = lookupName.dictionary { + dictionary.keyType = resolveTypeWithName(dictionary.keyTypeName) + dictionary.valueType = resolveTypeWithName(dictionary.valueTypeName) -/// :nodoc: -public enum Log { + if dictionary.keyTypeName.actualTypeName != nil || dictionary.valueTypeName.actualTypeName != nil || retrievedName != nil { + let dictionary = DictionaryType(name: dictionary.name, valueTypeName: dictionary.valueTypeName, valueType: dictionary.valueType, keyTypeName: dictionary.keyTypeName, keyType: dictionary.keyType) + dictionary.keyTypeName = dictionary.keyTypeName.actualTypeName ?? dictionary.keyTypeName + dictionary.keyTypeName.actualTypeName = nil // TODO: really don't like this old behaviour + dictionary.valueTypeName = dictionary.valueTypeName.actualTypeName ?? dictionary.valueTypeName + dictionary.valueTypeName.actualTypeName = nil // TODO: really don't like this old behaviour - public enum Level: Int { - case errors - case warnings - case info - case verbose - } + dictionary.name = dictionary.asSource - public static var level: Level = .warnings - public static var logBenchmarks: Bool = false - public static var logAST: Bool = false + typeName.dictionary = dictionary // TODO: really don't like this old behaviour + typeName.generic = dictionary.asGeneric // TODO: really don't like this old behaviour - public static var stackMessages: Bool = false - public private(set) static var messagesStack = [String]() + typeName.actualTypeName = TypeName(name: dictionary.asSource, + isOptional: typeName.isOptional, + isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, + tuple: lookupName.tuple, + array: lookupName.array, + dictionary: dictionary, + closure: lookupName.closure, + set: lookupName.set, + generic: dictionary.asGeneric + ) + } + } else + if let closure = lookupName.closure { + var needsUpdate = false - public static func error(_ message: Any) { - log(level: .errors, "error: \\(message)") - // to return error when running swift templates which is done in a different process - if ProcessInfo.processInfo.processName != "Sourcery" { - fputs("\\(message)", stderr) - } - } + closure.returnType = resolveTypeWithName(closure.returnTypeName) + closure.parameters.forEach { parameter in + parameter.type = resolveTypeWithName(parameter.typeName) + if parameter.typeName.actualTypeName != nil { + needsUpdate = true + } + } - public static func warning(_ message: Any) { - log(level: .warnings, "warning: \\(message)") - } + if closure.returnTypeName.actualTypeName != nil || needsUpdate || retrievedName != nil { + typeName.closure = closure // TODO: really don't like this old behaviour - public static func astWarning(_ message: Any) { - guard logAST else { return } - log(level: .warnings, "ast warning: \\(message)") - } + typeName.actualTypeName = TypeName(name: closure.asSource, + isOptional: typeName.isOptional, + isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, + tuple: lookupName.tuple, + array: lookupName.array, + dictionary: lookupName.dictionary, + closure: closure, + set: lookupName.set, + generic: lookupName.generic + ) + } - public static func astError(_ message: Any) { - guard logAST else { return } - log(level: .errors, "ast error: \\(message)") - } + return nil + } else + if let generic = lookupName.generic { + var needsUpdate = false - public static func verbose(_ message: Any) { - log(level: .verbose, message) - } + generic.typeParameters.forEach { parameter in + parameter.type = resolveTypeWithName(parameter.typeName) + if parameter.typeName.actualTypeName != nil { + needsUpdate = true + } + } - public static func info(_ message: Any) { - log(level: .info, message) - } + if needsUpdate || retrievedName != nil { + let generic = GenericType(name: generic.name, typeParameters: generic.typeParameters) + generic.typeParameters.forEach { + $0.typeName = $0.typeName.actualTypeName ?? $0.typeName + $0.typeName.actualTypeName = nil // TODO: really don't like this old behaviour + } + typeName.generic = generic // TODO: really don't like this old behaviour + typeName.array = lookupName.array // TODO: really don't like this old behaviour + typeName.dictionary = lookupName.dictionary // TODO: really don't like this old behaviour - public static func benchmark(_ message: Any) { - guard logBenchmarks else { return } - if stackMessages { - messagesStack.append("\\(message)") - } else { - print(message) - } - } + let params = generic.typeParameters.map { $0.typeName.asSource }.joined(separator: ", ") - private static func log(level logLevel: Level, _ message: Any) { - guard logLevel.rawValue <= Log.level.rawValue else { return } - if stackMessages { - messagesStack.append("\\(message)") - } else { - print(message) + typeName.actualTypeName = TypeName(name: "\\(generic.name)<\\(params)>", + isOptional: typeName.isOptional, + isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, + tuple: lookupName.tuple, + array: lookupName.array, // TODO: asArray + dictionary: lookupName.dictionary, // TODO: asDictionary + closure: lookupName.closure, + set: lookupName.set, + generic: generic + ) + } + } + + if let aliasedName = (typeName.actualTypeName ?? retrievedName), aliasedName.unwrappedTypeName != typeName.unwrappedTypeName { + typeName.actualTypeName = aliasedName + } + + let hasGenericRequirements = containingType?.genericRequirements.isEmpty == false + || (method != nil && method?.genericRequirements.isEmpty == false) + + if hasGenericRequirements { + // we should consider if we are looking up return type of a method with generic constraints + // where `typeName` passed would include `... where ...` suffix + let typeNameForLookup = typeName.name.split(separator: " ").first! + let genericRequirements: [GenericRequirement] + if let requirements = containingType?.genericRequirements, !requirements.isEmpty { + genericRequirements = requirements + } else { + genericRequirements = method?.genericRequirements ?? [] + } + let relevantRequirements = genericRequirements.filter { + // matched type against a generic requirement name + // thus type should be replaced with a protocol composition + $0.leftType.name == typeNameForLookup + } + if relevantRequirements.count > 1 { + // compose protocols into `ProtocolComposition` and generate TypeName + var implements: [String: Type] = [:] + relevantRequirements.forEach { + implements[$0.rightType.typeName.name] = $0.rightType.type + } + let composedProtocols = ProtocolComposition( + inheritedTypes: relevantRequirements.map { $0.rightType.typeName.unwrappedTypeName }, + isGeneric: true, + composedTypes: relevantRequirements.compactMap { $0.rightType.type }, + implements: implements + ) + typeName.actualTypeName = TypeName(name: "(\\(relevantRequirements.map { $0.rightType.typeName.unwrappedTypeName }.joined(separator: " & ")))", isProtocolComposition: true) + return composedProtocols + } else if let protocolRequirement = relevantRequirements.first { + // create TypeName off a single generic's protocol requirement + typeName.actualTypeName = TypeName(name: "(\\(protocolRequirement.rightType.typeName))") + return protocolRequirement.rightType.type + } + } + + // try to peek into typealias, maybe part of the typeName is a composed identifier from a type and typealias + // i.e. + // enum Module { + // typealias ID = MyView + // } + // class MyView { + // class ID: String {} + // } + // + // let variable: Module.ID.ID // should be resolved as MyView.ID type + let finalLookup = typeName.actualTypeName ?? typeName + var resolvedIdentifier = finalLookup.generic?.name ?? finalLookup.unwrappedTypeName + for alias in resolvedTypealiases { + /// iteratively replace all typealiases from the resolvedIdentifier to get to the actual type name requested + if resolvedIdentifier.contains(alias.value.name), let range = resolvedIdentifier.range(of: alias.value.name) { + resolvedIdentifier = resolvedIdentifier.replacingCharacters(in: range, with: alias.value.typeName.name) + } + } + // should we cache resolved typenames? + if unique[resolvedIdentifier] == nil { + // peek into typealiases, if any of them contain the same typeName + // this is done after the initial attempt in order to prioritise local (recognized) types first + // before even trying to substitute the requested type with any typealias + for alias in resolvedTypealiases { + /// iteratively replace all typealiases from the resolvedIdentifier to get to the actual type name requested, + /// ignoring namespacing + if resolvedIdentifier == alias.value.aliasName { + resolvedIdentifier = alias.value.typeName.name + typeName.actualTypeName = alias.value.typeName + break + } + } } + + return unique[resolvedIdentifier] } - public static func output(_ message: String) { - print(message) + private func actualTypeName(for typeName: TypeName, + containingType: Type? = nil) -> TypeName? { + let unique = typeMap + let typealiases = resolvedTypealiases + + var unwrapped = typeName.unwrappedTypeName + if let generic = typeName.generic { + unwrapped = generic.name + } + + guard let aliased = resolveGlobalName(for: unwrapped, containingType: containingType, unique: unique, modules: modules, typealiases: typealiases) else { + return nil + } + + /// TODO: verify + let generic = typeName.generic.map { GenericType(name: $0.name, typeParameters: $0.typeParameters) } + generic?.name = aliased.name + let dictionary = typeName.dictionary.map { DictionaryType(name: $0.name, valueTypeName: $0.valueTypeName, valueType: $0.valueType, keyTypeName: $0.keyTypeName, keyType: $0.keyType) } + dictionary?.name = aliased.name + let array = typeName.array.map { ArrayType(name: $0.name, elementTypeName: $0.elementTypeName, elementType: $0.elementType) } + array?.name = aliased.name + let set = typeName.set.map { SetType(name: $0.name, elementTypeName: $0.elementTypeName, elementType: $0.elementType) } + set?.name = aliased.name + + return TypeName(name: aliased.name, + isOptional: typeName.isOptional, + isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, + tuple: aliased.typealias?.typeName.tuple ?? typeName.tuple, // TODO: verify + array: aliased.typealias?.typeName.array ?? array, + dictionary: aliased.typealias?.typeName.dictionary ?? dictionary, + closure: aliased.typealias?.typeName.closure ?? typeName.closure, + set: aliased.typealias?.typeName.set ?? set, + generic: aliased.typealias?.typeName.generic ?? generic + ) } -} -extension String: Error {} +} """), - .init(name: "MethodParameter.swift", content: + .init(name: "PhantomProtocols.swift", content: """ +// +// Created by Krzysztof Zablocki on 23/01/2017. +// Copyright (c) 2017 Pixle. All rights reserved. +// + import Foundation -/// Describes method parameter -public class MethodParameter: NSObject, SourceryModel, Typed, Annotated, Diffable { +/// Phantom protocol for diffing +protocol AutoDiffable {} - /// Parameter external name - public var argumentLabel: String? +/// Phantom protocol for equality +protocol AutoEquatable {} - // Note: although method parameter can have no name, this property is not optional, - // this is so to maintain compatibility with existing templates. - /// Parameter internal name - public let name: String +/// Phantom protocol for equality +protocol AutoDescription {} - /// Parameter type name - public let typeName: TypeName +/// Phantom protocol for NSCoding +protocol AutoCoding {} - /// Parameter flag whether it's inout or not - public let `inout`: Bool +protocol AutoJSExport {} - /// Is this variadic parameter? - public let isVariadic: Bool +/// Phantom protocol for NSCoding, Equatable and Diffable +protocol SourceryModelWithoutDescription: AutoDiffable, AutoEquatable, AutoCoding, AutoJSExport {} - // sourcery: skipEquality, skipDescription - /// Parameter type, if known - public var type: Type? +protocol SourceryModel: SourceryModelWithoutDescription, AutoDescription {} - /// Parameter type attributes, i.e. `@escaping` - public var typeAttributes: AttributeList { - return typeName.attributes - } +"""), + .init(name: "Protocol.swift", content: +""" +// +// Protocol.swift +// Sourcery +// +// Created by Krzysztof Zablocki on 09/12/2016. +// Copyright © 2016 Pixle. All rights reserved. +// - /// Method parameter default value expression - public var defaultValue: String? +import Foundation - /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 - public var annotations: Annotations = [:] +/// :nodoc: +public typealias SourceryProtocol = Protocol - /// :nodoc: - public init(argumentLabel: String?, name: String = "", typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false, isVariadic: Bool = false) { - self.typeName = typeName - self.argumentLabel = argumentLabel - self.name = name - self.type = type - self.defaultValue = defaultValue - self.annotations = annotations - self.`inout` = isInout - self.isVariadic = isVariadic - } +/// Describes Swift protocol +#if canImport(ObjectiveC) +@objcMembers +#endif +public final class Protocol: Type { - /// :nodoc: - public init(name: String = "", typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false, isVariadic: Bool = false) { - self.typeName = typeName - self.argumentLabel = name - self.name = name - self.type = type - self.defaultValue = defaultValue - self.annotations = annotations - self.`inout` = isInout - self.isVariadic = isVariadic - } + /// Returns "protocol" + public override var kind: String { return "protocol" } - public var asSource: String { - let typeSuffix = ": \\(`inout` ? "inout " : "")\\(typeName.asSource)\\(defaultValue.map { " = \\($0)" } ?? "")" + (isVariadic ? "..." : "") - guard argumentLabel != name else { - return name + typeSuffix + /// list of all declared associated types with their names as keys + public var associatedTypes: [String: AssociatedType] { + didSet { + isGeneric = !associatedTypes.isEmpty || !genericRequirements.isEmpty } - - let labels = [argumentLabel ?? "_", name.nilIfEmpty] - .compactMap { $0 } - .joined(separator: " ") - - return (labels.nilIfEmpty ?? "_") + typeSuffix - } - - /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "argumentLabel = \\(String(describing: self.argumentLabel)), " - string += "name = \\(String(describing: self.name)), " - string += "typeName = \\(String(describing: self.typeName)), " - string += "`inout` = \\(String(describing: self.`inout`)), " - string += "isVariadic = \\(String(describing: self.isVariadic)), " - string += "typeAttributes = \\(String(describing: self.typeAttributes)), " - string += "defaultValue = \\(String(describing: self.defaultValue)), " - string += "annotations = \\(String(describing: self.annotations)), " - string += "asSource = \\(String(describing: self.asSource))" - return string } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? MethodParameter else { - results.append("Incorrect type ") - return results + // sourcery: skipCoding + /// list of generic requirements + public override var genericRequirements: [GenericRequirement] { + didSet { + isGeneric = !associatedTypes.isEmpty || !genericRequirements.isEmpty } - results.append(contentsOf: DiffableResult(identifier: "argumentLabel").trackDifference(actual: self.argumentLabel, expected: castObject.argumentLabel)) - results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) - results.append(contentsOf: DiffableResult(identifier: "`inout`").trackDifference(actual: self.`inout`, expected: castObject.`inout`)) - results.append(contentsOf: DiffableResult(identifier: "isVariadic").trackDifference(actual: self.isVariadic, expected: castObject.isVariadic)) - results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) - results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) - return results } - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.argumentLabel) - hasher.combine(self.name) - hasher.combine(self.typeName) - hasher.combine(self.`inout`) - hasher.combine(self.isVariadic) - hasher.combine(self.defaultValue) - hasher.combine(self.annotations) + /// :nodoc: + public init(name: String = "", + parent: Type? = nil, + accessLevel: AccessLevel = .internal, + isExtension: Bool = false, + variables: [Variable] = [], + methods: [Method] = [], + subscripts: [Subscript] = [], + inheritedTypes: [String] = [], + containedTypes: [Type] = [], + typealiases: [Typealias] = [], + associatedTypes: [String: AssociatedType] = [:], + genericRequirements: [GenericRequirement] = [], + attributes: AttributeList = [:], + modifiers: [SourceryModifier] = [], + annotations: [String: NSObject] = [:], + documentation: [String] = [], + implements: [String: Type] = [:]) { + self.associatedTypes = associatedTypes + super.init( + name: name, + parent: parent, + accessLevel: accessLevel, + isExtension: isExtension, + variables: variables, + methods: methods, + subscripts: subscripts, + inheritedTypes: inheritedTypes, + containedTypes: containedTypes, + typealiases: typealiases, + genericRequirements: genericRequirements, + attributes: attributes, + modifiers: modifiers, + annotations: annotations, + documentation: documentation, + isGeneric: !associatedTypes.isEmpty || !genericRequirements.isEmpty, + implements: implements + ) + } + + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = super.description + string.append(", ") + string.append("kind = \\(String(describing: self.kind)), ") + string.append("associatedTypes = \\(String(describing: self.associatedTypes)), ") + return string + } + + override public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? Protocol else { + results.append("Incorrect type ") + return results + } + results.append(contentsOf: DiffableResult(identifier: "associatedTypes").trackDifference(actual: self.associatedTypes, expected: castObject.associatedTypes)) + results.append(contentsOf: super.diffAgainst(castObject)) + return results + } + + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.associatedTypes) + hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? MethodParameter else { return false } - if self.argumentLabel != rhs.argumentLabel { return false } - if self.name != rhs.name { return false } - if self.typeName != rhs.typeName { return false } - if self.`inout` != rhs.`inout` { return false } - if self.isVariadic != rhs.isVariadic { return false } - if self.defaultValue != rhs.defaultValue { return false } - if self.annotations != rhs.annotations { return false } - return true + guard let rhs = object as? Protocol else { return false } + if self.associatedTypes != rhs.associatedTypes { return false } + return super.isEqual(rhs) } -// sourcery:inline:MethodParameter.AutoCoding +// sourcery:inline:Protocol.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { - self.argumentLabel = aDecoder.decode(forKey: "argumentLabel") - guard let name: String = aDecoder.decode(forKey: "name") else { - withVaList(["name"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.name = name - guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { - withVaList(["typeName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.typeName = typeName - self.`inout` = aDecoder.decode(forKey: "`inout`") - self.isVariadic = aDecoder.decode(forKey: "isVariadic") - self.type = aDecoder.decode(forKey: "type") - self.defaultValue = aDecoder.decode(forKey: "defaultValue") - guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { - withVaList(["annotations"]) { arguments in + guard let associatedTypes: [String: AssociatedType] = aDecoder.decode(forKey: "associatedTypes") else { + withVaList(["associatedTypes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.annotations = annotations + }; self.associatedTypes = associatedTypes + super.init(coder: aDecoder) } /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.argumentLabel, forKey: "argumentLabel") - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.typeName, forKey: "typeName") - aCoder.encode(self.`inout`, forKey: "`inout`") - aCoder.encode(self.isVariadic, forKey: "isVariadic") - aCoder.encode(self.type, forKey: "type") - aCoder.encode(self.defaultValue, forKey: "defaultValue") - aCoder.encode(self.annotations, forKey: "annotations") + override public func encode(with aCoder: NSCoder) { + super.encode(with: aCoder) + aCoder.encode(self.associatedTypes, forKey: "associatedTypes") } // sourcery:end } -extension Array where Element == MethodParameter { - public var asSource: String { - "(\\(map { $0.asSource }.joined(separator: ", ")))" - } -} - """), - .init(name: "ClosureParameter.swift", content: + .init(name: "ProtocolComposition.swift", content: """ -import Foundation +// Created by eric_horacek on 2/12/20. +// Copyright © 2020 Airbnb Inc. All rights reserved. -// sourcery: skipDiffing -public final class ClosureParameter: NSObject, SourceryModel, Typed, Annotated { - /// Parameter external name - public var argumentLabel: String? +import Foundation - /// Parameter internal name - public let name: String? +/// Describes a Swift [protocol composition](https://docs.swift.org/swift-book/ReferenceManual/Types.html#ID454). +#if canImport(ObjectiveC) +@objcMembers +#endif +public final class ProtocolComposition: Type { - /// Parameter type name - public let typeName: TypeName + /// Returns "protocolComposition" + public override var kind: String { return "protocolComposition" } - /// Parameter flag whether it's inout or not - public let `inout`: Bool + /// The names of the types composed to form this composition + public let composedTypeNames: [TypeName] // sourcery: skipEquality, skipDescription - /// Parameter type, if known - public var type: Type? + /// The types composed to form this composition, if known + public var composedTypes: [Type]? - /// Parameter type attributes, i.e. `@escaping` - public var typeAttributes: AttributeList { - return typeName.attributes + /// :nodoc: + public init(name: String = "", + parent: Type? = nil, + accessLevel: AccessLevel = .internal, + isExtension: Bool = false, + variables: [Variable] = [], + methods: [Method] = [], + subscripts: [Subscript] = [], + inheritedTypes: [String] = [], + containedTypes: [Type] = [], + typealiases: [Typealias] = [], + attributes: AttributeList = [:], + annotations: [String: NSObject] = [:], + isGeneric: Bool = false, + composedTypeNames: [TypeName] = [], + composedTypes: [Type]? = nil, + implements: [String: Type] = [:]) { + self.composedTypeNames = composedTypeNames + self.composedTypes = composedTypes + super.init( + name: name, + parent: parent, + accessLevel: accessLevel, + isExtension: isExtension, + variables: variables, + methods: methods, + subscripts: subscripts, + inheritedTypes: inheritedTypes, + containedTypes: containedTypes, + typealiases: typealiases, + annotations: annotations, + isGeneric: isGeneric, + implements: implements + ) } - /// Method parameter default value expression - public var defaultValue: String? - - /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 - public var annotations: Annotations = [:] - /// :nodoc: - public init(argumentLabel: String? = nil, name: String? = nil, typeName: TypeName, type: Type? = nil, - defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false) { - self.typeName = typeName - self.argumentLabel = argumentLabel - self.name = name - self.type = type - self.defaultValue = defaultValue - self.annotations = annotations - self.`inout` = isInout + // sourcery: skipJSExport + override public var description: String { + var string = super.description + string += ", " + string += "kind = \\(String(describing: self.kind)), " + string += "composedTypeNames = \\(String(describing: self.composedTypeNames))" + return string } - public var asSource: String { - let typeInfo = "\\(`inout` ? "inout " : "")\\(typeName.asSource)" - if argumentLabel?.nilIfNotValidParameterName == nil, name?.nilIfNotValidParameterName == nil { - return typeInfo - } - - let typeSuffix = ": \\(typeInfo)" - guard argumentLabel != name else { - return name ?? "" + typeSuffix + override public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? ProtocolComposition else { + results.append("Incorrect type ") + return results } - - let labels = [argumentLabel ?? "_", name?.nilIfEmpty] - .compactMap { $0 } - .joined(separator: " ") - - return (labels.nilIfEmpty ?? "_") + typeSuffix + results.append(contentsOf: DiffableResult(identifier: "composedTypeNames").trackDifference(actual: self.composedTypeNames, expected: castObject.composedTypeNames)) + results.append(contentsOf: super.diffAgainst(castObject)) + return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() - hasher.combine(self.argumentLabel) - hasher.combine(self.name) - hasher.combine(self.typeName) - hasher.combine(self.`inout`) - hasher.combine(self.defaultValue) - hasher.combine(self.annotations) + hasher.combine(self.composedTypeNames) + hasher.combine(super.hash) return hasher.finalize() } - /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "argumentLabel = \\(String(describing: self.argumentLabel)), " - string += "name = \\(String(describing: self.name)), " - string += "typeName = \\(String(describing: self.typeName)), " - string += "`inout` = \\(String(describing: self.`inout`)), " - string += "typeAttributes = \\(String(describing: self.typeAttributes)), " - string += "defaultValue = \\(String(describing: self.defaultValue)), " - string += "annotations = \\(String(describing: self.annotations)), " - string += "asSource = \\(String(describing: self.asSource))" - return string - } - /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? ClosureParameter else { return false } - if self.argumentLabel != rhs.argumentLabel { return false } - if self.name != rhs.name { return false } - if self.typeName != rhs.typeName { return false } - if self.`inout` != rhs.`inout` { return false } - if self.defaultValue != rhs.defaultValue { return false } - if self.annotations != rhs.annotations { return false } - return true + guard let rhs = object as? ProtocolComposition else { return false } + if self.composedTypeNames != rhs.composedTypeNames { return false } + return super.isEqual(rhs) } - // sourcery:inline:ClosureParameter.AutoCoding +// sourcery:inline:ProtocolComposition.AutoCoding - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - self.argumentLabel = aDecoder.decode(forKey: "argumentLabel") - self.name = aDecoder.decode(forKey: "name") - guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { - withVaList(["typeName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.typeName = typeName - self.`inout` = aDecoder.decode(forKey: "`inout`") - self.type = aDecoder.decode(forKey: "type") - self.defaultValue = aDecoder.decode(forKey: "defaultValue") - guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { - withVaList(["annotations"]) { arguments in + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let composedTypeNames: [TypeName] = aDecoder.decode(forKey: "composedTypeNames") else { + withVaList(["composedTypeNames"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.annotations = annotations - } - - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.argumentLabel, forKey: "argumentLabel") - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.typeName, forKey: "typeName") - aCoder.encode(self.`inout`, forKey: "`inout`") - aCoder.encode(self.type, forKey: "type") - aCoder.encode(self.defaultValue, forKey: "defaultValue") - aCoder.encode(self.annotations, forKey: "annotations") - } + }; self.composedTypeNames = composedTypeNames + self.composedTypes = aDecoder.decode(forKey: "composedTypes") + super.init(coder: aDecoder) + } - // sourcery:end -} + /// :nodoc: + override public func encode(with aCoder: NSCoder) { + super.encode(with: aCoder) + aCoder.encode(self.composedTypeNames, forKey: "composedTypeNames") + aCoder.encode(self.composedTypes, forKey: "composedTypes") + } +// sourcery:end -extension Array where Element == ClosureParameter { - public var asSource: String { - "(\\(map { $0.asSource }.joined(separator: ", ")))" - } } """), - .init(name: "Method.swift", content: + .init(name: "Set.swift", content: """ import Foundation -/// :nodoc: -public typealias SourceryMethod = Method - -/// Describes method -public final class Method: NSObject, SourceryModel, Annotated, Documented, Definition, Diffable { - public subscript(dynamicMember member: String) -> Any? { - switch member { - case "definedInType": - return definedInType - case "shortName": - return shortName - case "name": - return name - case "selectorName": - return selectorName - case "callName": - return callName - case "parameters": - return parameters - case "throws": - return `throws` - case "isInitializer": - return isInitializer - case "accessLevel": - return accessLevel - case "isStatic": - return isStatic - case "returnTypeName": - return returnTypeName - case "isAsync": - return isAsync - case "attributes": - return attributes - case "isOptionalReturnType": - return isOptionalReturnType - case "actualReturnTypeName": - return actualReturnTypeName - case "isDynamic": - return isDynamic - case "genericRequirements": - return genericRequirements - default: - fatalError("unable to lookup: \\(member) in \\(self)") - } - } - - /// Full method name, including generic constraints, i.e. `foo(bar: T)` - public let name: String +/// Describes set type +#if canImport(ObjectiveC) +@objcMembers +#endif +public final class SetType: NSObject, SourceryModel, Diffable { + /// Type name used in declaration + public var name: String - /// Method name including arguments names, i.e. `foo(bar:)` - public var selectorName: String + /// Array element type name + public var elementTypeName: TypeName // sourcery: skipEquality, skipDescription - /// Method name without arguments names and parenthesis, i.e. `foo` - public var shortName: String { - return name.range(of: "(").map({ String(name[..<$0.lowerBound]) }) ?? name - } + /// Array element type, if known + public var elementType: Type? - // sourcery: skipEquality, skipDescription - /// Method name without arguments names, parenthesis and generic types, i.e. `foo` (can be used to generate code for method call) - public var callName: String { - return shortName.range(of: "<").map({ String(shortName[..<$0.lowerBound]) }) ?? shortName + /// :nodoc: + public init(name: String, elementTypeName: TypeName, elementType: Type? = nil) { + self.name = name + self.elementTypeName = elementTypeName + self.elementType = elementType } - /// Method parameters - public var parameters: [MethodParameter] - - /// Return value type name used in declaration, including generic constraints, i.e. `where T: Equatable` - public var returnTypeName: TypeName - - // sourcery: skipEquality, skipDescription - /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` - public var actualReturnTypeName: TypeName { - return returnTypeName.actualTypeName ?? returnTypeName + /// Returns array as generic type + public var asGeneric: GenericType { + GenericType(name: "Set", typeParameters: [ + .init(typeName: elementTypeName) + ]) } - // sourcery: skipEquality, skipDescription - /// Actual return value type, if known - public var returnType: Type? - - // sourcery: skipEquality, skipDescription - /// Whether return value type is optional - public var isOptionalReturnType: Bool { - return returnTypeName.isOptional || isFailableInitializer + public var asSource: String { + "[\\(elementTypeName.asSource)]" } - // sourcery: skipEquality, skipDescription - /// Whether return value type is implicitly unwrapped optional - public var isImplicitlyUnwrappedOptionalReturnType: Bool { - return returnTypeName.isImplicitlyUnwrappedOptional + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("name = \\(String(describing: self.name)), ") + string.append("elementTypeName = \\(String(describing: self.elementTypeName)), ") + string.append("asGeneric = \\(String(describing: self.asGeneric)), ") + string.append("asSource = \\(String(describing: self.asSource))") + return string } - // sourcery: skipEquality, skipDescription - /// Return value type name without attributes and optional type information - public var unwrappedReturnTypeName: String { - return returnTypeName.unwrappedTypeName + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? SetType else { + results.append("Incorrect type ") + return results + } + results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) + results.append(contentsOf: DiffableResult(identifier: "elementTypeName").trackDifference(actual: self.elementTypeName, expected: castObject.elementTypeName)) + return results } - /// Whether method is async method - public let isAsync: Bool - - /// Whether method throws - public let `throws`: Bool + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.name) + hasher.combine(self.elementTypeName) + return hasher.finalize() + } - /// Whether method rethrows - public let `rethrows`: Bool + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? SetType else { return false } + if self.name != rhs.name { return false } + if self.elementTypeName != rhs.elementTypeName { return false } + return true + } - /// Method access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` - public let accessLevel: String +// sourcery:inline:SetType.AutoCoding - /// Whether method is a static method - public let isStatic: Bool + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let name: String = aDecoder.decode(forKey: "name") else { + withVaList(["name"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.name = name + guard let elementTypeName: TypeName = aDecoder.decode(forKey: "elementTypeName") else { + withVaList(["elementTypeName"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.elementTypeName = elementTypeName + self.elementType = aDecoder.decode(forKey: "elementType") + } - /// Whether method is a class method - public let isClass: Bool + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.elementTypeName, forKey: "elementTypeName") + aCoder.encode(self.elementType, forKey: "elementType") + } +// sourcery:end +} - // sourcery: skipEquality, skipDescription - /// Whether method is an initializer - public var isInitializer: Bool { - return selectorName.hasPrefix("init(") || selectorName == "init" - } +"""), + .init(name: "Struct.swift", content: +""" +// +// Struct.swift +// Sourcery +// +// Created by Krzysztof Zablocki on 13/09/2016. +// Copyright © 2016 Pixle. All rights reserved. +// - // sourcery: skipEquality, skipDescription - /// Whether method is an deinitializer - public var isDeinitializer: Bool { - return selectorName == "deinit" - } +import Foundation - /// Whether method is a failable initializer - public let isFailableInitializer: Bool +// sourcery: skipDescription +/// Describes Swift struct +#if canImport(ObjectiveC) +@objcMembers +#endif +public final class Struct: Type { - // sourcery: skipEquality, skipDescription - /// Whether method is a convenience initializer - public var isConvenienceInitializer: Bool { - modifiers.contains { $0.name == Attribute.Identifier.convenience.rawValue } - } + /// Returns "struct" + public override var kind: String { return "struct" } - // sourcery: skipEquality, skipDescription - /// Whether method is required - public var isRequired: Bool { - modifiers.contains { $0.name == Attribute.Identifier.required.rawValue } - } - - // sourcery: skipEquality, skipDescription - /// Whether method is final - public var isFinal: Bool { - modifiers.contains { $0.name == Attribute.Identifier.final.rawValue } + /// :nodoc: + public override init(name: String = "", + parent: Type? = nil, + accessLevel: AccessLevel = .internal, + isExtension: Bool = false, + variables: [Variable] = [], + methods: [Method] = [], + subscripts: [Subscript] = [], + inheritedTypes: [String] = [], + containedTypes: [Type] = [], + typealiases: [Typealias] = [], + genericRequirements: [GenericRequirement] = [], + attributes: AttributeList = [:], + modifiers: [SourceryModifier] = [], + annotations: [String: NSObject] = [:], + documentation: [String] = [], + isGeneric: Bool = false, + implements: [String: Type] = [:]) { + super.init( + name: name, + parent: parent, + accessLevel: accessLevel, + isExtension: isExtension, + variables: variables, + methods: methods, + subscripts: subscripts, + inheritedTypes: inheritedTypes, + containedTypes: containedTypes, + typealiases: typealiases, + genericRequirements: genericRequirements, + attributes: attributes, + modifiers: modifiers, + annotations: annotations, + documentation: documentation, + isGeneric: isGeneric, + implements: implements + ) } - // sourcery: skipEquality, skipDescription - /// Whether method is mutating - public var isMutating: Bool { - modifiers.contains { $0.name == Attribute.Identifier.mutating.rawValue } + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = super.description + string += ", " + string += "kind = \\(String(describing: self.kind))" + return string } - // sourcery: skipEquality, skipDescription - /// Whether method is generic - public var isGeneric: Bool { - shortName.hasSuffix(">") + override public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? Struct else { + results.append("Incorrect type ") + return results + } + results.append(contentsOf: super.diffAgainst(castObject)) + return results } - // sourcery: skipEquality, skipDescription - /// Whether method is optional (in an Objective-C protocol) - public var isOptional: Bool { - modifiers.contains { $0.name == Attribute.Identifier.optional.rawValue } + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(super.hash) + return hasher.finalize() } - // sourcery: skipEquality, skipDescription - /// Whether method is nonisolated (this modifier only applies to actor methods) - public var isNonisolated: Bool { - modifiers.contains { $0.name == Attribute.Identifier.nonisolated.rawValue } + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? Struct else { return false } + return super.isEqual(rhs) } - // sourcery: skipEquality, skipDescription - /// Whether method is dynamic - public var isDynamic: Bool { - modifiers.contains { $0.name == Attribute.Identifier.dynamic.rawValue } - } +// sourcery:inline:Struct.AutoCoding - /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 - public let annotations: Annotations + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } - public let documentation: Documentation + /// :nodoc: + override public func encode(with aCoder: NSCoder) { + super.encode(with: aCoder) + } +// sourcery:end +} - /// Reference to type name where the method is defined, - /// nil if defined outside of any `enum`, `struct`, `class` etc - public let definedInTypeName: TypeName? +"""), + .init(name: "TemplateContext.swift", content: +""" +// +// Created by Krzysztof Zablocki on 31/12/2016. +// Copyright (c) 2016 Pixle. All rights reserved. +// - // sourcery: skipEquality, skipDescription - /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` - public var actualDefinedInTypeName: TypeName? { - return definedInTypeName?.actualTypeName ?? definedInTypeName - } +import Foundation - // sourcery: skipEquality, skipDescription - /// Reference to actual type where the object is defined, - /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown - public var definedInType: Type? +/// :nodoc: +// sourcery: skipCoding +#if canImport(ObjectiveC) +@objcMembers +#endif +public final class TemplateContext: NSObject, SourceryModel, NSCoding, Diffable { + // sourcery: skipJSExport + public let parserResult: FileParserResult? + public let functions: [SourceryMethod] + public let types: Types + public let argument: [String: NSObject] - /// Method attributes, i.e. `@discardableResult` - public let attributes: AttributeList + // sourcery: skipDescription + public var type: [String: Type] { + return types.typesByName + } - /// Method modifiers, i.e. `private` - public let modifiers: [SourceryModifier] + public init(parserResult: FileParserResult?, types: Types, functions: [SourceryMethod], arguments: [String: NSObject]) { + self.parserResult = parserResult + self.types = types + self.functions = functions + self.argument = arguments + } - // Underlying parser data, never to be used by anything else - // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: - public var __parserData: Any? + required public init?(coder aDecoder: NSCoder) { + guard let parserResult: FileParserResult = aDecoder.decode(forKey: "parserResult") else { + withVaList(["parserResult"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found. FileParserResults are required for template context that needs persisting.", arguments: arguments) + } + fatalError() + } + guard let argument: [String: NSObject] = aDecoder.decode(forKey: "argument") else { + withVaList(["argument"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + } - /// list of generic requirements - public var genericRequirements: [GenericRequirement] + // if we want to support multiple cycles of encode / decode we need deep copy because composer changes reference types + let fileParserResultCopy: FileParserResult? = nil +// fileParserResultCopy = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(NSKeyedArchiver.archivedData(withRootObject: parserResult)) as? FileParserResult + + let composed = Composer.uniqueTypesAndFunctions(parserResult) + self.types = .init(types: composed.types, typealiases: composed.typealiases) + self.functions = composed.functions + + self.parserResult = fileParserResultCopy + self.argument = argument + } /// :nodoc: - public init(name: String, - selectorName: String? = nil, - parameters: [MethodParameter] = [], - returnTypeName: TypeName = TypeName(name: "Void"), - isAsync: Bool = false, - throws: Bool = false, - rethrows: Bool = false, - accessLevel: AccessLevel = .internal, - isStatic: Bool = false, - isClass: Bool = false, - isFailableInitializer: Bool = false, - attributes: AttributeList = [:], - modifiers: [SourceryModifier] = [], - annotations: [String: NSObject] = [:], - documentation: [String] = [], - definedInTypeName: TypeName? = nil, - genericRequirements: [GenericRequirement] = []) { - self.name = name - self.selectorName = selectorName ?? name - self.parameters = parameters - self.returnTypeName = returnTypeName - self.isAsync = isAsync - self.throws = `throws` - self.rethrows = `rethrows` - self.accessLevel = accessLevel.rawValue - self.isStatic = isStatic - self.isClass = isClass - self.isFailableInitializer = isFailableInitializer - self.attributes = attributes - self.modifiers = modifiers - self.annotations = annotations - self.documentation = documentation - self.definedInTypeName = definedInTypeName - self.genericRequirements = genericRequirements + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.parserResult, forKey: "parserResult") + aCoder.encode(self.argument, forKey: "argument") + } + + public var stencilContext: [String: Any] { + return [ + "types": types, + "functions": functions, + "type": types.typesByName, + "argument": argument + ] } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " - string += "name = \\(String(describing: self.name)), " - string += "selectorName = \\(String(describing: self.selectorName)), " - string += "parameters = \\(String(describing: self.parameters)), " - string += "returnTypeName = \\(String(describing: self.returnTypeName)), " - string += "isAsync = \\(String(describing: self.isAsync)), " - string += "`throws` = \\(String(describing: self.`throws`)), " - string += "`rethrows` = \\(String(describing: self.`rethrows`)), " - string += "accessLevel = \\(String(describing: self.accessLevel)), " - string += "isStatic = \\(String(describing: self.isStatic)), " - string += "isClass = \\(String(describing: self.isClass)), " - string += "isFailableInitializer = \\(String(describing: self.isFailableInitializer)), " - string += "annotations = \\(String(describing: self.annotations)), " - string += "documentation = \\(String(describing: self.documentation)), " - string += "definedInTypeName = \\(String(describing: self.definedInTypeName)), " - string += "attributes = \\(String(describing: self.attributes)), " - string += "modifiers = \\(String(describing: self.modifiers))" - string += "genericRequirements = \\(String(describing: self.genericRequirements))" + string.append("parserResult = \\(String(describing: self.parserResult)), ") + string.append("functions = \\(String(describing: self.functions)), ") + string.append("types = \\(String(describing: self.types)), ") + string.append("argument = \\(String(describing: self.argument)), ") + string.append("stencilContext = \\(String(describing: self.stencilContext))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() - guard let castObject = object as? Method else { - results.append("Incorrect type ") + guard let castObject = object as? TemplateContext else { + results.append("Incorrect type ") return results } - results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "selectorName").trackDifference(actual: self.selectorName, expected: castObject.selectorName)) - results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) - results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) - results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) - results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) - results.append(contentsOf: DiffableResult(identifier: "`rethrows`").trackDifference(actual: self.`rethrows`, expected: castObject.`rethrows`)) - results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) - results.append(contentsOf: DiffableResult(identifier: "isStatic").trackDifference(actual: self.isStatic, expected: castObject.isStatic)) - results.append(contentsOf: DiffableResult(identifier: "isClass").trackDifference(actual: self.isClass, expected: castObject.isClass)) - results.append(contentsOf: DiffableResult(identifier: "isFailableInitializer").trackDifference(actual: self.isFailableInitializer, expected: castObject.isFailableInitializer)) - results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) - results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) - results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) - results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) - results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) - results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) + results.append(contentsOf: DiffableResult(identifier: "parserResult").trackDifference(actual: self.parserResult, expected: castObject.parserResult)) + results.append(contentsOf: DiffableResult(identifier: "functions").trackDifference(actual: self.functions, expected: castObject.functions)) + results.append(contentsOf: DiffableResult(identifier: "types").trackDifference(actual: self.types, expected: castObject.types)) + results.append(contentsOf: DiffableResult(identifier: "argument").trackDifference(actual: self.argument, expected: castObject.argument)) return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() - hasher.combine(self.name) - hasher.combine(self.selectorName) - hasher.combine(self.parameters) - hasher.combine(self.returnTypeName) - hasher.combine(self.isAsync) - hasher.combine(self.`throws`) - hasher.combine(self.`rethrows`) - hasher.combine(self.accessLevel) - hasher.combine(self.isStatic) - hasher.combine(self.isClass) - hasher.combine(self.isFailableInitializer) + hasher.combine(self.parserResult) + hasher.combine(self.functions) + hasher.combine(self.types) + hasher.combine(self.argument) + return hasher.finalize() + } + + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? TemplateContext else { return false } + if self.parserResult != rhs.parserResult { return false } + if self.functions != rhs.functions { return false } + if self.types != rhs.types { return false } + if self.argument != rhs.argument { return false } + return true + } + + // sourcery: skipDescription, skipEquality + public var jsContext: [String: Any] { + return [ + "types": [ + "all": types.all, + "protocols": types.protocols, + "classes": types.classes, + "structs": types.structs, + "enums": types.enums, + "extensions": types.extensions, + "based": types.based, + "inheriting": types.inheriting, + "implementing": types.implementing, + "protocolCompositions": types.protocolCompositions + ] as [String : Any], + "functions": functions, + "type": types.typesByName, + "argument": argument + ] + } + +} + +extension ProcessInfo { + /// :nodoc: + public var context: TemplateContext! { + return NSKeyedUnarchiver.unarchiveObject(withFile: arguments[1]) as? TemplateContext + } +} + +"""), + .init(name: "Typealias.swift", content: +""" +import Foundation + +/// :nodoc: +#if canImport(ObjectiveC) +@objcMembers +#endif +public final class Typealias: NSObject, Typed, SourceryModel, Diffable { + // New typealias name + public let aliasName: String + + // Target name + public let typeName: TypeName + + // sourcery: skipEquality, skipDescription + public var type: Type? + + /// module in which this typealias was declared + public var module: String? + + /// typealias annotations + public var annotations: Annotations = [:] + + /// typealias documentation + public var documentation: Documentation = [] + + // sourcery: skipEquality, skipDescription + public var parent: Type? { + didSet { + parentName = parent?.name + } + } + + /// Type access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` + public let accessLevel: String + + var parentName: String? + + public var name: String { + if let parentName = parent?.name { + return "\\(module != nil ? "\\(module!)." : "")\\(parentName).\\(aliasName)" + } else { + return "\\(module != nil ? "\\(module!)." : "")\\(aliasName)" + } + } + + public init(aliasName: String = "", typeName: TypeName, accessLevel: AccessLevel = .internal, parent: Type? = nil, module: String? = nil, annotations: [String: NSObject] = [:], documentation: [String] = []) { + self.aliasName = aliasName + self.typeName = typeName + self.accessLevel = accessLevel.rawValue + self.parent = parent + self.parentName = parent?.name + self.module = module + self.annotations = annotations + self.documentation = documentation + } + + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("aliasName = \\(String(describing: self.aliasName)), ") + string.append("typeName = \\(String(describing: self.typeName)), ") + string.append("module = \\(String(describing: self.module)), ") + string.append("accessLevel = \\(String(describing: self.accessLevel)), ") + string.append("parentName = \\(String(describing: self.parentName)), ") + string.append("name = \\(String(describing: self.name)), ") + string.append("annotations = \\(String(describing: self.annotations)), ") + string.append("documentation = \\(String(describing: self.documentation)), ") + return string + } + + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? Typealias else { + results.append("Incorrect type ") + return results + } + results.append(contentsOf: DiffableResult(identifier: "aliasName").trackDifference(actual: self.aliasName, expected: castObject.aliasName)) + results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) + results.append(contentsOf: DiffableResult(identifier: "module").trackDifference(actual: self.module, expected: castObject.module)) + results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) + results.append(contentsOf: DiffableResult(identifier: "parentName").trackDifference(actual: self.parentName, expected: castObject.parentName)) + results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) + results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) + return results + } + + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.aliasName) + hasher.combine(self.typeName) + hasher.combine(self.module) + hasher.combine(self.accessLevel) + hasher.combine(self.parentName) hasher.combine(self.annotations) hasher.combine(self.documentation) - hasher.combine(self.definedInTypeName) - hasher.combine(self.attributes) - hasher.combine(self.modifiers) - hasher.combine(self.genericRequirements) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? Method else { return false } - if self.name != rhs.name { return false } - if self.selectorName != rhs.selectorName { return false } - if self.parameters != rhs.parameters { return false } - if self.returnTypeName != rhs.returnTypeName { return false } - if self.isAsync != rhs.isAsync { return false } - if self.`throws` != rhs.`throws` { return false } - if self.`rethrows` != rhs.`rethrows` { return false } + guard let rhs = object as? Typealias else { return false } + if self.aliasName != rhs.aliasName { return false } + if self.typeName != rhs.typeName { return false } + if self.module != rhs.module { return false } if self.accessLevel != rhs.accessLevel { return false } - if self.isStatic != rhs.isStatic { return false } - if self.isClass != rhs.isClass { return false } - if self.isFailableInitializer != rhs.isFailableInitializer { return false } - if self.annotations != rhs.annotations { return false } + if self.parentName != rhs.parentName { return false } if self.documentation != rhs.documentation { return false } - if self.definedInTypeName != rhs.definedInTypeName { return false } - if self.attributes != rhs.attributes { return false } - if self.modifiers != rhs.modifiers { return false } - if self.genericRequirements != rhs.genericRequirements { return false } + if self.annotations != rhs.annotations { return false } return true } - -// sourcery:inline:Method.AutoCoding + +// sourcery:inline:Typealias.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { - withVaList(["name"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.name = name - guard let selectorName: String = aDecoder.decode(forKey: "selectorName") else { - withVaList(["selectorName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.selectorName = selectorName - guard let parameters: [MethodParameter] = aDecoder.decode(forKey: "parameters") else { - withVaList(["parameters"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.parameters = parameters - guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { - withVaList(["returnTypeName"]) { arguments in + guard let aliasName: String = aDecoder.decode(forKey: "aliasName") else { + withVaList(["aliasName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.returnTypeName = returnTypeName - self.returnType = aDecoder.decode(forKey: "returnType") - self.isAsync = aDecoder.decode(forKey: "isAsync") - self.`throws` = aDecoder.decode(forKey: "`throws`") - self.`rethrows` = aDecoder.decode(forKey: "`rethrows`") - guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { - withVaList(["accessLevel"]) { arguments in + }; self.aliasName = aliasName + guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { + withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.accessLevel = accessLevel - self.isStatic = aDecoder.decode(forKey: "isStatic") - self.isClass = aDecoder.decode(forKey: "isClass") - self.isFailableInitializer = aDecoder.decode(forKey: "isFailableInitializer") - guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { + }; self.typeName = typeName + self.type = aDecoder.decode(forKey: "type") + self.module = aDecoder.decode(forKey: "module") + guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations - guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { + guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation - self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") - self.definedInType = aDecoder.decode(forKey: "definedInType") - guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { - withVaList(["attributes"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.attributes = attributes - guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { - withVaList(["modifiers"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.modifiers = modifiers - guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { - withVaList(["genericRequirements"]) { arguments in + self.parent = aDecoder.decode(forKey: "parent") + guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { + withVaList(["accessLevel"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.genericRequirements = genericRequirements + }; self.accessLevel = accessLevel + self.parentName = aDecoder.decode(forKey: "parentName") } /// :nodoc: public func encode(with aCoder: NSCoder) { - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.selectorName, forKey: "selectorName") - aCoder.encode(self.parameters, forKey: "parameters") - aCoder.encode(self.returnTypeName, forKey: "returnTypeName") - aCoder.encode(self.returnType, forKey: "returnType") - aCoder.encode(self.isAsync, forKey: "isAsync") - aCoder.encode(self.`throws`, forKey: "`throws`") - aCoder.encode(self.`rethrows`, forKey: "`rethrows`") - aCoder.encode(self.accessLevel, forKey: "accessLevel") - aCoder.encode(self.isStatic, forKey: "isStatic") - aCoder.encode(self.isClass, forKey: "isClass") - aCoder.encode(self.isFailableInitializer, forKey: "isFailableInitializer") + aCoder.encode(self.aliasName, forKey: "aliasName") + aCoder.encode(self.typeName, forKey: "typeName") + aCoder.encode(self.type, forKey: "type") + aCoder.encode(self.module, forKey: "module") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") - aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") - aCoder.encode(self.definedInType, forKey: "definedInType") - aCoder.encode(self.attributes, forKey: "attributes") - aCoder.encode(self.modifiers, forKey: "modifiers") - aCoder.encode(self.genericRequirements, forKey: "genericRequirements") + aCoder.encode(self.parent, forKey: "parent") + aCoder.encode(self.accessLevel, forKey: "accessLevel") + aCoder.encode(self.parentName, forKey: "parentName") } // sourcery:end } """), - .init(name: "Modifier.swift", content: + .init(name: "Typed.swift", content: """ import Foundation -public typealias SourceryModifier = Modifier -/// modifier can be thing like `private`, `class`, `nonmutating` -/// if a declaration has modifier like `private(set)` it's name will be `private` and detail will be `set` -public class Modifier: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJSExport, Diffable { +/// Descibes typed declaration, i.e. variable, method parameter, tuple element, enum case associated value +public protocol Typed { - /// The declaration modifier name. - public let name: String + // sourcery: skipEquality, skipDescription + /// Type, if known + var type: Type? { get } - /// The modifier detail, if any. - public let detail: String? + // sourcery: skipEquality, skipDescription + /// Type name + var typeName: TypeName { get } - public init(name: String, detail: String? = nil) { - self.name = name - self.detail = detail - } + // sourcery: skipEquality, skipDescription + /// Whether type is optional + var isOptional: Bool { get } - public var asSource: String { - if let detail = detail { - return "\\(name)(\\(detail))" - } else { - return name + // sourcery: skipEquality, skipDescription + /// Whether type is implicitly unwrapped optional + var isImplicitlyUnwrappedOptional: Bool { get } + + // sourcery: skipEquality, skipDescription + /// Type name without attributes and optional type information + var unwrappedTypeName: String { get } +} + +"""), + .init(name: "AssociatedType_Linux.swift", content: +""" +#if !canImport(ObjectiveC) +import Foundation + +/// Describes Swift AssociatedType +public final class AssociatedType: NSObject, SourceryModel, SourceryDynamicMemberLookup { + public subscript(dynamicMember member: String) -> Any? { + switch member { + case "name": + return name + case "typeName": + return typeName + case "type": + return type + default: + fatalError("unable to lookup: \\(member) in \\(self)") } } + /// Associated type name + public let name: String + + /// Associated type type constraint name, if specified + public let typeName: TypeName? + + // sourcery: skipEquality, skipDescription + /// Associated type constrained type, if known, i.e. if the type is declared in the scanned sources. + public var type: Type? + + /// :nodoc: + public init(name: String, typeName: TypeName? = nil, type: Type? = nil) { + self.name = name + self.typeName = typeName + self.type = type + } + + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("name = \\(String(describing: self.name)), ") + string.append("typeName = \\(String(describing: self.typeName))") + return string + } + public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() - guard let castObject = object as? Modifier else { - results.append("Incorrect type ") + guard let castObject = object as? AssociatedType else { + results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "detail").trackDifference(actual: self.detail, expected: castObject.detail)) + results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) - hasher.combine(self.detail) + hasher.combine(self.typeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? Modifier else { return false } + guard let rhs = object as? AssociatedType else { return false } if self.name != rhs.name { return false } - if self.detail != rhs.detail { return false } + if self.typeName != rhs.typeName { return false } return true } - // sourcery:inline:Modifier.AutoCoding +// sourcery:inline:AssociatedType.AutoCoding - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name - self.detail = aDecoder.decode(forKey: "detail") - } + self.typeName = aDecoder.decode(forKey: "typeName") + self.type = aDecoder.decode(forKey: "type") + } - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.detail, forKey: "detail") - } - // sourcery:end + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.typeName, forKey: "typeName") + aCoder.encode(self.type, forKey: "type") + } +// sourcery:end } - +#endif """), - .init(name: "ParserResultsComposed.swift", content: + .init(name: "AssociatedValue_Linux.swift", content: """ // -// Created by Krzysztof Zablocki on 31/12/2016. +// Created by Krzysztof Zablocki on 13/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // - +#if !canImport(ObjectiveC) import Foundation -internal struct ParserResultsComposed { - private(set) var typeMap = [String: Type]() - private(set) var modules = [String: [String: Type]]() - private(set) var types = [Type]() +/// Defines enum case associated value +public final class AssociatedValue: NSObject, SourceryModel, AutoDescription, Typed, Annotated, Diffable, SourceryDynamicMemberLookup { + public subscript(dynamicMember member: String) -> Any? { + switch member { + case "externalName": + return externalName + case "localName": + return localName + case "typeName": + return typeName + case "type": + return type + case "defaultValue": + return defaultValue + case "annotations": + return annotations + default: + fatalError("unable to lookup: \\(member) in \\(self)") + } + } - let parsedTypes: [Type] - let functions: [SourceryMethod] - let resolvedTypealiases: [String: Typealias] - let unresolvedTypealiases: [String: Typealias] + /// Associated value local name. + /// This is a name to be used to construct enum case value + public let localName: String? - init(parserResult: FileParserResult) { - // TODO: This logic should really be more complicated - // For any resolution we need to be looking at accessLevel and module boundaries - // e.g. there might be a typealias `private typealias Something = MyType` in one module and same name in another with public modifier, one could be accessed and the other could not - self.functions = parserResult.functions - let aliases = Self.typealiases(parserResult) - resolvedTypealiases = aliases.resolved - unresolvedTypealiases = aliases.unresolved - parsedTypes = parserResult.types + /// Associated value external name. + /// This is a name to be used to access value in value-bindig + public let externalName: String? - // set definedInType for all methods and variables - parsedTypes - .forEach { type in - type.variables.forEach { $0.definedInType = type } - type.methods.forEach { $0.definedInType = type } - type.subscripts.forEach { $0.definedInType = type } - } + /// Associated value type name + public let typeName: TypeName - // map all known types to their names - parsedTypes - .filter { !$0.isExtension } - .forEach { - typeMap[$0.globalName] = $0 - if let module = $0.module { - var typesByModules = modules[module, default: [:]] - typesByModules[$0.name] = $0 - modules[module] = typesByModules - } - } + // sourcery: skipEquality, skipDescription + /// Associated value type, if known + public var type: Type? - /// Resolve typealiases - let typealiases = Array(unresolvedTypealiases.values) - typealiases.forEach { alias in - alias.type = resolveType(typeName: alias.typeName, containingType: alias.parent) - } + /// Associated value default value + public let defaultValue: String? - types = unifyTypes() + /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 + public var annotations: Annotations = [:] + + /// :nodoc: + public init(localName: String?, externalName: String?, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:]) { + self.localName = localName + self.externalName = externalName + self.typeName = typeName + self.type = type + self.defaultValue = defaultValue + self.annotations = annotations } - private func resolveExtensionOfNestedType(_ type: Type) { - var components = type.localName.components(separatedBy: ".") - let rootName = type.module ?? components.removeFirst() // Module/parent name - if let moduleTypes = modules[rootName], let baseType = moduleTypes[components.joined(separator: ".")] ?? moduleTypes[type.localName] { - type.localName = baseType.localName - type.module = baseType.module - type.parent = baseType.parent - } else { - for _import in type.imports { - let parentKey = "\\(rootName).\\(components.joined(separator: "."))" - let parentKeyFull = "\\(_import.moduleName).\\(parentKey)" - if let moduleTypes = modules[_import.moduleName], let baseType = moduleTypes[parentKey] ?? moduleTypes[parentKeyFull] { - type.localName = baseType.localName - type.module = baseType.module - type.parent = baseType.parent - return - } - } - } + convenience init(name: String? = nil, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:]) { + self.init(localName: name, externalName: name, typeName: typeName, type: type, defaultValue: defaultValue, annotations: annotations) } - private mutating func unifyTypes() -> [Type] { - /// Resolve actual names of extensions, as they could have been done on typealias and note updated child names in uniques if needed - parsedTypes - .filter { $0.isExtension } - .forEach { - let oldName = $0.globalName + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("localName = \\(String(describing: self.localName)), ") + string.append("externalName = \\(String(describing: self.externalName)), ") + string.append("typeName = \\(String(describing: self.typeName)), ") + string.append("defaultValue = \\(String(describing: self.defaultValue)), ") + string.append("annotations = \\(String(describing: self.annotations))") + return string + } - if $0.parent == nil, $0.localName.contains(".") { - resolveExtensionOfNestedType($0) - } + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? AssociatedValue else { + results.append("Incorrect type ") + return results + } + results.append(contentsOf: DiffableResult(identifier: "localName").trackDifference(actual: self.localName, expected: castObject.localName)) + results.append(contentsOf: DiffableResult(identifier: "externalName").trackDifference(actual: self.externalName, expected: castObject.externalName)) + results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) + results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) + results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) + return results + } - if let resolved = resolveGlobalName(for: oldName, containingType: $0.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases)?.name { - $0.localName = resolved.replacingOccurrences(of: "\\($0.module != nil ? "\\($0.module!)." : "")", with: "") - } else { - return - } + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.localName) + hasher.combine(self.externalName) + hasher.combine(self.typeName) + hasher.combine(self.defaultValue) + hasher.combine(self.annotations) + return hasher.finalize() + } - // nothing left to do - guard oldName != $0.globalName else { - return - } + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? AssociatedValue else { return false } + if self.localName != rhs.localName { return false } + if self.externalName != rhs.externalName { return false } + if self.typeName != rhs.typeName { return false } + if self.defaultValue != rhs.defaultValue { return false } + if self.annotations != rhs.annotations { return false } + return true + } - // if it had contained types, they might have been fully defined and so their name has to be noted in uniques - func rewriteChildren(of type: Type) { - // child is never an extension so no need to check - for child in type.containedTypes { - typeMap[child.globalName] = child - rewriteChildren(of: child) - } - } - rewriteChildren(of: $0) - } +// sourcery:inline:AssociatedValue.AutoCoding - // extend all types with their extensions - parsedTypes.forEach { type in - type.inheritedTypes = type.inheritedTypes.map { inheritedName in - resolveGlobalName(for: inheritedName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases)?.name ?? inheritedName - } - - let uniqueType = typeMap[type.globalName] ?? // this check will only fail on an extension? - typeFromComposedName(type.name, modules: modules) ?? // this can happen for an extension on unknown type, this case should probably be handled by the inferTypeNameFromModules - (inferTypeNameFromModules(from: type.localName, containedInType: type.parent, uniqueTypes: typeMap, modules: modules).flatMap { typeMap[$0] }) - - guard let current = uniqueType else { - assert(type.isExtension, "Type \\(type.globalName) should be extension") - - // for unknown types we still store their extensions but mark them as unknown - type.isUnknownExtension = true - if let existingType = typeMap[type.globalName] { - existingType.extend(type) - typeMap[type.globalName] = existingType - } else { - typeMap[type.globalName] = type + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + self.localName = aDecoder.decode(forKey: "localName") + self.externalName = aDecoder.decode(forKey: "externalName") + guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { + withVaList(["typeName"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } - - let inheritanceClause = type.inheritedTypes.isEmpty ? "" : - ": \\(type.inheritedTypes.joined(separator: ", "))" - - Log.astWarning("Found \\"extension \\(type.name)\\(inheritanceClause)\\" of type for which there is no original type declaration information.") - return - } - - if current == type { return } - - current.extend(type) - typeMap[current.globalName] = current + fatalError() + }; self.typeName = typeName + self.type = aDecoder.decode(forKey: "type") + self.defaultValue = aDecoder.decode(forKey: "defaultValue") + guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { + withVaList(["annotations"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.annotations = annotations } - let values = typeMap.values - var processed = Set(minimumCapacity: values.count) - return typeMap.values.filter({ - let name = $0.globalName - let wasProcessed = processed.contains(name) - processed.insert(name) - return !wasProcessed - }) - } - - /// returns typealiases map to their full names, with `resolved` removing intermediate - /// typealises and `unresolved` including typealiases that reference other typealiases. - private static func typealiases(_ parserResult: FileParserResult) -> (resolved: [String: Typealias], unresolved: [String: Typealias]) { - var typealiasesByNames = [String: Typealias]() - parserResult.typealiases.forEach { typealiasesByNames[$0.name] = $0 } - parserResult.types.forEach { type in - type.typealiases.forEach({ (_, alias) in - // TODO: should I deal with the fact that alias.name depends on type name but typenames might be updated later on - // maybe just handle non extension case here and extension aliases after resolving them? - typealiasesByNames[alias.name] = alias - }) + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.localName, forKey: "localName") + aCoder.encode(self.externalName, forKey: "externalName") + aCoder.encode(self.typeName, forKey: "typeName") + aCoder.encode(self.type, forKey: "type") + aCoder.encode(self.defaultValue, forKey: "defaultValue") + aCoder.encode(self.annotations, forKey: "annotations") } +// sourcery:end - let unresolved = typealiasesByNames +} +#endif - // ! if a typealias leads to another typealias, follow through and replace with final type - typealiasesByNames.forEach { _, alias in - var aliasNamesToReplace = [alias.name] - var finalAlias = alias - while let targetAlias = typealiasesByNames[finalAlias.typeName.name] { - aliasNamesToReplace.append(targetAlias.name) - finalAlias = targetAlias - } +"""), + .init(name: "ClosureParameter_Linux.swift", content: +""" +#if !canImport(ObjectiveC) +import Foundation - // ! replace all keys - aliasNamesToReplace.forEach { typealiasesByNames[$0] = finalAlias } +// sourcery: skipDiffing +public final class ClosureParameter: NSObject, SourceryModel, Typed, Annotated, SourceryDynamicMemberLookup { + public subscript(dynamicMember member: String) -> Any? { + switch member { + case "argumentLabel": + return argumentLabel + case "name": + return name + case "typeName": + return typeName + case "inout": + return `inout` + case "type": + return type + case "isVariadic": + return isVariadic + case "defaultValue": + return defaultValue + default: + fatalError("unable to lookup: \\(member) in \\(self)") } - - return (resolved: typealiasesByNames, unresolved: unresolved) } + /// Parameter external name + public var argumentLabel: String? - /// Resolves type identifier for name - func resolveGlobalName(for type: String, - containingType: Type? = nil, - unique: [String: Type]? = nil, - modules: [String: [String: Type]], - typealiases: [String: Typealias]) -> (name: String, typealias: Typealias?)? { - // if the type exists for this name and isn't an extension just return it's name - // if it's extension we need to check if there aren't other options TODO: verify - if let realType = unique?[type], realType.isExtension == false { - return (name: realType.globalName, typealias: nil) - } + /// Parameter internal name + public let name: String? - if let alias = typealiases[type] { - return (name: alias.type?.globalName ?? alias.typeName.name, typealias: alias) - } + /// Parameter type name + public let typeName: TypeName - if let containingType = containingType { - if type == "Self" { - return (name: containingType.globalName, typealias: nil) - } + /// Parameter flag whether it's inout or not + public let `inout`: Bool - var currentContainer: Type? = containingType - while currentContainer != nil, let parentName = currentContainer?.globalName { - /// TODO: no parent for sure? - /// manually walk the containment tree - if let name = resolveGlobalName(for: "\\(parentName).\\(type)", containingType: nil, unique: unique, modules: modules, typealiases: typealiases) { - return name - } + // sourcery: skipEquality, skipDescription + /// Parameter type, if known + public var type: Type? - currentContainer = currentContainer?.parent - } + /// Parameter if the argument has a variadic type or not + public let isVariadic: Bool -// if let name = resolveGlobalName(for: "\\(containingType.globalName).\\(type)", containingType: containingType.parent, unique: unique, modules: modules, typealiases: typealiases) { -// return name -// } + /// Parameter type attributes, i.e. `@escaping` + public var typeAttributes: AttributeList { + return typeName.attributes + } -// last check it's via module -// if let module = containingType.module, let name = resolveGlobalName(for: "\\(module).\\(type)", containingType: nil, unique: unique, modules: modules, typealiases: typealiases) { -// return name -// } - } + /// Method parameter default value expression + public var defaultValue: String? - // TODO: is this needed? - if let inferred = inferTypeNameFromModules(from: type, containedInType: containingType, uniqueTypes: unique ?? [:], modules: modules) { - return (name: inferred, typealias: nil) - } + /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 + public var annotations: Annotations = [:] - return typeFromComposedName(type, modules: modules).map { (name: $0.globalName, typealias: nil) } + /// :nodoc: + public init(argumentLabel: String? = nil, name: String? = nil, typeName: TypeName, type: Type? = nil, + defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false, + isVariadic: Bool = false) { + self.typeName = typeName + self.argumentLabel = argumentLabel + self.name = name + self.type = type + self.defaultValue = defaultValue + self.annotations = annotations + self.`inout` = isInout + self.isVariadic = isVariadic } - private func inferTypeNameFromModules(from typeIdentifier: String, containedInType: Type?, uniqueTypes: [String: Type], modules: [String: [String: Type]]) -> String? { - func fullName(for module: String) -> String { - "\\(module).\\(typeIdentifier)" + public var asSource: String { + let typeInfo = "\\(`inout` ? "inout " : "")\\(typeName.asSource)\\(isVariadic ? "..." : "")" + if argumentLabel?.nilIfNotValidParameterName == nil, name?.nilIfNotValidParameterName == nil { + return typeInfo } - func type(for module: String) -> Type? { - return modules[module]?[typeIdentifier] + let typeSuffix = ": \\(typeInfo)" + guard argumentLabel != name else { + return name ?? "" + typeSuffix } - func ambiguousErrorMessage(from types: [Type]) -> String? { - Log.astWarning("Ambiguous type \\(typeIdentifier), found \\(types.map { $0.globalName }.joined(separator: ", ")). Specify module name at declaration site to disambiguate.") - return nil - } + let labels = [argumentLabel ?? "_", name?.nilIfEmpty] + .compactMap { $0 } + .joined(separator: " ") - let explicitModulesAtDeclarationSite: [String] = [ - containedInType?.module.map { [$0] } ?? [], // main module for this typename - containedInType?.imports.map { $0.moduleName } ?? [] // imported modules - ] - .flatMap { $0 } + return (labels.nilIfEmpty ?? "_") + typeSuffix + } - let remainingModules = Set(modules.keys).subtracting(explicitModulesAtDeclarationSite) + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.argumentLabel) + hasher.combine(self.name) + hasher.combine(self.typeName) + hasher.combine(self.`inout`) + hasher.combine(self.isVariadic) + hasher.combine(self.defaultValue) + hasher.combine(self.annotations) + return hasher.finalize() + } - /// We need to check whether we can find type in one of the modules but we need to be careful to avoid amibiguity - /// First checking explicit modules available at declaration site (so source module + all imported ones) - /// If there is no ambigiuity there we can assume that module will be resolved by the compiler - /// If that's not the case we look after remaining modules in the application and if the typename has no ambigiuity we use that - /// But if there is more than 1 typename duplication across modules we have no way to resolve what is the compiler going to use so we fail - let moduleSetsToCheck: [[String]] = [ - explicitModulesAtDeclarationSite, - Array(remainingModules) - ] + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("argumentLabel = \\(String(describing: self.argumentLabel)), ") + string.append("name = \\(String(describing: self.name)), ") + string.append("typeName = \\(String(describing: self.typeName)), ") + string.append("`inout` = \\(String(describing: self.`inout`)), ") + string.append("typeAttributes = \\(String(describing: self.typeAttributes)), ") + string.append("defaultValue = \\(String(describing: self.defaultValue)), ") + string.append("annotations = \\(String(describing: self.annotations)), ") + string.append("asSource = \\(String(describing: self.asSource))") + return string + } - for modules in moduleSetsToCheck { - let possibleTypes = modules - .compactMap { type(for: $0) } + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? ClosureParameter else { return false } + if self.argumentLabel != rhs.argumentLabel { return false } + if self.name != rhs.name { return false } + if self.typeName != rhs.typeName { return false } + if self.`inout` != rhs.`inout` { return false } + if self.isVariadic != rhs.isVariadic { return false } + if self.defaultValue != rhs.defaultValue { return false } + if self.annotations != rhs.annotations { return false } + return true + } - if possibleTypes.count > 1 { - return ambiguousErrorMessage(from: possibleTypes) - } + // sourcery:inline:ClosureParameter.AutoCoding - if let type = possibleTypes.first { - return type.globalName + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + self.argumentLabel = aDecoder.decode(forKey: "argumentLabel") + self.name = aDecoder.decode(forKey: "name") + guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { + withVaList(["typeName"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.typeName = typeName + self.`inout` = aDecoder.decode(forKey: "`inout`") + self.type = aDecoder.decode(forKey: "type") + self.isVariadic = aDecoder.decode(forKey: "isVariadic") + self.defaultValue = aDecoder.decode(forKey: "defaultValue") + guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { + withVaList(["annotations"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.annotations = annotations } - } - // as last result for unknown types / extensions - // try extracting type from unique array - if let module = containedInType?.module { - return uniqueTypes[fullName(for: module)]?.globalName - } - return nil - } + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.argumentLabel, forKey: "argumentLabel") + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.typeName, forKey: "typeName") + aCoder.encode(self.`inout`, forKey: "`inout`") + aCoder.encode(self.type, forKey: "type") + aCoder.encode(self.isVariadic, forKey: "isVariadic") + aCoder.encode(self.defaultValue, forKey: "defaultValue") + aCoder.encode(self.annotations, forKey: "annotations") + } - func typeFromComposedName(_ name: String, modules: [String: [String: Type]]) -> Type? { - guard name.contains(".") else { return nil } - let nameComponents = name.components(separatedBy: ".") - let moduleName = nameComponents[0] - let typeName = nameComponents.suffix(from: 1).joined(separator: ".") - return modules[moduleName]?[typeName] - } + // sourcery:end +} - func resolveType(typeName: TypeName, containingType: Type?, method: Method? = nil) -> Type? { - let resolveTypeWithName = { (typeName: TypeName) -> Type? in - return self.resolveType(typeName: typeName, containingType: containingType) - } +extension Array where Element == ClosureParameter { + public var asSource: String { + "(\\(map { $0.asSource }.joined(separator: ", ")))" + } +} +#endif - let unique = typeMap +"""), + .init(name: "Closure_Linux.swift", content: +""" +#if !canImport(ObjectiveC) +import Foundation - if let name = typeName.actualTypeName { - let resolvedIdentifier = name.generic?.name ?? name.unwrappedTypeName - return unique[resolvedIdentifier] +/// Describes closure type +public final class ClosureType: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { + public subscript(dynamicMember member: String) -> Any? { + switch member { + case "name": + return name + case "parameters": + return parameters + case "returnTypeName": + return returnTypeName + case "actualReturnTypeName": + return actualReturnTypeName + case "returnType": + return returnType + case "isOptionalReturnType": + return isOptionalReturnType + case "isImplicitlyUnwrappedOptionalReturnType": + return isImplicitlyUnwrappedOptionalReturnType + case "unwrappedReturnTypeName": + return unwrappedReturnTypeName + case "isAsync": + return isAsync + case "asyncKeyword": + return asyncKeyword + case "throws": + return `throws` + case "throwsOrRethrowsKeyword": + return throwsOrRethrowsKeyword + default: + fatalError("unable to lookup: \\(member) in \\(self)") } + } + /// Type name used in declaration with stripped whitespaces and new lines + public let name: String - let retrievedName = actualTypeName(for: typeName, containingType: containingType) - let lookupName = retrievedName ?? typeName - - if let tuple = lookupName.tuple { - var needsUpdate = false + /// List of closure parameters + public let parameters: [ClosureParameter] - tuple.elements.forEach { tupleElement in - tupleElement.type = resolveTypeWithName(tupleElement.typeName) - if tupleElement.typeName.actualTypeName != nil { - needsUpdate = true - } - } + /// Return value type name + public let returnTypeName: TypeName - if needsUpdate || retrievedName != nil { - let tupleCopy = TupleType(name: tuple.name, elements: tuple.elements) - tupleCopy.elements.forEach { - $0.typeName = $0.actualTypeName ?? $0.typeName - $0.typeName.actualTypeName = nil - } - tupleCopy.name = tupleCopy.elements.asTypeName + /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` + public var actualReturnTypeName: TypeName { + return returnTypeName.actualTypeName ?? returnTypeName + } - typeName.tuple = tupleCopy // TODO: really don't like this old behaviour - typeName.actualTypeName = TypeName(name: tupleCopy.name, - isOptional: typeName.isOptional, - isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, - tuple: tupleCopy, - array: lookupName.array, - dictionary: lookupName.dictionary, - closure: lookupName.closure, - set: lookupName.set, - generic: lookupName.generic - ) - } - return nil - } else - if let array = lookupName.array { - array.elementType = resolveTypeWithName(array.elementTypeName) + // sourcery: skipEquality, skipDescription + /// Actual return value type, if known + public var returnType: Type? - if array.elementTypeName.actualTypeName != nil || retrievedName != nil { - let array = ArrayType(name: array.name, elementTypeName: array.elementTypeName, elementType: array.elementType) - array.elementTypeName = array.elementTypeName.actualTypeName ?? array.elementTypeName - array.elementTypeName.actualTypeName = nil - array.name = array.asSource - typeName.array = array // TODO: really don't like this old behaviour - typeName.generic = array.asGeneric // TODO: really don't like this old behaviour + // sourcery: skipEquality, skipDescription + /// Whether return value type is optional + public var isOptionalReturnType: Bool { + return returnTypeName.isOptional + } - typeName.actualTypeName = TypeName(name: array.name, - isOptional: typeName.isOptional, - isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, - tuple: lookupName.tuple, - array: array, - dictionary: lookupName.dictionary, - closure: lookupName.closure, - set: lookupName.set, - generic: typeName.generic - ) - } - } else - if let dictionary = lookupName.dictionary { - dictionary.keyType = resolveTypeWithName(dictionary.keyTypeName) - dictionary.valueType = resolveTypeWithName(dictionary.valueTypeName) + // sourcery: skipEquality, skipDescription + /// Whether return value type is implicitly unwrapped optional + public var isImplicitlyUnwrappedOptionalReturnType: Bool { + return returnTypeName.isImplicitlyUnwrappedOptional + } - if dictionary.keyTypeName.actualTypeName != nil || dictionary.valueTypeName.actualTypeName != nil || retrievedName != nil { - let dictionary = DictionaryType(name: dictionary.name, valueTypeName: dictionary.valueTypeName, valueType: dictionary.valueType, keyTypeName: dictionary.keyTypeName, keyType: dictionary.keyType) - dictionary.keyTypeName = dictionary.keyTypeName.actualTypeName ?? dictionary.keyTypeName - dictionary.keyTypeName.actualTypeName = nil // TODO: really don't like this old behaviour - dictionary.valueTypeName = dictionary.valueTypeName.actualTypeName ?? dictionary.valueTypeName - dictionary.valueTypeName.actualTypeName = nil // TODO: really don't like this old behaviour + // sourcery: skipEquality, skipDescription + /// Return value type name without attributes and optional type information + public var unwrappedReturnTypeName: String { + return returnTypeName.unwrappedTypeName + } + + /// Whether method is async method + public let isAsync: Bool - dictionary.name = dictionary.asSource + /// async keyword + public let asyncKeyword: String? - typeName.dictionary = dictionary // TODO: really don't like this old behaviour - typeName.generic = dictionary.asGeneric // TODO: really don't like this old behaviour + /// Whether closure throws + public let `throws`: Bool - typeName.actualTypeName = TypeName(name: dictionary.asSource, - isOptional: typeName.isOptional, - isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, - tuple: lookupName.tuple, - array: lookupName.array, - dictionary: dictionary, - closure: lookupName.closure, - set: lookupName.set, - generic: dictionary.asGeneric - ) - } - } else - if let closure = lookupName.closure { - var needsUpdate = false + /// throws or rethrows keyword + public let throwsOrRethrowsKeyword: String? - closure.returnType = resolveTypeWithName(closure.returnTypeName) - closure.parameters.forEach { parameter in - parameter.type = resolveTypeWithName(parameter.typeName) - if parameter.typeName.actualTypeName != nil { - needsUpdate = true - } - } + /// :nodoc: + public init(name: String, parameters: [ClosureParameter], returnTypeName: TypeName, returnType: Type? = nil, asyncKeyword: String? = nil, throwsOrRethrowsKeyword: String? = nil) { + self.name = name + self.parameters = parameters + self.returnTypeName = returnTypeName + self.returnType = returnType + self.asyncKeyword = asyncKeyword + self.isAsync = asyncKeyword != nil + self.throwsOrRethrowsKeyword = throwsOrRethrowsKeyword + self.`throws` = throwsOrRethrowsKeyword != nil + } - if closure.returnTypeName.actualTypeName != nil || needsUpdate || retrievedName != nil { - typeName.closure = closure // TODO: really don't like this old behaviour + public var asSource: String { + "\\(parameters.asSource)\\(asyncKeyword != nil ? " \\(asyncKeyword!)" : "")\\(throwsOrRethrowsKeyword != nil ? " \\(throwsOrRethrowsKeyword!)" : "") -> \\(returnTypeName.asSource)" + } - typeName.actualTypeName = TypeName(name: closure.asSource, - isOptional: typeName.isOptional, - isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, - tuple: lookupName.tuple, - array: lookupName.array, - dictionary: lookupName.dictionary, - closure: closure, - set: lookupName.set, - generic: lookupName.generic - ) - } + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("name = \\(String(describing: self.name)), ") + string.append("parameters = \\(String(describing: self.parameters)), ") + string.append("returnTypeName = \\(String(describing: self.returnTypeName)), ") + string.append("actualReturnTypeName = \\(String(describing: self.actualReturnTypeName)), ") + string.append("isAsync = \\(String(describing: self.isAsync)), ") + string.append("asyncKeyword = \\(String(describing: self.asyncKeyword)), ") + string.append("`throws` = \\(String(describing: self.`throws`)), ") + string.append("throwsOrRethrowsKeyword = \\(String(describing: self.throwsOrRethrowsKeyword)), ") + string.append("asSource = \\(String(describing: self.asSource))") + return string + } - return nil - } else - if let generic = lookupName.generic { - var needsUpdate = false + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? ClosureType else { + results.append("Incorrect type ") + return results + } + results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) + results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) + results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) + results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) + results.append(contentsOf: DiffableResult(identifier: "asyncKeyword").trackDifference(actual: self.asyncKeyword, expected: castObject.asyncKeyword)) + results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) + results.append(contentsOf: DiffableResult(identifier: "throwsOrRethrowsKeyword").trackDifference(actual: self.throwsOrRethrowsKeyword, expected: castObject.throwsOrRethrowsKeyword)) + return results + } - generic.typeParameters.forEach { parameter in - parameter.type = resolveTypeWithName(parameter.typeName) - if parameter.typeName.actualTypeName != nil { - needsUpdate = true - } - } + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.name) + hasher.combine(self.parameters) + hasher.combine(self.returnTypeName) + hasher.combine(self.isAsync) + hasher.combine(self.asyncKeyword) + hasher.combine(self.`throws`) + hasher.combine(self.throwsOrRethrowsKeyword) + return hasher.finalize() + } - if needsUpdate || retrievedName != nil { - let generic = GenericType(name: generic.name, typeParameters: generic.typeParameters) - generic.typeParameters.forEach { - $0.typeName = $0.typeName.actualTypeName ?? $0.typeName - $0.typeName.actualTypeName = nil // TODO: really don't like this old behaviour - } - typeName.generic = generic // TODO: really don't like this old behaviour - typeName.array = lookupName.array // TODO: really don't like this old behaviour - typeName.dictionary = lookupName.dictionary // TODO: really don't like this old behaviour - - let params = generic.typeParameters.map { $0.typeName.asSource }.joined(separator: ", ") - - typeName.actualTypeName = TypeName(name: "\\(generic.name)<\\(params)>", - isOptional: typeName.isOptional, - isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, - tuple: lookupName.tuple, - array: lookupName.array, // TODO: asArray - dictionary: lookupName.dictionary, // TODO: asDictionary - closure: lookupName.closure, - set: lookupName.set, - generic: generic - ) - } - } - - if let aliasedName = (typeName.actualTypeName ?? retrievedName), aliasedName.unwrappedTypeName != typeName.unwrappedTypeName { - typeName.actualTypeName = aliasedName - } + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? ClosureType else { return false } + if self.name != rhs.name { return false } + if self.parameters != rhs.parameters { return false } + if self.returnTypeName != rhs.returnTypeName { return false } + if self.isAsync != rhs.isAsync { return false } + if self.asyncKeyword != rhs.asyncKeyword { return false } + if self.`throws` != rhs.`throws` { return false } + if self.throwsOrRethrowsKeyword != rhs.throwsOrRethrowsKeyword { return false } + return true + } - let hasGenericRequirements = containingType?.genericRequirements.isEmpty == false - || (method != nil && method?.genericRequirements.isEmpty == false) +// sourcery:inline:ClosureType.AutoCoding - if hasGenericRequirements { - // we should consider if we are looking up return type of a method with generic constraints - // where `typeName` passed would include `... where ...` suffix - let typeNameForLookup = typeName.name.split(separator: " ").first! - let genericRequirements: [GenericRequirement] - if let requirements = containingType?.genericRequirements, !requirements.isEmpty { - genericRequirements = requirements - } else { - genericRequirements = method?.genericRequirements ?? [] - } - let relevantRequirements = genericRequirements.filter { - // matched type against a generic requirement name - // thus type should be replaced with a protocol composition - $0.leftType.name == typeNameForLookup - } - if relevantRequirements.count > 1 { - // compose protocols into `ProtocolComposition` and generate TypeName - var implements: [String: Type] = [:] - relevantRequirements.forEach { - implements[$0.rightType.typeName.name] = $0.rightType.type + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let name: String = aDecoder.decode(forKey: "name") else { + withVaList(["name"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } - let composedProtocols = ProtocolComposition( - inheritedTypes: relevantRequirements.map { $0.rightType.typeName.unwrappedTypeName }, - isGeneric: true, - composedTypes: relevantRequirements.compactMap { $0.rightType.type }, - implements: implements - ) - typeName.actualTypeName = TypeName(name: "(\\(relevantRequirements.map { $0.rightType.typeName.unwrappedTypeName }.joined(separator: " & ")))", isProtocolComposition: true) - return composedProtocols - } else if let protocolRequirement = relevantRequirements.first { - // create TypeName off a single generic's protocol requirement - typeName.actualTypeName = TypeName(name: "(\\(protocolRequirement.rightType.typeName))") - return protocolRequirement.rightType.type - } - } - - // try to peek into typealias, maybe part of the typeName is a composed identifier from a type and typealias - // i.e. - // enum Module { - // typealias ID = MyView - // } - // class MyView { - // class ID: String {} - // } - // - // let variable: Module.ID.ID // should be resolved as MyView.ID type - let finalLookup = typeName.actualTypeName ?? typeName - var resolvedIdentifier = finalLookup.generic?.name ?? finalLookup.unwrappedTypeName - for alias in resolvedTypealiases { - /// iteratively replace all typealiases from the resolvedIdentifier to get to the actual type name requested - if resolvedIdentifier.contains(alias.value.name), let range = resolvedIdentifier.range(of: alias.value.name) { - resolvedIdentifier = resolvedIdentifier.replacingCharacters(in: range, with: alias.value.typeName.name) - } - } - // should we cache resolved typenames? - if unique[resolvedIdentifier] == nil { - // peek into typealiases, if any of them contain the same typeName - // this is done after the initial attempt in order to prioritise local (recognized) types first - // before even trying to substitute the requested type with any typealias - for alias in resolvedTypealiases { - /// iteratively replace all typealiases from the resolvedIdentifier to get to the actual type name requested, - /// ignoring namespacing - if resolvedIdentifier == alias.value.aliasName { - resolvedIdentifier = alias.value.typeName.name - typeName.actualTypeName = alias.value.typeName - break + fatalError() + }; self.name = name + guard let parameters: [ClosureParameter] = aDecoder.decode(forKey: "parameters") else { + withVaList(["parameters"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } - } - } - - return unique[resolvedIdentifier] - } - - private func actualTypeName(for typeName: TypeName, - containingType: Type? = nil) -> TypeName? { - let unique = typeMap - let typealiases = resolvedTypealiases - - var unwrapped = typeName.unwrappedTypeName - if let generic = typeName.generic { - unwrapped = generic.name + fatalError() + }; self.parameters = parameters + guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { + withVaList(["returnTypeName"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.returnTypeName = returnTypeName + self.returnType = aDecoder.decode(forKey: "returnType") + self.isAsync = aDecoder.decode(forKey: "isAsync") + self.asyncKeyword = aDecoder.decode(forKey: "asyncKeyword") + self.`throws` = aDecoder.decode(forKey: "`throws`") + self.throwsOrRethrowsKeyword = aDecoder.decode(forKey: "throwsOrRethrowsKeyword") } - guard let aliased = resolveGlobalName(for: unwrapped, containingType: containingType, unique: unique, modules: modules, typealiases: typealiases) else { - return nil + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.parameters, forKey: "parameters") + aCoder.encode(self.returnTypeName, forKey: "returnTypeName") + aCoder.encode(self.returnType, forKey: "returnType") + aCoder.encode(self.isAsync, forKey: "isAsync") + aCoder.encode(self.asyncKeyword, forKey: "asyncKeyword") + aCoder.encode(self.`throws`, forKey: "`throws`") + aCoder.encode(self.throwsOrRethrowsKeyword, forKey: "throwsOrRethrowsKeyword") } - - /// TODO: verify - let generic = typeName.generic.map { GenericType(name: $0.name, typeParameters: $0.typeParameters) } - generic?.name = aliased.name - let dictionary = typeName.dictionary.map { DictionaryType(name: $0.name, valueTypeName: $0.valueTypeName, valueType: $0.valueType, keyTypeName: $0.keyTypeName, keyType: $0.keyType) } - dictionary?.name = aliased.name - let array = typeName.array.map { ArrayType(name: $0.name, elementTypeName: $0.elementTypeName, elementType: $0.elementType) } - array?.name = aliased.name - let set = typeName.set.map { SetType(name: $0.name, elementTypeName: $0.elementTypeName, elementType: $0.elementType) } - set?.name = aliased.name - - return TypeName(name: aliased.name, - isOptional: typeName.isOptional, - isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, - tuple: aliased.typealias?.typeName.tuple ?? typeName.tuple, // TODO: verify - array: aliased.typealias?.typeName.array ?? array, - dictionary: aliased.typealias?.typeName.dictionary ?? dictionary, - closure: aliased.typealias?.typeName.closure ?? typeName.closure, - set: aliased.typealias?.typeName.set ?? set, - generic: aliased.typealias?.typeName.generic ?? generic - ) - } +// sourcery:end } +#endif """), - .init(name: "PhantomProtocols.swift", content: + .init(name: "DynamicMemberLookup_Linux.swift", content: """ // -// Created by Krzysztof Zablocki on 23/01/2017. -// Copyright (c) 2017 Pixle. All rights reserved. +// Stencil +// Copyright © 2022 Stencil +// MIT Licence // -import Foundation - -/// Phantom protocol for diffing -protocol AutoDiffable {} - -/// Phantom protocol for equality -protocol AutoEquatable {} - -/// Phantom protocol for equality -protocol AutoDescription {} - -/// Phantom protocol for NSCoding -protocol AutoCoding {} +#if !canImport(ObjectiveC) +#if canImport(Stencil) +import Stencil +#else +// This is not supposed to work at all, since in Stencil there is a protocol conformance check against `DynamicMemberLookup`, +// and, of course, a substitute with the "same name" but in `Sourcery` will never satisfy that check. +// Here, we are just mimicking `Stencil.DynamicMemberLookup` to showcase what is happening within the `Sourcery` during runtime. + +/// Marker protocol so we can know which types support `@dynamicMemberLookup`. Add this to your own types that support +/// lookup by String. +public protocol DynamicMemberLookup { + /// Get a value for a given `String` key + subscript(dynamicMember member: String) -> Any? { get } +} -protocol AutoJSExport {} +public extension DynamicMemberLookup where Self: RawRepresentable { + /// Get a value for a given `String` key + subscript(dynamicMember member: String) -> Any? { + switch member { + case "rawValue": + return rawValue + default: + return nil + } + } +} +#endif -/// Phantom protocol for NSCoding, Equatable and Diffable -protocol SourceryModelWithoutDescription: AutoDiffable, AutoEquatable, AutoCoding, AutoJSExport {} +public protocol SourceryDynamicMemberLookup: DynamicMemberLookup {} -protocol SourceryModel: SourceryModelWithoutDescription, AutoDescription {} +#endif """), - .init(name: "Protocol.swift", content: + .init(name: "EnumCase_Linux.swift", content: """ // -// Protocol.swift -// Sourcery -// -// Created by Krzysztof Zablocki on 09/12/2016. -// Copyright © 2016 Pixle. All rights reserved. +// Created by Krzysztof Zablocki on 13/09/2016. +// Copyright (c) 2016 Pixle. All rights reserved. // - +#if !canImport(ObjectiveC) import Foundation -/// :nodoc: -public typealias SourceryProtocol = Protocol +/// Defines enum case +public final class EnumCase: NSObject, SourceryModel, AutoDescription, Annotated, Documented, Diffable, SourceryDynamicMemberLookup { + public subscript(dynamicMember member: String) -> Any? { + switch member { + case "name": + return name + case "hasAssociatedValue": + return hasAssociatedValue + case "associatedValues": + return associatedValues + case "indirect": + return indirect + case "annotations": + return annotations + case "rawValue": + return rawValue + default: + fatalError("unable to lookup: \\(member) in \\(self)") + } + } + /// Enum case name + public let name: String -/// Describes Swift protocol -public final class Protocol: Type { + /// Enum case raw value, if any + public let rawValue: String? - /// Returns "protocol" - public override var kind: String { return "protocol" } + /// Enum case associated values + public let associatedValues: [AssociatedValue] - /// list of all declared associated types with their names as keys - public var associatedTypes: [String: AssociatedType] { - didSet { - isGeneric = !associatedTypes.isEmpty || !genericRequirements.isEmpty - } - } + /// Enum case annotations + public var annotations: Annotations = [:] - /// list of generic requirements - public override var genericRequirements: [GenericRequirement] { - didSet { - isGeneric = !associatedTypes.isEmpty || !genericRequirements.isEmpty - } + public var documentation: Documentation = [] + + /// Whether enum case is indirect + public let indirect: Bool + + /// Whether enum case has associated value + public var hasAssociatedValue: Bool { + return !associatedValues.isEmpty } + // Underlying parser data, never to be used by anything else + // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: - public init(name: String = "", - parent: Type? = nil, - accessLevel: AccessLevel = .internal, - isExtension: Bool = false, - variables: [Variable] = [], - methods: [Method] = [], - subscripts: [Subscript] = [], - inheritedTypes: [String] = [], - containedTypes: [Type] = [], - typealiases: [Typealias] = [], - associatedTypes: [String: AssociatedType] = [:], - genericRequirements: [GenericRequirement] = [], - attributes: AttributeList = [:], - modifiers: [SourceryModifier] = [], - annotations: [String: NSObject] = [:], - documentation: [String] = [], - implements: [String: Type] = [:]) { - self.associatedTypes = associatedTypes - super.init( - name: name, - parent: parent, - accessLevel: accessLevel, - isExtension: isExtension, - variables: variables, - methods: methods, - subscripts: subscripts, - inheritedTypes: inheritedTypes, - containedTypes: containedTypes, - typealiases: typealiases, - genericRequirements: genericRequirements, - attributes: attributes, - modifiers: modifiers, - annotations: annotations, - documentation: documentation, - isGeneric: !associatedTypes.isEmpty || !genericRequirements.isEmpty, - implements: implements - ) + public var __parserData: Any? + + /// :nodoc: + public init(name: String, rawValue: String? = nil, associatedValues: [AssociatedValue] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], indirect: Bool = false) { + self.name = name + self.rawValue = rawValue + self.associatedValues = associatedValues + self.annotations = annotations + self.documentation = documentation + self.indirect = indirect } /// :nodoc: + // sourcery: skipJSExport override public var description: String { - var string = super.description - string += ", " - string += "kind = \\(String(describing: self.kind)), " - string += "associatedTypes = \\(String(describing: self.associatedTypes)), " + var string = "\\(Swift.type(of: self)): " + string.append("name = \\(String(describing: self.name)), ") + string.append("rawValue = \\(String(describing: self.rawValue)), ") + string.append("associatedValues = \\(String(describing: self.associatedValues)), ") + string.append("annotations = \\(String(describing: self.annotations)), ") + string.append("documentation = \\(String(describing: self.documentation)), ") + string.append("indirect = \\(String(describing: self.indirect)), ") + string.append("hasAssociatedValue = \\(String(describing: self.hasAssociatedValue))") return string } - override public func diffAgainst(_ object: Any?) -> DiffableResult { + public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() - guard let castObject = object as? Protocol else { - results.append("Incorrect type ") + guard let castObject = object as? EnumCase else { + results.append("Incorrect type ") return results } - results.append(contentsOf: DiffableResult(identifier: "associatedTypes").trackDifference(actual: self.associatedTypes, expected: castObject.associatedTypes)) - results.append(contentsOf: super.diffAgainst(castObject)) + results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) + results.append(contentsOf: DiffableResult(identifier: "rawValue").trackDifference(actual: self.rawValue, expected: castObject.rawValue)) + results.append(contentsOf: DiffableResult(identifier: "associatedValues").trackDifference(actual: self.associatedValues, expected: castObject.associatedValues)) + results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) + results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) + results.append(contentsOf: DiffableResult(identifier: "indirect").trackDifference(actual: self.indirect, expected: castObject.indirect)) return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() - hasher.combine(self.associatedTypes) - hasher.combine(super.hash) + hasher.combine(self.name) + hasher.combine(self.rawValue) + hasher.combine(self.associatedValues) + hasher.combine(self.annotations) + hasher.combine(self.documentation) + hasher.combine(self.indirect) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? Protocol else { return false } - if self.associatedTypes != rhs.associatedTypes { return false } - return super.isEqual(rhs) + guard let rhs = object as? EnumCase else { return false } + if self.name != rhs.name { return false } + if self.rawValue != rhs.rawValue { return false } + if self.associatedValues != rhs.associatedValues { return false } + if self.annotations != rhs.annotations { return false } + if self.documentation != rhs.documentation { return false } + if self.indirect != rhs.indirect { return false } + return true } -// sourcery:inline:Protocol.AutoCoding +// sourcery:inline:EnumCase.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let associatedTypes: [String: AssociatedType] = aDecoder.decode(forKey: "associatedTypes") else { - withVaList(["associatedTypes"]) { arguments in + guard let name: String = aDecoder.decode(forKey: "name") else { + withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.associatedTypes = associatedTypes - super.init(coder: aDecoder) + }; self.name = name + self.rawValue = aDecoder.decode(forKey: "rawValue") + guard let associatedValues: [AssociatedValue] = aDecoder.decode(forKey: "associatedValues") else { + withVaList(["associatedValues"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.associatedValues = associatedValues + guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { + withVaList(["annotations"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.annotations = annotations + guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { + withVaList(["documentation"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.documentation = documentation + self.indirect = aDecoder.decode(forKey: "indirect") } /// :nodoc: - override public func encode(with aCoder: NSCoder) { - super.encode(with: aCoder) - aCoder.encode(self.associatedTypes, forKey: "associatedTypes") + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.rawValue, forKey: "rawValue") + aCoder.encode(self.associatedValues, forKey: "associatedValues") + aCoder.encode(self.annotations, forKey: "annotations") + aCoder.encode(self.documentation, forKey: "documentation") + aCoder.encode(self.indirect, forKey: "indirect") } // sourcery:end } +#endif """), - .init(name: "ProtocolComposition.swift", content: + .init(name: "Enum_Linux.swift", content: """ -// Created by eric_horacek on 2/12/20. -// Copyright © 2020 Airbnb Inc. All rights reserved. +// +// Created by Krzysztof Zablocki on 13/09/2016. +// Copyright (c) 2016 Pixle. All rights reserved. +// +#if !canImport(ObjectiveC) import Foundation -// sourcery: skipJSExport -/// Describes a Swift [protocol composition](https://docs.swift.org/swift-book/ReferenceManual/Types.html#ID454). -public final class ProtocolComposition: Type { +/// Defines Swift enum +public final class Enum: Type { + public override subscript(dynamicMember member: String) -> Any? { + switch member { + case "cases": + return cases + case "hasAssociatedValues": + return hasAssociatedValues + default: + return super[dynamicMember: member] + } + } - /// Returns "protocolComposition" - public override var kind: String { return "protocolComposition" } + // sourcery: skipDescription + /// Returns "enum" + public override var kind: String { return "enum" } - /// The names of the types composed to form this composition - public let composedTypeNames: [TypeName] + /// Enum cases + public var cases: [EnumCase] - // sourcery: skipEquality, skipDescription - /// The types composed to form this composition, if known - public var composedTypes: [Type]? + /** + Enum raw value type name, if any. This type is removed from enum's `based` and `inherited` types collections. + + - important: Unless raw type is specified explicitly via type alias RawValue it will be set to the first type in the inheritance chain. + So if your enum does not have raw value but implements protocols you'll have to specify conformance to these protocols via extension to get enum with nil raw value type and all based and inherited types. + */ + public var rawTypeName: TypeName? { + didSet { + if let rawTypeName = rawTypeName { + hasRawType = true + if let index = inheritedTypes.firstIndex(of: rawTypeName.name) { + inheritedTypes.remove(at: index) + } + if based[rawTypeName.name] != nil { + based[rawTypeName.name] = nil + } + } else { + hasRawType = false + } + } + } + + // sourcery: skipDescription, skipEquality + /// :nodoc: + public private(set) var hasRawType: Bool + + // sourcery: skipDescription, skipEquality + /// Enum raw value type, if known + public var rawType: Type? + + // sourcery: skipEquality, skipDescription, skipCoding + /// Names of types or protocols this type inherits from, including unknown (not scanned) types + public override var based: [String: String] { + didSet { + if let rawTypeName = rawTypeName, based[rawTypeName.name] != nil { + based[rawTypeName.name] = nil + } + } + } + + /// Whether enum contains any associated values + public var hasAssociatedValues: Bool { + return cases.contains(where: { $0.hasAssociatedValue }) + } /// :nodoc: public init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, + inheritedTypes: [String] = [], + rawTypeName: TypeName? = nil, + cases: [EnumCase] = [], variables: [Variable] = [], methods: [Method] = [], - subscripts: [Subscript] = [], - inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], attributes: AttributeList = [:], + modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], - isGeneric: Bool = false, - composedTypeNames: [TypeName] = [], - composedTypes: [Type]? = nil, - implements: [String: Type] = [:]) { - self.composedTypeNames = composedTypeNames - self.composedTypes = composedTypes - super.init( - name: name, - parent: parent, - accessLevel: accessLevel, - isExtension: isExtension, - variables: variables, - methods: methods, - subscripts: subscripts, - inheritedTypes: inheritedTypes, - containedTypes: containedTypes, - typealiases: typealiases, - annotations: annotations, - isGeneric: isGeneric, - implements: implements - ) + documentation: [String] = [], + isGeneric: Bool = false) { + + self.cases = cases + self.rawTypeName = rawTypeName + self.hasRawType = rawTypeName != nil || !inheritedTypes.isEmpty + + super.init(name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric) + + if let rawTypeName = rawTypeName?.name, let index = self.inheritedTypes.firstIndex(of: rawTypeName) { + self.inheritedTypes.remove(at: index) + } } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = super.description - string += ", " - string += "kind = \\(String(describing: self.kind)), " - string += "composedTypeNames = \\(String(describing: self.composedTypeNames))" + string.append(", ") + string.append("cases = \\(String(describing: self.cases)), ") + string.append("rawTypeName = \\(String(describing: self.rawTypeName)), ") + string.append("hasAssociatedValues = \\(String(describing: self.hasAssociatedValues))") return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() - guard let castObject = object as? ProtocolComposition else { - results.append("Incorrect type ") + guard let castObject = object as? Enum else { + results.append("Incorrect type ") return results } - results.append(contentsOf: DiffableResult(identifier: "composedTypeNames").trackDifference(actual: self.composedTypeNames, expected: castObject.composedTypeNames)) + results.append(contentsOf: DiffableResult(identifier: "cases").trackDifference(actual: self.cases, expected: castObject.cases)) + results.append(contentsOf: DiffableResult(identifier: "rawTypeName").trackDifference(actual: self.rawTypeName, expected: castObject.rawTypeName)) results.append(contentsOf: super.diffAgainst(castObject)) return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() - hasher.combine(self.composedTypeNames) + hasher.combine(self.cases) + hasher.combine(self.rawTypeName) hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? ProtocolComposition else { return false } - if self.composedTypeNames != rhs.composedTypeNames { return false } + guard let rhs = object as? Enum else { return false } + if self.cases != rhs.cases { return false } + if self.rawTypeName != rhs.rawTypeName { return false } return super.isEqual(rhs) } -// sourcery:inline:ProtocolComposition.AutoCoding +// sourcery:inline:Enum.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let composedTypeNames: [TypeName] = aDecoder.decode(forKey: "composedTypeNames") else { - withVaList(["composedTypeNames"]) { arguments in + guard let cases: [EnumCase] = aDecoder.decode(forKey: "cases") else { + withVaList(["cases"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.composedTypeNames = composedTypeNames - self.composedTypes = aDecoder.decode(forKey: "composedTypes") + }; self.cases = cases + self.rawTypeName = aDecoder.decode(forKey: "rawTypeName") + self.hasRawType = aDecoder.decode(forKey: "hasRawType") + self.rawType = aDecoder.decode(forKey: "rawType") super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) - aCoder.encode(self.composedTypeNames, forKey: "composedTypeNames") - aCoder.encode(self.composedTypes, forKey: "composedTypes") + aCoder.encode(self.cases, forKey: "cases") + aCoder.encode(self.rawTypeName, forKey: "rawTypeName") + aCoder.encode(self.hasRawType, forKey: "hasRawType") + aCoder.encode(self.rawType, forKey: "rawType") } // sourcery:end - } +#endif """), - .init(name: "Struct.swift", content: + .init(name: "GenericParameter_Linux.swift", content: """ -// -// Struct.swift -// Sourcery -// -// Created by Krzysztof Zablocki on 13/09/2016. -// Copyright © 2016 Pixle. All rights reserved. -// - +#if !canImport(ObjectiveC) import Foundation -// sourcery: skipDescription -/// Describes Swift struct -public final class Struct: Type { +/// Descibes Swift generic parameter +public final class GenericParameter: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { + public subscript(dynamicMember member: String) -> Any? { + switch member { + case "name": + return name + case "inheritedTypeName": + return inheritedTypeName + default: + fatalError("unable to lookup: \\(member) in \\(self)") + } + } - /// Returns "struct" - public override var kind: String { return "struct" } + /// Generic parameter name + public var name: String + + /// Generic parameter inherited type + public var inheritedTypeName: TypeName? /// :nodoc: - public override init(name: String = "", - parent: Type? = nil, - accessLevel: AccessLevel = .internal, - isExtension: Bool = false, - variables: [Variable] = [], - methods: [Method] = [], - subscripts: [Subscript] = [], - inheritedTypes: [String] = [], - containedTypes: [Type] = [], - typealiases: [Typealias] = [], - genericRequirements: [GenericRequirement] = [], - attributes: AttributeList = [:], - modifiers: [SourceryModifier] = [], - annotations: [String: NSObject] = [:], - documentation: [String] = [], - isGeneric: Bool = false, - implements: [String: Type] = [:]) { - super.init( - name: name, - parent: parent, - accessLevel: accessLevel, - isExtension: isExtension, - variables: variables, - methods: methods, - subscripts: subscripts, - inheritedTypes: inheritedTypes, - containedTypes: containedTypes, - typealiases: typealiases, - genericRequirements: genericRequirements, - attributes: attributes, - modifiers: modifiers, - annotations: annotations, - documentation: documentation, - isGeneric: isGeneric, - implements: implements - ) + public init(name: String, inheritedTypeName: TypeName? = nil) { + self.name = name + self.inheritedTypeName = inheritedTypeName } /// :nodoc: + // sourcery: skipJSExport override public var description: String { - var string = super.description - string += ", " - string += "kind = \\(String(describing: self.kind))" + var string = "\\(Swift.type(of: self)): " + string.append("name = \\(String(describing: self.name)), ") + string.append("inheritedTypeName = \\(String(describing: self.inheritedTypeName))") return string } - override public func diffAgainst(_ object: Any?) -> DiffableResult { + public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() - guard let castObject = object as? Struct else { - results.append("Incorrect type ") + guard let castObject = object as? GenericParameter else { + results.append("Incorrect type ") return results } - results.append(contentsOf: super.diffAgainst(castObject)) + results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) + results.append(contentsOf: DiffableResult(identifier: "inheritedTypeName").trackDifference(actual: self.inheritedTypeName, expected: castObject.inheritedTypeName)) return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() - hasher.combine(super.hash) + hasher.combine(self.name) + hasher.combine(self.inheritedTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? Struct else { return false } - return super.isEqual(rhs) + guard let rhs = object as? GenericParameter else { return false } + if self.name != rhs.name { return false } + if self.inheritedTypeName != rhs.inheritedTypeName { return false } + return true } -// sourcery:inline:Struct.AutoCoding +// sourcery:inline:GenericParameter.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) + guard let name: String = aDecoder.decode(forKey: "name") else { + withVaList(["name"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.name = name + self.inheritedTypeName = aDecoder.decode(forKey: "inheritedTypeName") } /// :nodoc: - override public func encode(with aCoder: NSCoder) { - super.encode(with: aCoder) + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.inheritedTypeName, forKey: "inheritedTypeName") } + // sourcery:end } +#endif """), - .init(name: "Subscript.swift", content: -#""" + .init(name: "GenericRequirement_Linux.swift", content: +""" +#if !canImport(ObjectiveC) import Foundation -/// Describes subscript -public final class Subscript: NSObject, SourceryModel, Annotated, Documented, Definition, Diffable { - - /// Method parameters - public var parameters: [MethodParameter] +/// Descibes Swift generic requirement +public class GenericRequirement: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { + public subscript(dynamicMember member: String) -> Any? { + switch member { + case "leftType": + return leftType + case "rightType": + return rightType + case "relationship": + return relationship + case "relationshipSyntax": + return relationshipSyntax + default: + fatalError("unable to lookup: \\(member) in \\(self)") + } + } - /// Return value type name used in declaration, including generic constraints, i.e. `where T: Equatable` - public var returnTypeName: TypeName + public enum Relationship: String { + case equals + case conformsTo - /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` - public var actualReturnTypeName: TypeName { - return returnTypeName.actualTypeName ?? returnTypeName + var syntax: String { + switch self { + case .equals: + return "==" + case .conformsTo: + return ":" + } + } } - // sourcery: skipEquality, skipDescription - /// Actual return value type, if known - public var returnType: Type? + public var leftType: AssociatedType + public let rightType: GenericTypeParameter - // sourcery: skipEquality, skipDescription - /// Whether return value type is optional - public var isOptionalReturnType: Bool { - return returnTypeName.isOptional + /// relationship name + public let relationship: String + + /// Syntax e.g. `==` or `:` + public let relationshipSyntax: String + + public init(leftType: AssociatedType, rightType: GenericTypeParameter, relationship: Relationship) { + self.leftType = leftType + self.rightType = rightType + self.relationship = relationship.rawValue + self.relationshipSyntax = relationship.syntax } - // sourcery: skipEquality, skipDescription - /// Whether return value type is implicitly unwrapped optional - public var isImplicitlyUnwrappedOptionalReturnType: Bool { - return returnTypeName.isImplicitlyUnwrappedOptional + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("leftType = \\(String(describing: self.leftType)), ") + string.append("rightType = \\(String(describing: self.rightType)), ") + string.append("relationship = \\(String(describing: self.relationship)), ") + string.append("relationshipSyntax = \\(String(describing: self.relationshipSyntax))") + return string } - // sourcery: skipEquality, skipDescription - /// Return value type name without attributes and optional type information - public var unwrappedReturnTypeName: String { - return returnTypeName.unwrappedTypeName + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? GenericRequirement else { + results.append("Incorrect type ") + return results + } + results.append(contentsOf: DiffableResult(identifier: "leftType").trackDifference(actual: self.leftType, expected: castObject.leftType)) + results.append(contentsOf: DiffableResult(identifier: "rightType").trackDifference(actual: self.rightType, expected: castObject.rightType)) + results.append(contentsOf: DiffableResult(identifier: "relationship").trackDifference(actual: self.relationship, expected: castObject.relationship)) + results.append(contentsOf: DiffableResult(identifier: "relationshipSyntax").trackDifference(actual: self.relationshipSyntax, expected: castObject.relationshipSyntax)) + return results } - /// Whether method is final - public var isFinal: Bool { - modifiers.contains { $0.name == "final" } + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.leftType) + hasher.combine(self.rightType) + hasher.combine(self.relationship) + hasher.combine(self.relationshipSyntax) + return hasher.finalize() } - /// Variable read access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` - public let readAccess: String + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? GenericRequirement else { return false } + if self.leftType != rhs.leftType { return false } + if self.rightType != rhs.rightType { return false } + if self.relationship != rhs.relationship { return false } + if self.relationshipSyntax != rhs.relationshipSyntax { return false } + return true + } - /// Variable write access, i.e. `internal`, `private`, `fileprivate`, `public`, `open`. - /// For immutable variables this value is empty string - public var writeAccess: String + // sourcery:inline:GenericRequirement.AutoCoding - /// Whether subscript is async - public let isAsync: Bool + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let leftType: AssociatedType = aDecoder.decode(forKey: "leftType") else { + withVaList(["leftType"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.leftType = leftType + guard let rightType: GenericTypeParameter = aDecoder.decode(forKey: "rightType") else { + withVaList(["rightType"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.rightType = rightType + guard let relationship: String = aDecoder.decode(forKey: "relationship") else { + withVaList(["relationship"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.relationship = relationship + guard let relationshipSyntax: String = aDecoder.decode(forKey: "relationshipSyntax") else { + withVaList(["relationshipSyntax"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.relationshipSyntax = relationshipSyntax + } - /// Whether subscript throws - public let `throws`: Bool + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.leftType, forKey: "leftType") + aCoder.encode(self.rightType, forKey: "rightType") + aCoder.encode(self.relationship, forKey: "relationship") + aCoder.encode(self.relationshipSyntax, forKey: "relationshipSyntax") + } + // sourcery:end +} +#endif - /// Whether variable is mutable or not - public var isMutable: Bool { - return writeAccess != AccessLevel.none.rawValue - } +"""), + .init(name: "GenericTypeParameter_Linux.swift", content: +""" +#if !canImport(ObjectiveC) +import Foundation - /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 - public let annotations: Annotations - - public let documentation: Documentation - - /// Reference to type name where the method is defined, - /// nil if defined outside of any `enum`, `struct`, `class` etc - public let definedInTypeName: TypeName? - - /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` - public var actualDefinedInTypeName: TypeName? { - return definedInTypeName?.actualTypeName ?? definedInTypeName +/// Descibes Swift generic type parameter +public final class GenericTypeParameter: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { + public subscript(dynamicMember member: String) -> Any? { + switch member { + case "typeName": + return typeName + case "type": + return type + default: + fatalError("unable to lookup: \\(member) in \\(self)") + } } - // sourcery: skipEquality, skipDescription - /// Reference to actual type where the object is defined, - /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown - public var definedInType: Type? - - /// Method attributes, i.e. `@discardableResult` - public let attributes: AttributeList - - /// Method modifiers, i.e. `private` - public let modifiers: [SourceryModifier] - - /// list of generic parameters - public let genericParameters: [GenericParameter] - - /// list of generic requirements - public let genericRequirements: [GenericRequirement] - - /// Whether subscript is generic or not - public var isGeneric: Bool { - return genericParameters.isEmpty == false - } + /// Generic parameter type name + public var typeName: TypeName - // Underlying parser data, never to be used by anything else - // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport - /// :nodoc: - public var __parserData: Any? + // sourcery: skipEquality, skipDescription + /// Generic parameter type, if known + public var type: Type? /// :nodoc: - public init(parameters: [MethodParameter] = [], - returnTypeName: TypeName, - accessLevel: (read: AccessLevel, write: AccessLevel) = (.internal, .internal), - isAsync: Bool = false, - `throws`: Bool = false, - genericParameters: [GenericParameter] = [], - genericRequirements: [GenericRequirement] = [], - attributes: AttributeList = [:], - modifiers: [SourceryModifier] = [], - annotations: [String: NSObject] = [:], - documentation: [String] = [], - definedInTypeName: TypeName? = nil) { - - self.parameters = parameters - self.returnTypeName = returnTypeName - self.readAccess = accessLevel.read.rawValue - self.writeAccess = accessLevel.write.rawValue - self.isAsync = isAsync - self.throws = `throws` - self.genericParameters = genericParameters - self.genericRequirements = genericRequirements - self.attributes = attributes - self.modifiers = modifiers - self.annotations = annotations - self.documentation = documentation - self.definedInTypeName = definedInTypeName + public init(typeName: TypeName, type: Type? = nil) { + self.typeName = typeName + self.type = type } /// :nodoc: + // sourcery: skipJSExport override public var description: String { - var string = "\(Swift.type(of: self)): " - string += "parameters = \(String(describing: self.parameters)), " - string += "returnTypeName = \(String(describing: self.returnTypeName)), " - string += "actualReturnTypeName = \(String(describing: self.actualReturnTypeName)), " - string += "isFinal = \(String(describing: self.isFinal)), " - string += "readAccess = \(String(describing: self.readAccess)), " - string += "writeAccess = \(String(describing: self.writeAccess)), " - string += "isAsync = \(String(describing: self.isAsync)), " - string += "`throws` = \(String(describing: self.throws)), " - string += "isMutable = \(String(describing: self.isMutable)), " - string += "annotations = \(String(describing: self.annotations)), " - string += "documentation = \(String(describing: self.documentation)), " - string += "definedInTypeName = \(String(describing: self.definedInTypeName)), " - string += "actualDefinedInTypeName = \(String(describing: self.actualDefinedInTypeName)), " - string += "genericParameters = \(String(describing: self.genericParameters)), " - string += "genericRequirements = \(String(describing: self.genericRequirements)), " - string += "isGeneric = \(String(describing: self.isGeneric)), " - string += "attributes = \(String(describing: self.attributes)), " - string += "modifiers = \(String(describing: self.modifiers))" + var string = "\\(Swift.type(of: self)): " + string.append("typeName = \\(String(describing: self.typeName))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() - guard let castObject = object as? Subscript else { - results.append("Incorrect type ") + guard let castObject = object as? GenericTypeParameter else { + results.append("Incorrect type ") return results } - results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) - results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) - results.append(contentsOf: DiffableResult(identifier: "readAccess").trackDifference(actual: self.readAccess, expected: castObject.readAccess)) - results.append(contentsOf: DiffableResult(identifier: "writeAccess").trackDifference(actual: self.writeAccess, expected: castObject.writeAccess)) - results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) - results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.throws, expected: castObject.throws)) - results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) - results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) - results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) - results.append(contentsOf: DiffableResult(identifier: "genericParameters").trackDifference(actual: self.genericParameters, expected: castObject.genericParameters)) - results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) - results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) - results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) + results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() - hasher.combine(self.parameters) - hasher.combine(self.returnTypeName) - hasher.combine(self.readAccess) - hasher.combine(self.writeAccess) - hasher.combine(self.isAsync) - hasher.combine(self.throws) - hasher.combine(self.annotations) - hasher.combine(self.documentation) - hasher.combine(self.definedInTypeName) - hasher.combine(self.genericParameters) - hasher.combine(self.genericRequirements) - hasher.combine(self.attributes) - hasher.combine(self.modifiers) + hasher.combine(self.typeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? Subscript else { return false } - if self.parameters != rhs.parameters { return false } - if self.returnTypeName != rhs.returnTypeName { return false } - if self.readAccess != rhs.readAccess { return false } - if self.writeAccess != rhs.writeAccess { return false } - if self.isAsync != rhs.isAsync { return false } - if self.throws != rhs.throws { return false } - if self.annotations != rhs.annotations { return false } - if self.documentation != rhs.documentation { return false } - if self.definedInTypeName != rhs.definedInTypeName { return false } - if self.genericParameters != rhs.genericParameters { return false } - if self.genericRequirements != rhs.genericRequirements { return false } - if self.attributes != rhs.attributes { return false } - if self.modifiers != rhs.modifiers { return false } + guard let rhs = object as? GenericTypeParameter else { return false } + if self.typeName != rhs.typeName { return false } return true } -// sourcery:inline:Subscript.AutoCoding +// sourcery:inline:GenericTypeParameter.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let parameters: [MethodParameter] = aDecoder.decode(forKey: "parameters") else { - withVaList(["parameters"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.parameters = parameters - guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { - withVaList(["returnTypeName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.returnTypeName = returnTypeName - self.returnType = aDecoder.decode(forKey: "returnType") - guard let readAccess: String = aDecoder.decode(forKey: "readAccess") else { - withVaList(["readAccess"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.readAccess = readAccess - guard let writeAccess: String = aDecoder.decode(forKey: "writeAccess") else { - withVaList(["writeAccess"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.writeAccess = writeAccess - guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { - withVaList(["annotations"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.annotations = annotations - guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { - withVaList(["documentation"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.documentation = documentation - self.isAsync = aDecoder.decode(forKey: "isAsync") - self.`throws` = aDecoder.decode(forKey: "`throws`") - self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") - self.definedInType = aDecoder.decode(forKey: "definedInType") - guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { - withVaList(["attributes"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.attributes = attributes - guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { - withVaList(["modifiers"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.modifiers = modifiers - guard let genericParameters: [GenericParameter] = aDecoder.decode(forKey: "genericParameters") else { - withVaList(["genericParameters"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.genericParameters = genericParameters - guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { - withVaList(["genericRequirements"]) { arguments in + guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { + withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.genericRequirements = genericRequirements + }; self.typeName = typeName + self.type = aDecoder.decode(forKey: "type") } /// :nodoc: public func encode(with aCoder: NSCoder) { - aCoder.encode(self.parameters, forKey: "parameters") - aCoder.encode(self.returnTypeName, forKey: "returnTypeName") - aCoder.encode(self.returnType, forKey: "returnType") - aCoder.encode(self.readAccess, forKey: "readAccess") - aCoder.encode(self.writeAccess, forKey: "writeAccess") - aCoder.encode(self.isAsync, forKey: "isAsync") - aCoder.encode(self.`throws`, forKey: "`throws`") - aCoder.encode(self.annotations, forKey: "annotations") - aCoder.encode(self.documentation, forKey: "documentation") - aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") - aCoder.encode(self.definedInType, forKey: "definedInType") - aCoder.encode(self.genericParameters, forKey: "genericParameters") - aCoder.encode(self.genericRequirements, forKey: "genericRequirements") - aCoder.encode(self.attributes, forKey: "attributes") - aCoder.encode(self.modifiers, forKey: "modifiers") + aCoder.encode(self.typeName, forKey: "typeName") + aCoder.encode(self.type, forKey: "type") } -// sourcery:end +// sourcery:end } +#endif -"""#), - .init(name: "TemplateContext.swift", content: +"""), + .init(name: "MethodParameter_Linux.swift", content: """ -// -// Created by Krzysztof Zablocki on 31/12/2016. -// Copyright (c) 2016 Pixle. All rights reserved. -// - +#if !canImport(ObjectiveC) import Foundation -/// :nodoc: -// sourcery: skipCoding -public final class TemplateContext: NSObject, SourceryModel, NSCoding, Diffable { - // sourcery: skipJSExport - public let parserResult: FileParserResult? - public let functions: [SourceryMethod] - public let types: Types - public let argument: [String: NSObject] - - // sourcery: skipDescription - public var type: [String: Type] { - return types.typesByName +/// Describes method parameter +public class MethodParameter: NSObject, SourceryModel, Typed, Annotated, Diffable, SourceryDynamicMemberLookup { + public subscript(dynamicMember member: String) -> Any? { + switch member { + case "argumentLabel": + return argumentLabel + case "name": + return name + case "typeName": + return typeName + case "isClosure": + return isClosure + case "typeAttributes": + return typeAttributes + case "isVariadic": + return isVariadic + case "asSource": + return asSource + default: + fatalError("unable to lookup: \\(member) in \\(self)") + } } + /// Parameter external name + public var argumentLabel: String? - public init(parserResult: FileParserResult?, types: Types, functions: [SourceryMethod], arguments: [String: NSObject]) { - self.parserResult = parserResult - self.types = types - self.functions = functions - self.argument = arguments - } + // Note: although method parameter can have no name, this property is not optional, + // this is so to maintain compatibility with existing templates. + /// Parameter internal name + public let name: String - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let parserResult: FileParserResult = aDecoder.decode(forKey: "parserResult") else { - withVaList(["parserResult"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found. FileParserResults are required for template context that needs persisting.", arguments: arguments) - } - fatalError() - } - guard let argument: [String: NSObject] = aDecoder.decode(forKey: "argument") else { - withVaList(["argument"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - } + /// Parameter type name + public let typeName: TypeName - // if we want to support multiple cycles of encode / decode we need deep copy because composer changes reference types - let fileParserResultCopy: FileParserResult? = nil -// fileParserResultCopy = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(NSKeyedArchiver.archivedData(withRootObject: parserResult)) as? FileParserResult - - let composed = Composer.uniqueTypesAndFunctions(parserResult) - self.types = .init(types: composed.types, typealiases: composed.typealiases) - self.functions = composed.functions - - self.parserResult = fileParserResultCopy - self.argument = argument - } - - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.parserResult, forKey: "parserResult") - aCoder.encode(self.argument, forKey: "argument") - } + /// Parameter flag whether it's inout or not + public let `inout`: Bool + + /// Is this variadic parameter? + public let isVariadic: Bool - public var stencilContext: [String: Any] { - return [ - "types": types, - "functions": functions, - "type": types.typesByName, - "argument": argument - ] - } + // sourcery: skipEquality, skipDescription + /// Parameter type, if known + public var type: Type? - /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "parserResult = \\(String(describing: self.parserResult)), " - string += "functions = \\(String(describing: self.functions)), " - string += "types = \\(String(describing: self.types)), " - string += "argument = \\(String(describing: self.argument)), " - string += "stencilContext = \\(String(describing: self.stencilContext))" - return string + /// Parameter type attributes, i.e. `@escaping` + public var typeAttributes: AttributeList { + return typeName.attributes } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? TemplateContext else { - results.append("Incorrect type ") - return results - } - results.append(contentsOf: DiffableResult(identifier: "parserResult").trackDifference(actual: self.parserResult, expected: castObject.parserResult)) - results.append(contentsOf: DiffableResult(identifier: "functions").trackDifference(actual: self.functions, expected: castObject.functions)) - results.append(contentsOf: DiffableResult(identifier: "types").trackDifference(actual: self.types, expected: castObject.types)) - results.append(contentsOf: DiffableResult(identifier: "argument").trackDifference(actual: self.argument, expected: castObject.argument)) - return results - } + /// Method parameter default value expression + public var defaultValue: String? - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.parserResult) - hasher.combine(self.functions) - hasher.combine(self.types) - hasher.combine(self.argument) - return hasher.finalize() - } + /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 + public var annotations: Annotations = [:] /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? TemplateContext else { return false } - if self.parserResult != rhs.parserResult { return false } - if self.functions != rhs.functions { return false } - if self.types != rhs.types { return false } - if self.argument != rhs.argument { return false } - return true - } - - // sourcery: skipDescription, skipEquality - public var jsContext: [String: Any] { - return [ - "types": [ - "all": types.all, - "protocols": types.protocols, - "classes": types.classes, - "structs": types.structs, - "enums": types.enums, - "extensions": types.extensions, - "based": types.based, - "inheriting": types.inheriting, - "implementing": types.implementing - ] as [String : Any], - "functions": functions, - "type": types.typesByName, - "argument": argument - ] + public init(argumentLabel: String?, name: String = "", typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false, isVariadic: Bool = false) { + self.typeName = typeName + self.argumentLabel = argumentLabel + self.name = name + self.type = type + self.defaultValue = defaultValue + self.annotations = annotations + self.`inout` = isInout + self.isVariadic = isVariadic } -} - -extension ProcessInfo { /// :nodoc: - public var context: TemplateContext! { - return NSKeyedUnarchiver.unarchiveObject(withFile: arguments[1]) as? TemplateContext + public init(name: String = "", typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false, isVariadic: Bool = false) { + self.typeName = typeName + self.argumentLabel = name + self.name = name + self.type = type + self.defaultValue = defaultValue + self.annotations = annotations + self.`inout` = isInout + self.isVariadic = isVariadic } -} - -"""), - .init(name: "Types.swift", content: -""" -import Foundation - -// sourcery: skipJSExport -/// Collection of scanned types for accessing in templates -public final class Types: NSObject, SourceryModel, Diffable { - /// :nodoc: - public let types: [Type] + public var asSource: String { + let typeSuffix = ": \\(`inout` ? "inout " : "")\\(typeName.asSource)\\(defaultValue.map { " = \\($0)" } ?? "")" + (isVariadic ? "..." : "") + guard argumentLabel != name else { + return name + typeSuffix + } - /// All known typealiases - public let typealiases: [Typealias] + let labels = [argumentLabel ?? "_", name.nilIfEmpty] + .compactMap { $0 } + .joined(separator: " ") - /// :nodoc: - public init(types: [Type], typealiases: [Typealias] = []) { - self.types = types - self.typealiases = typealiases + return (labels.nilIfEmpty ?? "_") + typeSuffix } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " - string += "types = \\(String(describing: self.types)), " - string += "typealiases = \\(String(describing: self.typealiases))" + string.append("argumentLabel = \\(String(describing: self.argumentLabel)), ") + string.append("name = \\(String(describing: self.name)), ") + string.append("typeName = \\(String(describing: self.typeName)), ") + string.append("`inout` = \\(String(describing: self.`inout`)), ") + string.append("isVariadic = \\(String(describing: self.isVariadic)), ") + string.append("typeAttributes = \\(String(describing: self.typeAttributes)), ") + string.append("defaultValue = \\(String(describing: self.defaultValue)), ") + string.append("annotations = \\(String(describing: self.annotations)), ") + string.append("asSource = \\(String(describing: self.asSource))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() - guard let castObject = object as? Types else { - results.append("Incorrect type ") + guard let castObject = object as? MethodParameter else { + results.append("Incorrect type ") return results } - results.append(contentsOf: DiffableResult(identifier: "types").trackDifference(actual: self.types, expected: castObject.types)) - results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) + results.append(contentsOf: DiffableResult(identifier: "argumentLabel").trackDifference(actual: self.argumentLabel, expected: castObject.argumentLabel)) + results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) + results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) + results.append(contentsOf: DiffableResult(identifier: "`inout`").trackDifference(actual: self.`inout`, expected: castObject.`inout`)) + results.append(contentsOf: DiffableResult(identifier: "isVariadic").trackDifference(actual: self.isVariadic, expected: castObject.isVariadic)) + results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) + results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() - hasher.combine(self.types) - hasher.combine(self.typealiases) + hasher.combine(self.argumentLabel) + hasher.combine(self.name) + hasher.combine(self.typeName) + hasher.combine(self.`inout`) + hasher.combine(self.isVariadic) + hasher.combine(self.defaultValue) + hasher.combine(self.annotations) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? Types else { return false } - if self.types != rhs.types { return false } - if self.typealiases != rhs.typealiases { return false } + guard let rhs = object as? MethodParameter else { return false } + if self.argumentLabel != rhs.argumentLabel { return false } + if self.name != rhs.name { return false } + if self.typeName != rhs.typeName { return false } + if self.`inout` != rhs.`inout` { return false } + if self.isVariadic != rhs.isVariadic { return false } + if self.defaultValue != rhs.defaultValue { return false } + if self.annotations != rhs.annotations { return false } return true } -// sourcery:inline:Types.AutoCoding +// sourcery:inline:MethodParameter.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let types: [Type] = aDecoder.decode(forKey: "types") else { - withVaList(["types"]) { arguments in + self.argumentLabel = aDecoder.decode(forKey: "argumentLabel") + guard let name: String = aDecoder.decode(forKey: "name") else { + withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.types = types - guard let typealiases: [Typealias] = aDecoder.decode(forKey: "typealiases") else { - withVaList(["typealiases"]) { arguments in + }; self.name = name + guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { + withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.typealiases = typealiases + }; self.typeName = typeName + self.`inout` = aDecoder.decode(forKey: "`inout`") + self.isVariadic = aDecoder.decode(forKey: "isVariadic") + self.type = aDecoder.decode(forKey: "type") + self.defaultValue = aDecoder.decode(forKey: "defaultValue") + guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { + withVaList(["annotations"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.annotations = annotations } /// :nodoc: public func encode(with aCoder: NSCoder) { - aCoder.encode(self.types, forKey: "types") - aCoder.encode(self.typealiases, forKey: "typealiases") + aCoder.encode(self.argumentLabel, forKey: "argumentLabel") + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.typeName, forKey: "typeName") + aCoder.encode(self.`inout`, forKey: "`inout`") + aCoder.encode(self.isVariadic, forKey: "isVariadic") + aCoder.encode(self.type, forKey: "type") + aCoder.encode(self.defaultValue, forKey: "defaultValue") + aCoder.encode(self.annotations, forKey: "annotations") } // sourcery:end +} - // sourcery: skipDescription, skipEquality, skipCoding - /// :nodoc: - public lazy internal(set) var typesByName: [String: Type] = { - var typesByName = [String: Type]() - self.types.forEach { typesByName[$0.globalName] = $0 } - return typesByName - }() - - // sourcery: skipDescription, skipEquality, skipCoding - /// :nodoc: - public lazy internal(set) var typesaliasesByName: [String: Typealias] = { - var typesaliasesByName = [String: Typealias]() - self.typealiases.forEach { typesaliasesByName[$0.name] = $0 } - return typesaliasesByName - }() - - // sourcery: skipDescription, skipEquality, skipCoding - /// All known types, excluding protocols or protocol compositions. - public lazy internal(set) var all: [Type] = { - return self.types.filter { !($0 is Protocol || $0 is ProtocolComposition) } - }() - - // sourcery: skipDescription, skipEquality, skipCoding - /// All known protocols - public lazy internal(set) var protocols: [Protocol] = { - return self.types.compactMap { $0 as? Protocol } - }() +extension Array where Element == MethodParameter { + public var asSource: String { + "(\\(map { $0.asSource }.joined(separator: ", ")))" + } +} +#endif - // sourcery: skipDescription, skipEquality, skipCoding - /// All known protocol compositions - public lazy internal(set) var protocolCompositions: [ProtocolComposition] = { - return self.types.compactMap { $0 as? ProtocolComposition } - }() +"""), + .init(name: "Method_Linux.swift", content: +""" +#if !canImport(ObjectiveC) +import Foundation - // sourcery: skipDescription, skipEquality, skipCoding - /// All known classes - public lazy internal(set) var classes: [Class] = { - return self.all.compactMap { $0 as? Class } - }() +/// :nodoc: +public typealias SourceryMethod = Method - // sourcery: skipDescription, skipEquality, skipCoding - /// All known structs - public lazy internal(set) var structs: [Struct] = { - return self.all.compactMap { $0 as? Struct } - }() +/// Describes method +public final class Method: NSObject, SourceryModel, Annotated, Documented, Definition, Diffable, SourceryDynamicMemberLookup { + public subscript(dynamicMember member: String) -> Any? { + switch member { + case "definedInType": + return definedInType + case "shortName": + return shortName + case "name": + return name + case "selectorName": + return selectorName + case "callName": + return callName + case "parameters": + return parameters + case "throws": + return `throws` + case "isInitializer": + return isInitializer + case "accessLevel": + return accessLevel + case "isStatic": + return isStatic + case "returnTypeName": + return returnTypeName + case "isAsync": + return isAsync + case "attributes": + return attributes + case "isOptionalReturnType": + return isOptionalReturnType + case "actualReturnTypeName": + return actualReturnTypeName + case "isDynamic": + return isDynamic + case "genericRequirements": + return genericRequirements + default: + fatalError("unable to lookup: \\(member) in \\(self)") + } + } - // sourcery: skipDescription, skipEquality, skipCoding - /// All known enums - public lazy internal(set) var enums: [Enum] = { - return self.all.compactMap { $0 as? Enum } - }() + /// Full method name, including generic constraints, i.e. `foo(bar: T)` + public let name: String - // sourcery: skipDescription, skipEquality, skipCoding - /// All known extensions - public lazy internal(set) var extensions: [Type] = { - return self.all.compactMap { $0.isExtension ? $0 : nil } - }() + /// Method name including arguments names, i.e. `foo(bar:)` + public var selectorName: String - // sourcery: skipDescription, skipEquality, skipCoding - /// Types based on any other type, grouped by its name, even if they are not known. - /// `types.based.MyType` returns list of types based on `MyType` - public lazy internal(set) var based: TypesCollection = { - TypesCollection( - types: self.types, - collection: { Array($0.based.keys) } - ) - }() + // sourcery: skipEquality, skipDescription + /// Method name without arguments names and parenthesis, i.e. `foo` + public var shortName: String { + return name.range(of: "(").map({ String(name[..<$0.lowerBound]) }) ?? name + } - // sourcery: skipDescription, skipEquality, skipCoding - /// Classes inheriting from any known class, grouped by its name. - /// `types.inheriting.MyClass` returns list of types inheriting from `MyClass` - public lazy internal(set) var inheriting: TypesCollection = { - TypesCollection( - types: self.types, - collection: { Array($0.inherits.keys) }, - validate: { type in - guard type is Class else { - throw "\\(type.name) is not a class and should be used with `implementing` or `based`" - } - }) - }() + // sourcery: skipEquality, skipDescription + /// Method name without arguments names, parenthesis and generic types, i.e. `foo` (can be used to generate code for method call) + public var callName: String { + return shortName.range(of: "<").map({ String(shortName[..<$0.lowerBound]) }) ?? shortName + } - // sourcery: skipDescription, skipEquality, skipCoding - /// Types implementing known protocol, grouped by its name. - /// `types.implementing.MyProtocol` returns list of types implementing `MyProtocol` - public lazy internal(set) var implementing: TypesCollection = { - TypesCollection( - types: self.types, - collection: { Array($0.implements.keys) }, - validate: { type in - guard type is Protocol else { - throw "\\(type.name) is a class and should be used with `inheriting` or `based`" - } - }) - }() -} + /// Method parameters + public var parameters: [MethodParameter] -"""), - .init(name: "TypesCollection.swift", content: -""" -import Foundation + /// Return value type name used in declaration, including generic constraints, i.e. `where T: Equatable` + public var returnTypeName: TypeName -/// :nodoc: -public class TypesCollection: NSObject, AutoJSExport { + // sourcery: skipEquality, skipDescription + /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` + public var actualReturnTypeName: TypeName { + return returnTypeName.actualTypeName ?? returnTypeName + } - // sourcery:begin: skipJSExport - let all: [Type] - let types: [String: [Type]] - let validate: ((Type) throws -> Void)? - // sourcery:end + // sourcery: skipEquality, skipDescription + /// Actual return value type, if known + public var returnType: Type? - init(types: [Type], collection: (Type) -> [String], validate: ((Type) throws -> Void)? = nil) { - self.all = types - var content = [String: [Type]]() - self.all.forEach { type in - collection(type).forEach { name in - var list = content[name] ?? [Type]() - list.append(type) - content[name] = list - } - } - self.types = content - self.validate = validate + // sourcery: skipEquality, skipDescription + /// Whether return value type is optional + public var isOptionalReturnType: Bool { + return returnTypeName.isOptional || isFailableInitializer } - public func types(forKey key: String) throws -> [Type] { - // In some configurations, the types are keyed by "ModuleName.TypeName" - var longKey: String? + // sourcery: skipEquality, skipDescription + /// Whether return value type is implicitly unwrapped optional + public var isImplicitlyUnwrappedOptionalReturnType: Bool { + return returnTypeName.isImplicitlyUnwrappedOptional + } - if let validate = validate { - guard let type = all.first(where: { $0.name == key }) else { - throw "Unknown type \\(key), should be used with `based`" - } + // sourcery: skipEquality, skipDescription + /// Return value type name without attributes and optional type information + public var unwrappedReturnTypeName: String { + return returnTypeName.unwrappedTypeName + } - try validate(type) + /// Whether method is async method + public let isAsync: Bool - if let module = type.module { - longKey = [module, type.name].joined(separator: ".") - } - } + /// Whether method throws + public let `throws`: Bool - // If we find the types directly, return them - if let types = types[key] { - return types - } + /// Whether method rethrows + public let `rethrows`: Bool - // if we find a types for the longKey, return them - if let longKey = longKey, let types = types[longKey] { - return types - } + /// Method access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` + public let accessLevel: String - return [] - } + /// Whether method is a static method + public let isStatic: Bool - /// :nodoc: - public func value(forKey key: String) -> Any? { - do { - return try types(forKey: key) - } catch { - Log.error(error) - return nil - } - } + /// Whether method is a class method + public let isClass: Bool - /// :nodoc: - public subscript(_ key: String) -> [Type] { - do { - return try types(forKey: key) - } catch { - Log.error(error) - return [] - } + // sourcery: skipEquality, skipDescription + /// Whether method is an initializer + public var isInitializer: Bool { + return selectorName.hasPrefix("init(") || selectorName == "init" } -} -"""), - .init(name: "Tuple.swift", content: -""" -import Foundation + // sourcery: skipEquality, skipDescription + /// Whether method is an deinitializer + public var isDeinitializer: Bool { + return selectorName == "deinit" + } -/// Describes tuple type -public final class TupleType: NSObject, SourceryModel, Diffable { + /// Whether method is a failable initializer + public let isFailableInitializer: Bool - /// Type name used in declaration - public var name: String + // sourcery: skipEquality, skipDescription + /// Whether method is a convenience initializer + public var isConvenienceInitializer: Bool { + modifiers.contains { $0.name == Attribute.Identifier.convenience.rawValue } + } - /// Tuple elements - public var elements: [TupleElement] + // sourcery: skipEquality, skipDescription + /// Whether method is required + public var isRequired: Bool { + modifiers.contains { $0.name == Attribute.Identifier.required.rawValue } + } - /// :nodoc: - public init(name: String, elements: [TupleElement]) { - self.name = name - self.elements = elements + // sourcery: skipEquality, skipDescription + /// Whether method is final + public var isFinal: Bool { + modifiers.contains { $0.name == Attribute.Identifier.final.rawValue } } - /// :nodoc: - public init(elements: [TupleElement]) { - self.name = elements.asSource - self.elements = elements + // sourcery: skipEquality, skipDescription + /// Whether method is mutating + public var isMutating: Bool { + modifiers.contains { $0.name == Attribute.Identifier.mutating.rawValue } } - /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "name = \\(String(describing: self.name)), " - string += "elements = \\(String(describing: self.elements))" - return string + // sourcery: skipEquality, skipDescription + /// Whether method is generic + public var isGeneric: Bool { + shortName.hasSuffix(">") } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? TupleType else { - results.append("Incorrect type ") - return results - } - results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "elements").trackDifference(actual: self.elements, expected: castObject.elements)) - return results + // sourcery: skipEquality, skipDescription + /// Whether method is optional (in an Objective-C protocol) + public var isOptional: Bool { + modifiers.contains { $0.name == Attribute.Identifier.optional.rawValue } } - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.name) - hasher.combine(self.elements) - return hasher.finalize() + // sourcery: skipEquality, skipDescription + /// Whether method is nonisolated (this modifier only applies to actor methods) + public var isNonisolated: Bool { + modifiers.contains { $0.name == Attribute.Identifier.nonisolated.rawValue } } - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? TupleType else { return false } - if self.name != rhs.name { return false } - if self.elements != rhs.elements { return false } - return true + // sourcery: skipEquality, skipDescription + /// Whether method is dynamic + public var isDynamic: Bool { + modifiers.contains { $0.name == Attribute.Identifier.dynamic.rawValue } } -// sourcery:inline:TupleType.AutoCoding + /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 + public let annotations: Annotations - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { - withVaList(["name"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.name = name - guard let elements: [TupleElement] = aDecoder.decode(forKey: "elements") else { - withVaList(["elements"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.elements = elements - } + public let documentation: Documentation - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.elements, forKey: "elements") - } -// sourcery:end -} + /// Reference to type name where the method is defined, + /// nil if defined outside of any `enum`, `struct`, `class` etc + public let definedInTypeName: TypeName? -/// Describes tuple type element -public final class TupleElement: NSObject, SourceryModel, Typed, Diffable { + // sourcery: skipEquality, skipDescription + /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` + public var actualDefinedInTypeName: TypeName? { + return definedInTypeName?.actualTypeName ?? definedInTypeName + } - /// Tuple element name - public let name: String? + // sourcery: skipEquality, skipDescription + /// Reference to actual type where the object is defined, + /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown + public var definedInType: Type? - /// Tuple element type name - public var typeName: TypeName + /// Method attributes, i.e. `@discardableResult` + public let attributes: AttributeList - // sourcery: skipEquality, skipDescription - /// Tuple element type, if known - public var type: Type? + /// Method modifiers, i.e. `private` + public let modifiers: [SourceryModifier] + // Underlying parser data, never to be used by anything else + // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: - public init(name: String? = nil, typeName: TypeName, type: Type? = nil) { - self.name = name - self.typeName = typeName - self.type = type - } + public var __parserData: Any? - public var asSource: String { - // swiftlint:disable:next force_unwrapping - "\\(name != nil ? "\\(name!): " : "")\\(typeName.asSource)" + /// list of generic requirements + public var genericRequirements: [GenericRequirement] + + /// :nodoc: + public init(name: String, + selectorName: String? = nil, + parameters: [MethodParameter] = [], + returnTypeName: TypeName = TypeName(name: "Void"), + isAsync: Bool = false, + throws: Bool = false, + rethrows: Bool = false, + accessLevel: AccessLevel = .internal, + isStatic: Bool = false, + isClass: Bool = false, + isFailableInitializer: Bool = false, + attributes: AttributeList = [:], + modifiers: [SourceryModifier] = [], + annotations: [String: NSObject] = [:], + documentation: [String] = [], + definedInTypeName: TypeName? = nil, + genericRequirements: [GenericRequirement] = []) { + self.name = name + self.selectorName = selectorName ?? name + self.parameters = parameters + self.returnTypeName = returnTypeName + self.isAsync = isAsync + self.throws = `throws` + self.rethrows = `rethrows` + self.accessLevel = accessLevel.rawValue + self.isStatic = isStatic + self.isClass = isClass + self.isFailableInitializer = isFailableInitializer + self.attributes = attributes + self.modifiers = modifiers + self.annotations = annotations + self.documentation = documentation + self.definedInTypeName = definedInTypeName + self.genericRequirements = genericRequirements } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " - string += "name = \\(String(describing: self.name)), " - string += "typeName = \\(String(describing: self.typeName)), " - string += "asSource = \\(String(describing: self.asSource))" + string.append("name = \\(String(describing: self.name)), ") + string.append("selectorName = \\(String(describing: self.selectorName)), ") + string.append("parameters = \\(String(describing: self.parameters)), ") + string.append("returnTypeName = \\(String(describing: self.returnTypeName)), ") + string.append("isAsync = \\(String(describing: self.isAsync)), ") + string.append("`throws` = \\(String(describing: self.`throws`)), ") + string.append("`rethrows` = \\(String(describing: self.`rethrows`)), ") + string.append("accessLevel = \\(String(describing: self.accessLevel)), ") + string.append("isStatic = \\(String(describing: self.isStatic)), ") + string.append("isClass = \\(String(describing: self.isClass)), ") + string.append("isFailableInitializer = \\(String(describing: self.isFailableInitializer)), ") + string.append("annotations = \\(String(describing: self.annotations)), ") + string.append("documentation = \\(String(describing: self.documentation)), ") + string.append("definedInTypeName = \\(String(describing: self.definedInTypeName)), ") + string.append("attributes = \\(String(describing: self.attributes)), ") + string.append("modifiers = \\(String(describing: self.modifiers))") + string.append("genericRequirements = \\(String(describing: self.genericRequirements))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() - guard let castObject = object as? TupleElement else { - results.append("Incorrect type ") + guard let castObject = object as? Method else { + results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) + results.append(contentsOf: DiffableResult(identifier: "selectorName").trackDifference(actual: self.selectorName, expected: castObject.selectorName)) + results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) + results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) + results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) + results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) + results.append(contentsOf: DiffableResult(identifier: "`rethrows`").trackDifference(actual: self.`rethrows`, expected: castObject.`rethrows`)) + results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) + results.append(contentsOf: DiffableResult(identifier: "isStatic").trackDifference(actual: self.isStatic, expected: castObject.isStatic)) + results.append(contentsOf: DiffableResult(identifier: "isClass").trackDifference(actual: self.isClass, expected: castObject.isClass)) + results.append(contentsOf: DiffableResult(identifier: "isFailableInitializer").trackDifference(actual: self.isFailableInitializer, expected: castObject.isFailableInitializer)) + results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) + results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) + results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) + results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) + results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) + results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) - hasher.combine(self.typeName) + hasher.combine(self.selectorName) + hasher.combine(self.parameters) + hasher.combine(self.returnTypeName) + hasher.combine(self.isAsync) + hasher.combine(self.`throws`) + hasher.combine(self.`rethrows`) + hasher.combine(self.accessLevel) + hasher.combine(self.isStatic) + hasher.combine(self.isClass) + hasher.combine(self.isFailableInitializer) + hasher.combine(self.annotations) + hasher.combine(self.documentation) + hasher.combine(self.definedInTypeName) + hasher.combine(self.attributes) + hasher.combine(self.modifiers) + hasher.combine(self.genericRequirements) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? TupleElement else { return false } + guard let rhs = object as? Method else { return false } if self.name != rhs.name { return false } - if self.typeName != rhs.typeName { return false } + if self.selectorName != rhs.selectorName { return false } + if self.parameters != rhs.parameters { return false } + if self.returnTypeName != rhs.returnTypeName { return false } + if self.isAsync != rhs.isAsync { return false } + if self.`throws` != rhs.`throws` { return false } + if self.`rethrows` != rhs.`rethrows` { return false } + if self.accessLevel != rhs.accessLevel { return false } + if self.isStatic != rhs.isStatic { return false } + if self.isClass != rhs.isClass { return false } + if self.isFailableInitializer != rhs.isFailableInitializer { return false } + if self.annotations != rhs.annotations { return false } + if self.documentation != rhs.documentation { return false } + if self.definedInTypeName != rhs.definedInTypeName { return false } + if self.attributes != rhs.attributes { return false } + if self.modifiers != rhs.modifiers { return false } + if self.genericRequirements != rhs.genericRequirements { return false } return true } -// sourcery:inline:TupleElement.AutoCoding +// sourcery:inline:Method.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { - self.name = aDecoder.decode(forKey: "name") - guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { - withVaList(["typeName"]) { arguments in + guard let name: String = aDecoder.decode(forKey: "name") else { + withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.typeName = typeName - self.type = aDecoder.decode(forKey: "type") + }; self.name = name + guard let selectorName: String = aDecoder.decode(forKey: "selectorName") else { + withVaList(["selectorName"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.selectorName = selectorName + guard let parameters: [MethodParameter] = aDecoder.decode(forKey: "parameters") else { + withVaList(["parameters"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.parameters = parameters + guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { + withVaList(["returnTypeName"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.returnTypeName = returnTypeName + self.returnType = aDecoder.decode(forKey: "returnType") + self.isAsync = aDecoder.decode(forKey: "isAsync") + self.`throws` = aDecoder.decode(forKey: "`throws`") + self.`rethrows` = aDecoder.decode(forKey: "`rethrows`") + guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { + withVaList(["accessLevel"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.accessLevel = accessLevel + self.isStatic = aDecoder.decode(forKey: "isStatic") + self.isClass = aDecoder.decode(forKey: "isClass") + self.isFailableInitializer = aDecoder.decode(forKey: "isFailableInitializer") + guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { + withVaList(["annotations"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.annotations = annotations + guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { + withVaList(["documentation"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.documentation = documentation + self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") + self.definedInType = aDecoder.decode(forKey: "definedInType") + guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { + withVaList(["attributes"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.attributes = attributes + guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { + withVaList(["modifiers"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.modifiers = modifiers + guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { + withVaList(["genericRequirements"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.genericRequirements = genericRequirements } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.typeName, forKey: "typeName") - aCoder.encode(self.type, forKey: "type") - } -// sourcery:end -} + aCoder.encode(self.selectorName, forKey: "selectorName") + aCoder.encode(self.parameters, forKey: "parameters") + aCoder.encode(self.returnTypeName, forKey: "returnTypeName") + aCoder.encode(self.returnType, forKey: "returnType") + aCoder.encode(self.isAsync, forKey: "isAsync") + aCoder.encode(self.`throws`, forKey: "`throws`") + aCoder.encode(self.`rethrows`, forKey: "`rethrows`") + aCoder.encode(self.accessLevel, forKey: "accessLevel") + aCoder.encode(self.isStatic, forKey: "isStatic") + aCoder.encode(self.isClass, forKey: "isClass") + aCoder.encode(self.isFailableInitializer, forKey: "isFailableInitializer") + aCoder.encode(self.annotations, forKey: "annotations") + aCoder.encode(self.documentation, forKey: "documentation") + aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") + aCoder.encode(self.definedInType, forKey: "definedInType") + aCoder.encode(self.attributes, forKey: "attributes") + aCoder.encode(self.modifiers, forKey: "modifiers") + aCoder.encode(self.genericRequirements, forKey: "genericRequirements") + } +// sourcery:end +} +#endif -extension Array where Element == TupleElement { - public var asSource: String { - "(\\(map { $0.asSource }.joined(separator: ", ")))" +"""), + .init(name: "NSException_Linux.swift", content: +""" +#if !canImport(ObjectiveC) +import Foundation + +public class NSException { + static func raise(_ name: String, format: String, arguments: CVaListPointer) { + fatalError ("\\(name) exception: \\(NSString(format: format, arguments: arguments))") } - public var asTypeName: String { - "(\\(map { $0.typeName.asSource }.joined(separator: ", ")))" + static func raise(_ name: String) { + fatalError("\\(name) exception") } } +public extension NSExceptionName { + static var parseErrorException = "parseErrorException" +} +#endif + """), - .init(name: "Type.swift", content: + .init(name: "Subscript_Linux.swift", content: """ -// -// Created by Krzysztof Zablocki on 11/09/2016. -// Copyright (c) 2016 Pixle. All rights reserved. -// - +#if !canImport(ObjectiveC) import Foundation -/// :nodoc: -public typealias AttributeList = [String: [Attribute]] +/// Describes subscript +public final class Subscript: NSObject, SourceryModel, Annotated, Documented, Definition, Diffable, SourceryDynamicMemberLookup { -/// Defines Swift type -public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable { public subscript(dynamicMember member: String) -> Any? { switch member { - case "implements": - return implements - case "name": - return name - case "kind": - return kind - case "based": - return based - case "supertype": - return supertype - case "accessLevel": - return accessLevel - case "storedVariables": - return storedVariables - case "variables": - return variables - case "allVariables": - return allVariables - case "allMethods": - return allMethods + case "parameters": + return parameters + case "returnTypeName": + return returnTypeName + case "actualReturnTypeName": + return actualReturnTypeName + case "returnType": + return returnType + case "isOptionalReturnType": + return isOptionalReturnType + case "isImplicitlyUnwrappedOptionalReturnType": + return isImplicitlyUnwrappedOptionalReturnType + case "unwrappedReturnTypeName": + return unwrappedReturnTypeName + case "isFinal": + return isFinal + case "readAccess": + return readAccess + case "writeAccess": + return writeAccess + case "isAsync": + return isAsync + case "throws": + return `throws` + case "isMutable": + return isMutable case "annotations": return annotations - case "methods": - return methods - case "containedType": - return containedType - case "computedVariables": - return computedVariables - case "inherits": - return inherits - case "inheritedTypes": - return inheritedTypes - case "subscripts": - return subscripts - case "rawSubscripts": - return rawSubscripts - case "allSubscripts": - return allSubscripts + case "documentation": + return documentation + case "definedInTypeName": + return definedInTypeName + case "actualDefinedInTypeName": + return actualDefinedInTypeName + case "attributes": + return attributes + case "modifiers": + return modifiers + case "genericParameters": + return genericParameters case "genericRequirements": return genericRequirements + case "isGeneric": + return isGeneric default: fatalError("unable to lookup: \\(member) in \\(self)") } } - /// :nodoc: - public var module: String? + /// Method parameters + public var parameters: [MethodParameter] - /// Imports that existed in the file that contained this type declaration - public var imports: [Import] = [] + /// Return value type name used in declaration, including generic constraints, i.e. `where T: Equatable` + public var returnTypeName: TypeName - // sourcery: skipEquality - /// Imports existed in all files containing this type and all its super classes/protocols - public var allImports: [Import] { - return self.unique({ $0.gatherAllImports() }, filter: { $0 == $1 }) + /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` + public var actualReturnTypeName: TypeName { + return returnTypeName.actualTypeName ?? returnTypeName } - private func gatherAllImports() -> [Import] { - var allImports: [Import] = Array(self.imports) + // sourcery: skipEquality, skipDescription + /// Actual return value type, if known + public var returnType: Type? - self.basedTypes.values.forEach { (basedType) in - allImports.append(contentsOf: basedType.imports) - } - return allImports + // sourcery: skipEquality, skipDescription + /// Whether return value type is optional + public var isOptionalReturnType: Bool { + return returnTypeName.isOptional } - // All local typealiases - /// :nodoc: - public var typealiases: [String: Typealias] { - didSet { - typealiases.values.forEach { $0.parent = self } - } + // sourcery: skipEquality, skipDescription + /// Whether return value type is implicitly unwrapped optional + public var isImplicitlyUnwrappedOptionalReturnType: Bool { + return returnTypeName.isImplicitlyUnwrappedOptional } - // sourcery: skipJSExport - /// Whether declaration is an extension of some type - public var isExtension: Bool - - // sourcery: forceEquality - /// Kind of type declaration, i.e. `enum`, `struct`, `class`, `protocol` or `extension` - public var kind: String { isExtension ? "extension" : "unknown" } - - /// Type access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` - public let accessLevel: String + // sourcery: skipEquality, skipDescription + /// Return value type name without attributes and optional type information + public var unwrappedReturnTypeName: String { + return returnTypeName.unwrappedTypeName + } - /// Type name in global scope. For inner types includes the name of its containing type, i.e. `Type.Inner` - public var name: String { - guard let parentName = parent?.name else { return localName } - return "\\(parentName).\\(localName)" + /// Whether method is final + public var isFinal: Bool { + modifiers.contains { $0.name == "final" } } - // sourcery: skipCoding - /// Whether the type has been resolved as unknown extension - public var isUnknownExtension: Bool = false + /// Variable read access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` + public let readAccess: String - // sourcery: skipDescription - /// Global type name including module name, unless it's an extension of unknown type - public var globalName: String { - guard let module = module, !isUnknownExtension else { return name } - return "\\(module).\\(name)" - } + /// Variable write access, i.e. `internal`, `private`, `fileprivate`, `public`, `open`. + /// For immutable variables this value is empty string + public var writeAccess: String - /// Whether type is generic - public var isGeneric: Bool + /// Whether subscript is async + public let isAsync: Bool - /// Type name in its own scope. - public var localName: String + /// Whether subscript throws + public let `throws`: Bool - // sourcery: skipEquality, skipDescription - /// Variables defined in this type only, inluding variables defined in its extensions, - /// but not including variables inherited from superclasses (for classes only) and protocols - public var variables: [Variable] { - unique({ $0.rawVariables }, filter: Self.uniqueVariableFilter) + /// Whether variable is mutable or not + public var isMutable: Bool { + return writeAccess != AccessLevel.none.rawValue } - /// Unfiltered (can contain duplications from extensions) variables defined in this type only, inluding variables defined in its extensions, - /// but not including variables inherited from superclasses (for classes only) and protocols - public var rawVariables: [Variable] + /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 + public let annotations: Annotations - // sourcery: skipEquality, skipDescription - /// All variables defined for this type, including variables defined in extensions, - /// in superclasses (for classes only) and protocols - public var allVariables: [Variable] { - return flattenAll({ - return $0.variables - }, - isExtension: { $0.definedInType?.isExtension == true }, - filter: { all, extracted in - !all.contains(where: { Self.uniqueVariableFilter($0, rhs: extracted) }) - }) - } + public let documentation: Documentation - private static func uniqueVariableFilter(_ lhs: Variable, rhs: Variable) -> Bool { - return lhs.name == rhs.name && lhs.isStatic == rhs.isStatic && lhs.typeName == rhs.typeName - } + /// Reference to type name where the method is defined, + /// nil if defined outside of any `enum`, `struct`, `class` etc + public let definedInTypeName: TypeName? - // sourcery: skipEquality, skipDescription - /// Methods defined in this type only, inluding methods defined in its extensions, - /// but not including methods inherited from superclasses (for classes only) and protocols - public var methods: [Method] { - unique({ $0.rawMethods }, filter: Self.uniqueMethodFilter) + /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` + public var actualDefinedInTypeName: TypeName? { + return definedInTypeName?.actualTypeName ?? definedInTypeName } - /// Unfiltered (can contain duplications from extensions) methods defined in this type only, inluding methods defined in its extensions, - /// but not including methods inherited from superclasses (for classes only) and protocols - public var rawMethods: [Method] - // sourcery: skipEquality, skipDescription - /// All methods defined for this type, including methods defined in extensions, - /// in superclasses (for classes only) and protocols - public var allMethods: [Method] { - return flattenAll({ - $0.methods - }, - isExtension: { $0.definedInType?.isExtension == true }, - filter: { all, extracted in - !all.contains(where: { Self.uniqueMethodFilter($0, rhs: extracted) }) - }) - } + /// Reference to actual type where the object is defined, + /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown + public var definedInType: Type? - private static func uniqueMethodFilter(_ lhs: Method, rhs: Method) -> Bool { - return lhs.name == rhs.name && lhs.isStatic == rhs.isStatic && lhs.isClass == rhs.isClass && lhs.actualReturnTypeName == rhs.actualReturnTypeName - } + /// Method attributes, i.e. `@discardableResult` + public let attributes: AttributeList - // sourcery: skipEquality, skipDescription - /// Subscripts defined in this type only, inluding subscripts defined in its extensions, - /// but not including subscripts inherited from superclasses (for classes only) and protocols - public var subscripts: [Subscript] { - unique({ $0.rawSubscripts }, filter: Self.uniqueSubscriptFilter) - } + /// Method modifiers, i.e. `private` + public let modifiers: [SourceryModifier] - /// Unfiltered (can contain duplications from extensions) Subscripts defined in this type only, inluding subscripts defined in its extensions, - /// but not including subscripts inherited from superclasses (for classes only) and protocols - public var rawSubscripts: [Subscript] + /// list of generic parameters + public let genericParameters: [GenericParameter] - // sourcery: skipEquality, skipDescription - /// All subscripts defined for this type, including subscripts defined in extensions, - /// in superclasses (for classes only) and protocols - public var allSubscripts: [Subscript] { - return flattenAll({ $0.subscripts }, - isExtension: { $0.definedInType?.isExtension == true }, - filter: { all, extracted in - !all.contains(where: { Self.uniqueSubscriptFilter($0, rhs: extracted) }) - }) - } + /// list of generic requirements + public let genericRequirements: [GenericRequirement] - private static func uniqueSubscriptFilter(_ lhs: Subscript, rhs: Subscript) -> Bool { - return lhs.parameters == rhs.parameters && lhs.returnTypeName == rhs.returnTypeName && lhs.readAccess == rhs.readAccess && lhs.writeAccess == rhs.writeAccess + /// Whether subscript is generic or not + public var isGeneric: Bool { + return genericParameters.isEmpty == false } - // sourcery: skipEquality, skipDescription, skipJSExport - /// Bytes position of the body of this type in its declaration file if available. - public var bodyBytesRange: BytesRange? - - // sourcery: skipEquality, skipDescription, skipJSExport - /// Bytes position of the whole declaration of this type in its declaration file if available. - public var completeDeclarationRange: BytesRange? + // Underlying parser data, never to be used by anything else + // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport + /// :nodoc: + public var __parserData: Any? - private func flattenAll(_ extraction: @escaping (Type) -> [T], isExtension: (T) -> Bool, filter: ([T], T) -> Bool) -> [T] { - let all = NSMutableOrderedSet() - let allObjects = extraction(self) + /// :nodoc: + public init(parameters: [MethodParameter] = [], + returnTypeName: TypeName, + accessLevel: (read: AccessLevel, write: AccessLevel) = (.internal, .internal), + isAsync: Bool = false, + `throws`: Bool = false, + genericParameters: [GenericParameter] = [], + genericRequirements: [GenericRequirement] = [], + attributes: AttributeList = [:], + modifiers: [SourceryModifier] = [], + annotations: [String: NSObject] = [:], + documentation: [String] = [], + definedInTypeName: TypeName? = nil) { - /// The order of importance for properties is: - /// Base class - /// Inheritance - /// Protocol conformance - /// Extension + self.parameters = parameters + self.returnTypeName = returnTypeName + self.readAccess = accessLevel.read.rawValue + self.writeAccess = accessLevel.write.rawValue + self.isAsync = isAsync + self.throws = `throws` + self.genericParameters = genericParameters + self.genericRequirements = genericRequirements + self.attributes = attributes + self.modifiers = modifiers + self.annotations = annotations + self.documentation = documentation + self.definedInTypeName = definedInTypeName + } - var extensions = [T]() - var baseObjects = [T]() + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("parameters = \\(String(describing: self.parameters)), ") + string.append("returnTypeName = \\(String(describing: self.returnTypeName)), ") + string.append("actualReturnTypeName = \\(String(describing: self.actualReturnTypeName)), ") + string.append("isFinal = \\(String(describing: self.isFinal)), ") + string.append("readAccess = \\(String(describing: self.readAccess)), ") + string.append("writeAccess = \\(String(describing: self.writeAccess)), ") + string.append("isAsync = \\(String(describing: self.isAsync)), ") + string.append("`throws` = \\(String(describing: self.throws)), ") + string.append("isMutable = \\(String(describing: self.isMutable)), ") + string.append("annotations = \\(String(describing: self.annotations)), ") + string.append("documentation = \\(String(describing: self.documentation)), ") + string.append("definedInTypeName = \\(String(describing: self.definedInTypeName)), ") + string.append("actualDefinedInTypeName = \\(String(describing: self.actualDefinedInTypeName)), ") + string.append("genericParameters = \\(String(describing: self.genericParameters)), ") + string.append("genericRequirements = \\(String(describing: self.genericRequirements)), ") + string.append("isGeneric = \\(String(describing: self.isGeneric)), ") + string.append("attributes = \\(String(describing: self.attributes)), ") + string.append("modifiers = \\(String(describing: self.modifiers))") + return string + } - allObjects.forEach { - if isExtension($0) { - extensions.append($0) - } else { - baseObjects.append($0) - } + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? Subscript else { + results.append("Incorrect type ") + return results } + results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) + results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) + results.append(contentsOf: DiffableResult(identifier: "readAccess").trackDifference(actual: self.readAccess, expected: castObject.readAccess)) + results.append(contentsOf: DiffableResult(identifier: "writeAccess").trackDifference(actual: self.writeAccess, expected: castObject.writeAccess)) + results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) + results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.throws, expected: castObject.throws)) + results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) + results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) + results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) + results.append(contentsOf: DiffableResult(identifier: "genericParameters").trackDifference(actual: self.genericParameters, expected: castObject.genericParameters)) + results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) + results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) + results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) + return results + } - all.addObjects(from: baseObjects) + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.parameters) + hasher.combine(self.returnTypeName) + hasher.combine(self.readAccess) + hasher.combine(self.writeAccess) + hasher.combine(self.isAsync) + hasher.combine(self.throws) + hasher.combine(self.annotations) + hasher.combine(self.documentation) + hasher.combine(self.definedInTypeName) + hasher.combine(self.genericParameters) + hasher.combine(self.genericRequirements) + hasher.combine(self.attributes) + hasher.combine(self.modifiers) + return hasher.finalize() + } - func filteredExtraction(_ target: Type) -> [T] { - // swiftlint:disable:next force_cast - let all = all.array as! [T] - let extracted = extraction(target).filter({ filter(all, $0) }) - return extracted + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? Subscript else { return false } + if self.parameters != rhs.parameters { return false } + if self.returnTypeName != rhs.returnTypeName { return false } + if self.readAccess != rhs.readAccess { return false } + if self.writeAccess != rhs.writeAccess { return false } + if self.isAsync != rhs.isAsync { return false } + if self.throws != rhs.throws { return false } + if self.annotations != rhs.annotations { return false } + if self.documentation != rhs.documentation { return false } + if self.definedInTypeName != rhs.definedInTypeName { return false } + if self.genericParameters != rhs.genericParameters { return false } + if self.genericRequirements != rhs.genericRequirements { return false } + if self.attributes != rhs.attributes { return false } + if self.modifiers != rhs.modifiers { return false } + return true + } + +// sourcery:inline:Subscript.AutoCoding + + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let parameters: [MethodParameter] = aDecoder.decode(forKey: "parameters") else { + withVaList(["parameters"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.parameters = parameters + guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { + withVaList(["returnTypeName"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.returnTypeName = returnTypeName + self.returnType = aDecoder.decode(forKey: "returnType") + guard let readAccess: String = aDecoder.decode(forKey: "readAccess") else { + withVaList(["readAccess"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.readAccess = readAccess + guard let writeAccess: String = aDecoder.decode(forKey: "writeAccess") else { + withVaList(["writeAccess"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.writeAccess = writeAccess + self.isAsync = aDecoder.decode(forKey: "isAsync") + self.`throws` = aDecoder.decode(forKey: "`throws`") + guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { + withVaList(["annotations"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.annotations = annotations + guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { + withVaList(["documentation"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.documentation = documentation + self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") + self.definedInType = aDecoder.decode(forKey: "definedInType") + guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { + withVaList(["attributes"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.attributes = attributes + guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { + withVaList(["modifiers"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.modifiers = modifiers + guard let genericParameters: [GenericParameter] = aDecoder.decode(forKey: "genericParameters") else { + withVaList(["genericParameters"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.genericParameters = genericParameters + guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { + withVaList(["genericRequirements"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.genericRequirements = genericRequirements } - inherits.values.sorted(by: { $0.name < $1.name }).forEach { all.addObjects(from: filteredExtraction($0)) } - implements.values.sorted(by: { $0.name < $1.name }).forEach { all.addObjects(from: filteredExtraction($0)) } + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.parameters, forKey: "parameters") + aCoder.encode(self.returnTypeName, forKey: "returnTypeName") + aCoder.encode(self.returnType, forKey: "returnType") + aCoder.encode(self.readAccess, forKey: "readAccess") + aCoder.encode(self.writeAccess, forKey: "writeAccess") + aCoder.encode(self.isAsync, forKey: "isAsync") + aCoder.encode(self.`throws`, forKey: "`throws`") + aCoder.encode(self.annotations, forKey: "annotations") + aCoder.encode(self.documentation, forKey: "documentation") + aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") + aCoder.encode(self.definedInType, forKey: "definedInType") + aCoder.encode(self.attributes, forKey: "attributes") + aCoder.encode(self.modifiers, forKey: "modifiers") + aCoder.encode(self.genericParameters, forKey: "genericParameters") + aCoder.encode(self.genericRequirements, forKey: "genericRequirements") + } +// sourcery:end - // swiftlint:disable:next force_cast - let array = all.array as! [T] - all.addObjects(from: extensions.filter({ filter(array, $0) })) +} +#endif - return all.array.compactMap { $0 as? T } - } +"""), + .init(name: "Tuple_Linux.swift", content: +""" +#if !canImport(ObjectiveC) +import Foundation - private func unique(_ extraction: @escaping (Type) -> [T], filter: (T, T) -> Bool) -> [T] { - let all = NSMutableOrderedSet() - for nextItem in extraction(self) { - // swiftlint:disable:next force_cast - if !all.contains(where: { filter($0 as! T, nextItem) }) { - all.add(nextItem) - } +/// Describes tuple type +public final class TupleType: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { + public subscript(dynamicMember member: String) -> Any? { + switch member { + case "elements": + return elements + default: + fatalError("unable to lookup: \\(member) in \\(self)") } - - return all.array.compactMap { $0 as? T } } - /// All initializers defined in this type - public var initializers: [Method] { - return methods.filter { $0.isInitializer } - } + /// Type name used in declaration + public var name: String - /// All annotations for this type - public var annotations: Annotations = [:] - - public var documentation: Documentation = [] + /// Tuple elements + public var elements: [TupleElement] - /// Static variables defined in this type - public var staticVariables: [Variable] { - return variables.filter { $0.isStatic } + /// :nodoc: + public init(name: String, elements: [TupleElement]) { + self.name = name + self.elements = elements } - /// Static methods defined in this type - public var staticMethods: [Method] { - return methods.filter { $0.isStatic } + /// :nodoc: + public init(elements: [TupleElement]) { + self.name = elements.asSource + self.elements = elements } - /// Class methods defined in this type - public var classMethods: [Method] { - return methods.filter { $0.isClass } + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("name = \\(String(describing: self.name)), ") + string.append("elements = \\(String(describing: self.elements))") + return string } - /// Instance variables defined in this type - public var instanceVariables: [Variable] { - return variables.filter { !$0.isStatic } + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? TupleType else { + results.append("Incorrect type ") + return results + } + results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) + results.append(contentsOf: DiffableResult(identifier: "elements").trackDifference(actual: self.elements, expected: castObject.elements)) + return results } - /// Instance methods defined in this type - public var instanceMethods: [Method] { - return methods.filter { !$0.isStatic && !$0.isClass } + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.name) + hasher.combine(self.elements) + return hasher.finalize() } - /// Computed instance variables defined in this type - public var computedVariables: [Variable] { - return variables.filter { $0.isComputed && !$0.isStatic } + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? TupleType else { return false } + if self.name != rhs.name { return false } + if self.elements != rhs.elements { return false } + return true } - /// Stored instance variables defined in this type - public var storedVariables: [Variable] { - return variables.filter { !$0.isComputed && !$0.isStatic } - } +// sourcery:inline:TupleType.AutoCoding - /// Names of types this type inherits from (for classes only) and protocols it implements, in order of definition - public var inheritedTypes: [String] { - didSet { - based.removeAll() - inheritedTypes.forEach { name in - self.based[name] = name - } + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let name: String = aDecoder.decode(forKey: "name") else { + withVaList(["name"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.name = name + guard let elements: [TupleElement] = aDecoder.decode(forKey: "elements") else { + withVaList(["elements"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.elements = elements } - } - // sourcery: skipEquality, skipDescription - /// Names of types or protocols this type inherits from, including unknown (not scanned) types - public var based = [String: String]() + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.elements, forKey: "elements") + } +// sourcery:end +} - // sourcery: skipEquality, skipDescription - /// Types this type inherits from or implements, including unknown (not scanned) types with extensions defined - public var basedTypes = [String: Type]() +/// Describes tuple type element +public final class TupleElement: NSObject, SourceryModel, Typed, Diffable, SourceryDynamicMemberLookup { + public subscript(dynamicMember member: String) -> Any? { + switch member { + case "name": + return name + case "typeName": + return typeName + case "type": + return type + default: + fatalError("unable to lookup: \\(member) in \\(self)") + } + } - /// Types this type inherits from - public var inherits = [String: Type]() + /// Tuple element name + public let name: String? + + /// Tuple element type name + public var typeName: TypeName // sourcery: skipEquality, skipDescription - /// Protocols this type implements - public var implements = [String: Type]() + /// Tuple element type, if known + public var type: Type? - /// Contained types - public var containedTypes: [Type] { - didSet { - containedTypes.forEach { - containedType[$0.localName] = $0 - $0.parent = self - } - } + /// :nodoc: + public init(name: String? = nil, typeName: TypeName, type: Type? = nil) { + self.name = name + self.typeName = typeName + self.type = type } - // sourcery: skipEquality, skipDescription - /// Contained types groupd by their names - public private(set) var containedType: [String: Type] = [:] + public var asSource: String { + // swiftlint:disable:next force_unwrapping + "\\(name != nil ? "\\(name!): " : "")\\(typeName.asSource)" + } - /// Name of parent type (for contained types only) - public private(set) var parentName: String? + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("name = \\(String(describing: self.name)), ") + string.append("typeName = \\(String(describing: self.typeName)), ") + string.append("asSource = \\(String(describing: self.asSource))") + return string + } - // sourcery: skipEquality, skipDescription - /// Parent type, if known (for contained types only) - public var parent: Type? { - didSet { - parentName = parent?.name + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? TupleElement else { + results.append("Incorrect type ") + return results } + results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) + results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) + return results } - // sourcery: skipJSExport /// :nodoc: - public var parentTypes: AnyIterator { - var next: Type? = self - return AnyIterator { - next = next?.parent - return next - } + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.name) + hasher.combine(self.typeName) + return hasher.finalize() } - // sourcery: skipEquality, skipDescription - /// Superclass type, if known (only for classes) - public var supertype: Type? + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? TupleElement else { return false } + if self.name != rhs.name { return false } + if self.typeName != rhs.typeName { return false } + return true + } - /// Type attributes, i.e. `@objc` - public var attributes: AttributeList +// sourcery:inline:TupleElement.AutoCoding - /// Type modifiers, i.e. `private`, `final` - public var modifiers: [SourceryModifier] + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + self.name = aDecoder.decode(forKey: "name") + guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { + withVaList(["typeName"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.typeName = typeName + self.type = aDecoder.decode(forKey: "type") + } - /// Path to file where the type is defined - // sourcery: skipDescription, skipEquality, skipJSExport - public var path: String? { - didSet { - if let path = path { - fileName = (path as NSString).lastPathComponent - } + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.typeName, forKey: "typeName") + aCoder.encode(self.type, forKey: "type") } +// sourcery:end +} + +extension Array where Element == TupleElement { + public var asSource: String { + "(\\(map { $0.asSource }.joined(separator: ", ")))" } - /// Directory to file where the type is defined - // sourcery: skipDescription, skipEquality, skipJSExport - public var directory: String? { - get { - return (path as? NSString)?.deletingLastPathComponent - } + public var asTypeName: String { + "(\\(map { $0.typeName.asSource }.joined(separator: ", ")))" } +} +#endif - /// list of generic requirements - public var genericRequirements: [GenericRequirement] { - didSet { - isGeneric = isGeneric || !genericRequirements.isEmpty +"""), + .init(name: "TypeName_Linux.swift", content: +""" +// +// Created by Krzysztof Zabłocki on 25/12/2016. +// Copyright (c) 2016 Pixle. All rights reserved. +// +#if !canImport(ObjectiveC) +import Foundation + +/// Describes name of the type used in typed declaration (variable, method parameter or return value etc.) +public final class TypeName: NSObject, SourceryModelWithoutDescription, LosslessStringConvertible, Diffable, SourceryDynamicMemberLookup { + public subscript(dynamicMember member: String) -> Any? { + switch member { + case "tuple": + return tuple + case "name": + return name + case "isOptional": + return isOptional + case "unwrappedTypeName": + return unwrappedTypeName + case "isProtocolComposition": + return isProtocolComposition + case "isVoid": + return isVoid + case "isClosure": + return isClosure + case "closure": + return closure + case "set": + return set + case "isSet": + return isSet + default: + fatalError("unable to lookup: \\(member) in \\(self)") } } - /// File name where the type was defined - public var fileName: String? - /// :nodoc: - public init(name: String = "", - parent: Type? = nil, - accessLevel: AccessLevel = .internal, - isExtension: Bool = false, - variables: [Variable] = [], - methods: [Method] = [], - subscripts: [Subscript] = [], - inheritedTypes: [String] = [], - containedTypes: [Type] = [], - typealiases: [Typealias] = [], - genericRequirements: [GenericRequirement] = [], + public init(name: String, + actualTypeName: TypeName? = nil, + unwrappedTypeName: String? = nil, attributes: AttributeList = [:], - modifiers: [SourceryModifier] = [], - annotations: [String: NSObject] = [:], - documentation: [String] = [], - isGeneric: Bool = false, - implements: [String: Type] = [:]) { - self.localName = name - self.accessLevel = accessLevel.rawValue - self.isExtension = isExtension - self.rawVariables = variables - self.rawMethods = methods - self.rawSubscripts = subscripts - self.inheritedTypes = inheritedTypes - self.containedTypes = containedTypes - self.typealiases = [:] - self.parent = parent - self.parentName = parent?.name + isOptional: Bool = false, + isImplicitlyUnwrappedOptional: Bool = false, + tuple: TupleType? = nil, + array: ArrayType? = nil, + dictionary: DictionaryType? = nil, + closure: ClosureType? = nil, + set: SetType? = nil, + generic: GenericType? = nil, + isProtocolComposition: Bool = false) { + + let optionalSuffix: String + // TODO: TBR + if !name.hasPrefix("Optional<") && !name.contains(" where ") { + if isOptional { + optionalSuffix = "?" + } else if isImplicitlyUnwrappedOptional { + optionalSuffix = "!" + } else { + optionalSuffix = "" + } + } else { + optionalSuffix = "" + } + + self.name = name + optionalSuffix + self.actualTypeName = actualTypeName + self.unwrappedTypeName = unwrappedTypeName ?? name + self.tuple = tuple + self.array = array + self.dictionary = dictionary + self.closure = closure + self.generic = generic + self.isOptional = isOptional || isImplicitlyUnwrappedOptional + self.isImplicitlyUnwrappedOptional = isImplicitlyUnwrappedOptional + self.isProtocolComposition = isProtocolComposition + self.set = set self.attributes = attributes - self.modifiers = modifiers - self.annotations = annotations - self.documentation = documentation - self.isGeneric = isGeneric - self.genericRequirements = genericRequirements - self.implements = implements + self.modifiers = [] super.init() - containedTypes.forEach { - containedType[$0.localName] = $0 - $0.parent = self - } - inheritedTypes.forEach { name in - self.based[name] = name - } - typealiases.forEach({ - $0.parent = self - self.typealiases[$0.aliasName] = $0 - }) } - /// :nodoc: - public func extend(_ type: Type) { - type.annotations.forEach { self.annotations[$0.key] = $0.value } - type.inherits.forEach { self.inherits[$0.key] = $0.value } - type.implements.forEach { self.implements[$0.key] = $0.value } - self.inheritedTypes += type.inheritedTypes - self.containedTypes += type.containedTypes + /// Type name used in declaration + public var name: String - self.rawVariables += type.rawVariables - self.rawMethods += type.rawMethods - self.rawSubscripts += type.rawSubscripts + /// The generics of this TypeName + public var generic: GenericType? + + /// Whether this TypeName is generic + public var isGeneric: Bool { + actualTypeName?.generic != nil || generic != nil } - /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "module = \\(String(describing: self.module)), " - string += "imports = \\(String(describing: self.imports)), " - string += "allImports = \\(String(describing: self.allImports)), " - string += "typealiases = \\(String(describing: self.typealiases)), " - string += "isExtension = \\(String(describing: self.isExtension)), " - string += "kind = \\(String(describing: self.kind)), " - string += "accessLevel = \\(String(describing: self.accessLevel)), " - string += "name = \\(String(describing: self.name)), " - string += "isUnknownExtension = \\(String(describing: self.isUnknownExtension)), " - string += "isGeneric = \\(String(describing: self.isGeneric)), " - string += "localName = \\(String(describing: self.localName)), " - string += "rawVariables = \\(String(describing: self.rawVariables)), " - string += "rawMethods = \\(String(describing: self.rawMethods)), " - string += "rawSubscripts = \\(String(describing: self.rawSubscripts)), " - string += "initializers = \\(String(describing: self.initializers)), " - string += "annotations = \\(String(describing: self.annotations)), " - string += "documentation = \\(String(describing: self.documentation)), " - string += "staticVariables = \\(String(describing: self.staticVariables)), " - string += "staticMethods = \\(String(describing: self.staticMethods)), " - string += "classMethods = \\(String(describing: self.classMethods)), " - string += "instanceVariables = \\(String(describing: self.instanceVariables)), " - string += "instanceMethods = \\(String(describing: self.instanceMethods)), " - string += "computedVariables = \\(String(describing: self.computedVariables)), " - string += "storedVariables = \\(String(describing: self.storedVariables)), " - string += "inheritedTypes = \\(String(describing: self.inheritedTypes)), " - string += "inherits = \\(String(describing: self.inherits)), " - string += "containedTypes = \\(String(describing: self.containedTypes)), " - string += "parentName = \\(String(describing: self.parentName)), " - string += "parentTypes = \\(String(describing: self.parentTypes)), " - string += "attributes = \\(String(describing: self.attributes)), " - string += "modifiers = \\(String(describing: self.modifiers)), " - string += "fileName = \\(String(describing: self.fileName)), " - string += "genericRequirements = \\(String(describing: self.genericRequirements))" - return string + /// Whether this TypeName is protocol composition + public var isProtocolComposition: Bool + + // sourcery: skipEquality + /// Actual type name if given type name is a typealias + public var actualTypeName: TypeName? + + /// Type name attributes, i.e. `@escaping` + public var attributes: AttributeList + + /// Modifiers, i.e. `escaping` + public var modifiers: [SourceryModifier] + + // sourcery: skipEquality + /// Whether type is optional + public let isOptional: Bool + + // sourcery: skipEquality + /// Whether type is implicitly unwrapped optional + public let isImplicitlyUnwrappedOptional: Bool + + // sourcery: skipEquality + /// Type name without attributes and optional type information + public var unwrappedTypeName: String + + // sourcery: skipEquality + /// Whether type is void (`Void` or `()`) + public var isVoid: Bool { + return name == "Void" || name == "()" || unwrappedTypeName == "Void" + } + + /// Whether type is a tuple + public var isTuple: Bool { + actualTypeName?.tuple != nil || tuple != nil + } + + /// Tuple type data + public var tuple: TupleType? + + /// Whether type is an array + public var isArray: Bool { + actualTypeName?.array != nil || array != nil + } + + /// Array type data + public var array: ArrayType? + + /// Whether type is a dictionary + public var isDictionary: Bool { + actualTypeName?.dictionary != nil || dictionary != nil + } + + /// Dictionary type data + public var dictionary: DictionaryType? + + /// Whether type is a closure + public var isClosure: Bool { + actualTypeName?.closure != nil || closure != nil + } + + /// Closure type data + public var closure: ClosureType? + + /// Whether type is a Set + public var isSet: Bool { + actualTypeName?.set != nil || set != nil + } + + /// Set type data + public var set: SetType? + + /// Prints typename as it would appear on definition + public var asSource: String { + // TODO: TBR special treatment + let specialTreatment = isOptional && name.hasPrefix("Optional<") + + var description = ( + attributes.flatMap({ $0.value }).map({ $0.asSource }).sorted() + + modifiers.map({ $0.asSource }) + + [specialTreatment ? name : unwrappedTypeName] + ).joined(separator: " ") + + if let _ = self.dictionary { // array and dictionary cases are covered by the unwrapped type name +// description.append(dictionary.asSource) + } else if let _ = self.array { +// description.append(array.asSource) + } else if let _ = self.generic { +// let arguments = generic.typeParameters +// .map({ $0.typeName.asSource }) +// .joined(separator: ", ") +// description.append("<\\(arguments)>") + } + if !specialTreatment { + if isImplicitlyUnwrappedOptional { + description.append("!") + } else if isOptional { + description.append("?") + } + } + + return description + } + + public override var description: String { + ( + attributes.flatMap({ $0.value }).map({ $0.asSource }).sorted() + + modifiers.map({ $0.asSource }) + + [name] + ).joined(separator: " ") } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() - guard let castObject = object as? Type else { - results.append("Incorrect type ") + guard let castObject = object as? TypeName else { + results.append("Incorrect type ") return results } - results.append(contentsOf: DiffableResult(identifier: "module").trackDifference(actual: self.module, expected: castObject.module)) - results.append(contentsOf: DiffableResult(identifier: "imports").trackDifference(actual: self.imports, expected: castObject.imports)) - results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) - results.append(contentsOf: DiffableResult(identifier: "isExtension").trackDifference(actual: self.isExtension, expected: castObject.isExtension)) - results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) - results.append(contentsOf: DiffableResult(identifier: "isUnknownExtension").trackDifference(actual: self.isUnknownExtension, expected: castObject.isUnknownExtension)) - results.append(contentsOf: DiffableResult(identifier: "isGeneric").trackDifference(actual: self.isGeneric, expected: castObject.isGeneric)) - results.append(contentsOf: DiffableResult(identifier: "localName").trackDifference(actual: self.localName, expected: castObject.localName)) - results.append(contentsOf: DiffableResult(identifier: "rawVariables").trackDifference(actual: self.rawVariables, expected: castObject.rawVariables)) - results.append(contentsOf: DiffableResult(identifier: "rawMethods").trackDifference(actual: self.rawMethods, expected: castObject.rawMethods)) - results.append(contentsOf: DiffableResult(identifier: "rawSubscripts").trackDifference(actual: self.rawSubscripts, expected: castObject.rawSubscripts)) - results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) - results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) - results.append(contentsOf: DiffableResult(identifier: "inheritedTypes").trackDifference(actual: self.inheritedTypes, expected: castObject.inheritedTypes)) - results.append(contentsOf: DiffableResult(identifier: "inherits").trackDifference(actual: self.inherits, expected: castObject.inherits)) - results.append(contentsOf: DiffableResult(identifier: "containedTypes").trackDifference(actual: self.containedTypes, expected: castObject.containedTypes)) - results.append(contentsOf: DiffableResult(identifier: "parentName").trackDifference(actual: self.parentName, expected: castObject.parentName)) + results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) + results.append(contentsOf: DiffableResult(identifier: "generic").trackDifference(actual: self.generic, expected: castObject.generic)) + results.append(contentsOf: DiffableResult(identifier: "isProtocolComposition").trackDifference(actual: self.isProtocolComposition, expected: castObject.isProtocolComposition)) results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) - results.append(contentsOf: DiffableResult(identifier: "fileName").trackDifference(actual: self.fileName, expected: castObject.fileName)) - results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) + results.append(contentsOf: DiffableResult(identifier: "tuple").trackDifference(actual: self.tuple, expected: castObject.tuple)) + results.append(contentsOf: DiffableResult(identifier: "array").trackDifference(actual: self.array, expected: castObject.array)) + results.append(contentsOf: DiffableResult(identifier: "dictionary").trackDifference(actual: self.dictionary, expected: castObject.dictionary)) + results.append(contentsOf: DiffableResult(identifier: "closure").trackDifference(actual: self.closure, expected: castObject.closure)) + results.append(contentsOf: DiffableResult(identifier: "set").trackDifference(actual: self.set, expected: castObject.set)) return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() - hasher.combine(self.module) - hasher.combine(self.imports) - hasher.combine(self.typealiases) - hasher.combine(self.isExtension) - hasher.combine(self.accessLevel) - hasher.combine(self.isUnknownExtension) - hasher.combine(self.isGeneric) - hasher.combine(self.localName) - hasher.combine(self.rawVariables) - hasher.combine(self.rawMethods) - hasher.combine(self.rawSubscripts) - hasher.combine(self.annotations) - hasher.combine(self.documentation) - hasher.combine(self.inheritedTypes) - hasher.combine(self.inherits) - hasher.combine(self.containedTypes) - hasher.combine(self.parentName) + hasher.combine(self.name) + hasher.combine(self.generic) + hasher.combine(self.isProtocolComposition) hasher.combine(self.attributes) hasher.combine(self.modifiers) - hasher.combine(self.fileName) - hasher.combine(self.genericRequirements) - hasher.combine(kind) + hasher.combine(self.tuple) + hasher.combine(self.array) + hasher.combine(self.dictionary) + hasher.combine(self.closure) + hasher.combine(self.set) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? Type else { return false } - if self.module != rhs.module { return false } - if self.imports != rhs.imports { return false } - if self.typealiases != rhs.typealiases { return false } - if self.isExtension != rhs.isExtension { return false } - if self.accessLevel != rhs.accessLevel { return false } - if self.isUnknownExtension != rhs.isUnknownExtension { return false } - if self.isGeneric != rhs.isGeneric { return false } - if self.localName != rhs.localName { return false } - if self.rawVariables != rhs.rawVariables { return false } - if self.rawMethods != rhs.rawMethods { return false } - if self.rawSubscripts != rhs.rawSubscripts { return false } - if self.annotations != rhs.annotations { return false } - if self.documentation != rhs.documentation { return false } - if self.inheritedTypes != rhs.inheritedTypes { return false } - if self.inherits != rhs.inherits { return false } - if self.containedTypes != rhs.containedTypes { return false } - if self.parentName != rhs.parentName { return false } + guard let rhs = object as? TypeName else { return false } + if self.name != rhs.name { return false } + if self.generic != rhs.generic { return false } + if self.isProtocolComposition != rhs.isProtocolComposition { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } - if self.fileName != rhs.fileName { return false } - if self.kind != rhs.kind { return false } - if self.genericRequirements != rhs.genericRequirements { return false } + if self.tuple != rhs.tuple { return false } + if self.array != rhs.array { return false } + if self.dictionary != rhs.dictionary { return false } + if self.closure != rhs.closure { return false } + if self.set != rhs.set { return false } return true } -// sourcery:inline:Type.AutoCoding +// sourcery:inline:TypeName.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { - self.module = aDecoder.decode(forKey: "module") - guard let imports: [Import] = aDecoder.decode(forKey: "imports") else { - withVaList(["imports"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.imports = imports - guard let typealiases: [String: Typealias] = aDecoder.decode(forKey: "typealiases") else { - withVaList(["typealiases"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.typealiases = typealiases - self.isExtension = aDecoder.decode(forKey: "isExtension") - guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { - withVaList(["accessLevel"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.accessLevel = accessLevel - self.isGeneric = aDecoder.decode(forKey: "isGeneric") - guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { - withVaList(["genericRequirements"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.genericRequirements = genericRequirements - guard let localName: String = aDecoder.decode(forKey: "localName") else { - withVaList(["localName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.localName = localName - guard let rawVariables: [Variable] = aDecoder.decode(forKey: "rawVariables") else { - withVaList(["rawVariables"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.rawVariables = rawVariables - guard let rawMethods: [Method] = aDecoder.decode(forKey: "rawMethods") else { - withVaList(["rawMethods"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.rawMethods = rawMethods - guard let rawSubscripts: [Subscript] = aDecoder.decode(forKey: "rawSubscripts") else { - withVaList(["rawSubscripts"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.rawSubscripts = rawSubscripts - self.bodyBytesRange = aDecoder.decode(forKey: "bodyBytesRange") - self.completeDeclarationRange = aDecoder.decode(forKey: "completeDeclarationRange") - guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { - withVaList(["annotations"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.annotations = annotations - guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { - withVaList(["documentation"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.documentation = documentation - guard let inheritedTypes: [String] = aDecoder.decode(forKey: "inheritedTypes") else { - withVaList(["inheritedTypes"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.inheritedTypes = inheritedTypes - guard let based: [String: String] = aDecoder.decode(forKey: "based") else { - withVaList(["based"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.based = based - guard let basedTypes: [String: Type] = aDecoder.decode(forKey: "basedTypes") else { - withVaList(["basedTypes"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.basedTypes = basedTypes - guard let inherits: [String: Type] = aDecoder.decode(forKey: "inherits") else { - withVaList(["inherits"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.inherits = inherits - guard let implements: [String: Type] = aDecoder.decode(forKey: "implements") else { - withVaList(["implements"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.implements = implements - guard let containedTypes: [Type] = aDecoder.decode(forKey: "containedTypes") else { - withVaList(["containedTypes"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.containedTypes = containedTypes - guard let containedType: [String: Type] = aDecoder.decode(forKey: "containedType") else { - withVaList(["containedType"]) { arguments in + guard let name: String = aDecoder.decode(forKey: "name") else { + withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.containedType = containedType - self.parentName = aDecoder.decode(forKey: "parentName") - self.parent = aDecoder.decode(forKey: "parent") - self.supertype = aDecoder.decode(forKey: "supertype") - guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { + }; self.name = name + self.generic = aDecoder.decode(forKey: "generic") + self.isProtocolComposition = aDecoder.decode(forKey: "isProtocolComposition") + self.actualTypeName = aDecoder.decode(forKey: "actualTypeName") + guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes - guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { + guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers - self.path = aDecoder.decode(forKey: "path") - self.fileName = aDecoder.decode(forKey: "fileName") + self.isOptional = aDecoder.decode(forKey: "isOptional") + self.isImplicitlyUnwrappedOptional = aDecoder.decode(forKey: "isImplicitlyUnwrappedOptional") + guard let unwrappedTypeName: String = aDecoder.decode(forKey: "unwrappedTypeName") else { + withVaList(["unwrappedTypeName"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.unwrappedTypeName = unwrappedTypeName + self.tuple = aDecoder.decode(forKey: "tuple") + self.array = aDecoder.decode(forKey: "array") + self.dictionary = aDecoder.decode(forKey: "dictionary") + self.closure = aDecoder.decode(forKey: "closure") + self.set = aDecoder.decode(forKey: "set") } /// :nodoc: public func encode(with aCoder: NSCoder) { - aCoder.encode(self.module, forKey: "module") - aCoder.encode(self.imports, forKey: "imports") - aCoder.encode(self.typealiases, forKey: "typealiases") - aCoder.encode(self.isExtension, forKey: "isExtension") - aCoder.encode(self.accessLevel, forKey: "accessLevel") - aCoder.encode(self.isGeneric, forKey: "isGeneric") - aCoder.encode(self.localName, forKey: "localName") - aCoder.encode(self.rawVariables, forKey: "rawVariables") - aCoder.encode(self.rawMethods, forKey: "rawMethods") - aCoder.encode(self.rawSubscripts, forKey: "rawSubscripts") - aCoder.encode(self.bodyBytesRange, forKey: "bodyBytesRange") - aCoder.encode(self.completeDeclarationRange, forKey: "completeDeclarationRange") - aCoder.encode(self.annotations, forKey: "annotations") - aCoder.encode(self.documentation, forKey: "documentation") - aCoder.encode(self.inheritedTypes, forKey: "inheritedTypes") - aCoder.encode(self.based, forKey: "based") - aCoder.encode(self.basedTypes, forKey: "basedTypes") - aCoder.encode(self.inherits, forKey: "inherits") - aCoder.encode(self.implements, forKey: "implements") - aCoder.encode(self.containedTypes, forKey: "containedTypes") - aCoder.encode(self.containedType, forKey: "containedType") - aCoder.encode(self.parentName, forKey: "parentName") - aCoder.encode(self.parent, forKey: "parent") - aCoder.encode(self.supertype, forKey: "supertype") + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.generic, forKey: "generic") + aCoder.encode(self.isProtocolComposition, forKey: "isProtocolComposition") + aCoder.encode(self.actualTypeName, forKey: "actualTypeName") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") - aCoder.encode(self.path, forKey: "path") - aCoder.encode(self.fileName, forKey: "fileName") - aCoder.encode(self.genericRequirements, forKey: "genericRequirements") + aCoder.encode(self.isOptional, forKey: "isOptional") + aCoder.encode(self.isImplicitlyUnwrappedOptional, forKey: "isImplicitlyUnwrappedOptional") + aCoder.encode(self.unwrappedTypeName, forKey: "unwrappedTypeName") + aCoder.encode(self.tuple, forKey: "tuple") + aCoder.encode(self.array, forKey: "array") + aCoder.encode(self.dictionary, forKey: "dictionary") + aCoder.encode(self.closure, forKey: "closure") + aCoder.encode(self.set, forKey: "set") } // sourcery:end -} + // sourcery: skipEquality, skipDescription + /// :nodoc: + public override var debugDescription: String { + return name + } -extension Type { + public convenience init(_ description: String) { + self.init(name: description, actualTypeName: nil) + } +} - // sourcery: skipDescription, skipJSExport - /// :nodoc: - var isClass: Bool { - let isNotClass = self is Struct || self is Enum || self is Protocol - return !isNotClass && !isExtension +extension TypeName { + public static func unknown(description: String?, attributes: AttributeList = [:]) -> TypeName { + if let description = description { + Log.astWarning("Unknown type, please add type attribution to \\(description)") + } else { + Log.astWarning("Unknown type, please add type attribution") + } + return TypeName(name: "UnknownTypeSoAddTypeAttributionToVariable", attributes: attributes) } } +#endif """), - .init(name: "TypeName.swift", content: + .init(name: "Type_Linux.swift", content: """ // -// Created by Krzysztof Zabłocki on 25/12/2016. +// Created by Krzysztof Zablocki on 11/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // - +#if !canImport(ObjectiveC) import Foundation -/// Describes name of the type used in typed declaration (variable, method parameter or return value etc.) -public final class TypeName: NSObject, SourceryModelWithoutDescription, LosslessStringConvertible, Diffable { - - /// :nodoc: - public init(name: String, - actualTypeName: TypeName? = nil, - unwrappedTypeName: String? = nil, - attributes: AttributeList = [:], - isOptional: Bool = false, - isImplicitlyUnwrappedOptional: Bool = false, - tuple: TupleType? = nil, - array: ArrayType? = nil, - dictionary: DictionaryType? = nil, - closure: ClosureType? = nil, - set: SetType? = nil, - generic: GenericType? = nil, - isProtocolComposition: Bool = false) { - - let optionalSuffix: String - // TODO: TBR - if !name.hasPrefix("Optional<") && !name.contains(" where ") { - if isOptional { - optionalSuffix = "?" - } else if isImplicitlyUnwrappedOptional { - optionalSuffix = "!" - } else { - optionalSuffix = "" - } - } else { - optionalSuffix = "" - } +/// :nodoc: +public typealias AttributeList = [String: [Attribute]] - self.name = name + optionalSuffix - self.actualTypeName = actualTypeName - self.unwrappedTypeName = unwrappedTypeName ?? name - self.tuple = tuple - self.array = array - self.dictionary = dictionary - self.closure = closure - self.generic = generic - self.isOptional = isOptional || isImplicitlyUnwrappedOptional - self.isImplicitlyUnwrappedOptional = isImplicitlyUnwrappedOptional - self.isProtocolComposition = isProtocolComposition - self.set = set - self.attributes = attributes - self.modifiers = [] - super.init() +/// Defines Swift type +public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable, SourceryDynamicMemberLookup { + public subscript(dynamicMember member: String) -> Any? { + switch member { + case "implements": + return implements + case "name": + return name + case "kind": + return kind + case "based": + return based + case "supertype": + return supertype + case "accessLevel": + return accessLevel + case "storedVariables": + return storedVariables + case "variables": + return variables + case "allVariables": + return allVariables + case "allMethods": + return allMethods + case "annotations": + return annotations + case "methods": + return methods + case "containedType": + return containedType + case "computedVariables": + return computedVariables + case "inherits": + return inherits + case "inheritedTypes": + return inheritedTypes + case "subscripts": + return subscripts + case "rawSubscripts": + return rawSubscripts + case "allSubscripts": + return allSubscripts + case "genericRequirements": + return genericRequirements + default: + fatalError("unable to lookup: \\(member) in \\(self)") + } } - /// Type name used in declaration - public var name: String + /// :nodoc: + public var module: String? - /// The generics of this TypeName - public var generic: GenericType? + /// Imports that existed in the file that contained this type declaration + public var imports: [Import] = [] - /// Whether this TypeName is generic - public var isGeneric: Bool { - actualTypeName?.generic != nil || generic != nil + // sourcery: skipEquality + /// Imports existed in all files containing this type and all its super classes/protocols + public var allImports: [Import] { + return self.unique({ $0.gatherAllImports() }, filter: { $0 == $1 }) } - /// Whether this TypeName is protocol composition - public var isProtocolComposition: Bool - - // sourcery: skipEquality - /// Actual type name if given type name is a typealias - public var actualTypeName: TypeName? + private func gatherAllImports() -> [Import] { + var allImports: [Import] = Array(self.imports) - /// Type name attributes, i.e. `@escaping` - public var attributes: AttributeList + self.basedTypes.values.forEach { (basedType) in + allImports.append(contentsOf: basedType.imports) + } + return allImports + } - /// Modifiers, i.e. `escaping` - public var modifiers: [SourceryModifier] + // All local typealiases + /// :nodoc: + public var typealiases: [String: Typealias] { + didSet { + typealiases.values.forEach { $0.parent = self } + } + } - // sourcery: skipEquality - /// Whether type is optional - public let isOptional: Bool + // sourcery: skipJSExport + /// Whether declaration is an extension of some type + public var isExtension: Bool - // sourcery: skipEquality - /// Whether type is implicitly unwrapped optional - public let isImplicitlyUnwrappedOptional: Bool + // sourcery: forceEquality + /// Kind of type declaration, i.e. `enum`, `struct`, `class`, `protocol` or `extension` + public var kind: String { isExtension ? "extension" : "unknown" } - // sourcery: skipEquality - /// Type name without attributes and optional type information - public var unwrappedTypeName: String + /// Type access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` + public let accessLevel: String - // sourcery: skipEquality - /// Whether type is void (`Void` or `()`) - public var isVoid: Bool { - return name == "Void" || name == "()" || unwrappedTypeName == "Void" + /// Type name in global scope. For inner types includes the name of its containing type, i.e. `Type.Inner` + public var name: String { + guard let parentName = parent?.name else { return localName } + return "\\(parentName).\\(localName)" } - /// Whether type is a tuple - public var isTuple: Bool { - actualTypeName?.tuple != nil || tuple != nil + // sourcery: skipCoding + /// Whether the type has been resolved as unknown extension + public var isUnknownExtension: Bool = false + + // sourcery: skipDescription + /// Global type name including module name, unless it's an extension of unknown type + public var globalName: String { + guard let module = module, !isUnknownExtension else { return name } + return "\\(module).\\(name)" } - /// Tuple type data - public var tuple: TupleType? + /// Whether type is generic + public var isGeneric: Bool - /// Whether type is an array - public var isArray: Bool { - actualTypeName?.array != nil || array != nil + /// Type name in its own scope. + public var localName: String + + // sourcery: skipEquality, skipDescription + /// Variables defined in this type only, inluding variables defined in its extensions, + /// but not including variables inherited from superclasses (for classes only) and protocols + public var variables: [Variable] { + unique({ $0.rawVariables }, filter: Self.uniqueVariableFilter) } - /// Array type data - public var array: ArrayType? + /// Unfiltered (can contain duplications from extensions) variables defined in this type only, inluding variables defined in its extensions, + /// but not including variables inherited from superclasses (for classes only) and protocols + public var rawVariables: [Variable] - /// Whether type is a dictionary - public var isDictionary: Bool { - actualTypeName?.dictionary != nil || dictionary != nil + // sourcery: skipEquality, skipDescription + /// All variables defined for this type, including variables defined in extensions, + /// in superclasses (for classes only) and protocols + public var allVariables: [Variable] { + return flattenAll({ + return $0.variables + }, + isExtension: { $0.definedInType?.isExtension == true }, + filter: { all, extracted in + !all.contains(where: { Self.uniqueVariableFilter($0, rhs: extracted) }) + }) } - /// Dictionary type data - public var dictionary: DictionaryType? + private static func uniqueVariableFilter(_ lhs: Variable, rhs: Variable) -> Bool { + return lhs.name == rhs.name && lhs.isStatic == rhs.isStatic && lhs.typeName == rhs.typeName + } - /// Whether type is a closure - public var isClosure: Bool { - actualTypeName?.closure != nil || closure != nil + // sourcery: skipEquality, skipDescription + /// Methods defined in this type only, inluding methods defined in its extensions, + /// but not including methods inherited from superclasses (for classes only) and protocols + public var methods: [Method] { + unique({ $0.rawMethods }, filter: Self.uniqueMethodFilter) } - /// Closure type data - public var closure: ClosureType? + /// Unfiltered (can contain duplications from extensions) methods defined in this type only, inluding methods defined in its extensions, + /// but not including methods inherited from superclasses (for classes only) and protocols + public var rawMethods: [Method] - /// Whether type is a Set - public var isSet: Bool { - actualTypeName?.set != nil || set != nil + // sourcery: skipEquality, skipDescription + /// All methods defined for this type, including methods defined in extensions, + /// in superclasses (for classes only) and protocols + public var allMethods: [Method] { + return flattenAll({ + $0.methods + }, + isExtension: { $0.definedInType?.isExtension == true }, + filter: { all, extracted in + !all.contains(where: { Self.uniqueMethodFilter($0, rhs: extracted) }) + }) } - /// Set type data - public var set: SetType? + private static func uniqueMethodFilter(_ lhs: Method, rhs: Method) -> Bool { + return lhs.name == rhs.name && lhs.isStatic == rhs.isStatic && lhs.isClass == rhs.isClass && lhs.actualReturnTypeName == rhs.actualReturnTypeName + } - /// Prints typename as it would appear on definition - public var asSource: String { - // TODO: TBR special treatment - let specialTreatment = isOptional && name.hasPrefix("Optional<") + // sourcery: skipEquality, skipDescription + /// Subscripts defined in this type only, inluding subscripts defined in its extensions, + /// but not including subscripts inherited from superclasses (for classes only) and protocols + public var subscripts: [Subscript] { + unique({ $0.rawSubscripts }, filter: Self.uniqueSubscriptFilter) + } - var description = ( - attributes.flatMap({ $0.value }).map({ $0.asSource }).sorted() + - modifiers.map({ $0.asSource }) + - [specialTreatment ? name : unwrappedTypeName] - ).joined(separator: " ") + /// Unfiltered (can contain duplications from extensions) Subscripts defined in this type only, inluding subscripts defined in its extensions, + /// but not including subscripts inherited from superclasses (for classes only) and protocols + public var rawSubscripts: [Subscript] - if let _ = self.dictionary { // array and dictionary cases are covered by the unwrapped type name -// description.append(dictionary.asSource) - } else if let _ = self.array { -// description.append(array.asSource) - } else if let _ = self.generic { -// let arguments = generic.typeParameters -// .map({ $0.typeName.asSource }) -// .joined(separator: ", ") -// description.append("<\\(arguments)>") - } - if !specialTreatment { - if isImplicitlyUnwrappedOptional { - description.append("!") - } else if isOptional { - description.append("?") - } - } + // sourcery: skipEquality, skipDescription + /// All subscripts defined for this type, including subscripts defined in extensions, + /// in superclasses (for classes only) and protocols + public var allSubscripts: [Subscript] { + return flattenAll({ $0.subscripts }, + isExtension: { $0.definedInType?.isExtension == true }, + filter: { all, extracted in + !all.contains(where: { Self.uniqueSubscriptFilter($0, rhs: extracted) }) + }) + } - return description + private static func uniqueSubscriptFilter(_ lhs: Subscript, rhs: Subscript) -> Bool { + return lhs.parameters == rhs.parameters && lhs.returnTypeName == rhs.returnTypeName && lhs.readAccess == rhs.readAccess && lhs.writeAccess == rhs.writeAccess } - public override var description: String { - ( - attributes.flatMap({ $0.value }).map({ $0.asSource }).sorted() + - modifiers.map({ $0.asSource }) + - [name] - ).joined(separator: " ") - } + // sourcery: skipEquality, skipDescription, skipJSExport + /// Bytes position of the body of this type in its declaration file if available. + public var bodyBytesRange: BytesRange? - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? TypeName else { - results.append("Incorrect type ") - return results - } - results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "generic").trackDifference(actual: self.generic, expected: castObject.generic)) - results.append(contentsOf: DiffableResult(identifier: "isProtocolComposition").trackDifference(actual: self.isProtocolComposition, expected: castObject.isProtocolComposition)) - results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) - results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) - results.append(contentsOf: DiffableResult(identifier: "tuple").trackDifference(actual: self.tuple, expected: castObject.tuple)) - results.append(contentsOf: DiffableResult(identifier: "array").trackDifference(actual: self.array, expected: castObject.array)) - results.append(contentsOf: DiffableResult(identifier: "dictionary").trackDifference(actual: self.dictionary, expected: castObject.dictionary)) - results.append(contentsOf: DiffableResult(identifier: "closure").trackDifference(actual: self.closure, expected: castObject.closure)) - results.append(contentsOf: DiffableResult(identifier: "set").trackDifference(actual: self.set, expected: castObject.set)) - return results - } + // sourcery: skipEquality, skipDescription, skipJSExport + /// Bytes position of the whole declaration of this type in its declaration file if available. + public var completeDeclarationRange: BytesRange? - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.name) - hasher.combine(self.generic) - hasher.combine(self.isProtocolComposition) - hasher.combine(self.attributes) - hasher.combine(self.modifiers) - hasher.combine(self.tuple) - hasher.combine(self.array) - hasher.combine(self.dictionary) - hasher.combine(self.closure) - hasher.combine(self.set) - return hasher.finalize() - } + private func flattenAll(_ extraction: @escaping (Type) -> [T], isExtension: (T) -> Bool, filter: ([T], T) -> Bool) -> [T] { + let all = NSMutableOrderedSet() + let allObjects = extraction(self) - /// :nodoc: - public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? TypeName else { return false } - if self.name != rhs.name { return false } - if self.generic != rhs.generic { return false } - if self.isProtocolComposition != rhs.isProtocolComposition { return false } - if self.attributes != rhs.attributes { return false } - if self.modifiers != rhs.modifiers { return false } - if self.tuple != rhs.tuple { return false } - if self.array != rhs.array { return false } - if self.dictionary != rhs.dictionary { return false } - if self.closure != rhs.closure { return false } - if self.set != rhs.set { return false } - return true - } + /// The order of importance for properties is: + /// Base class + /// Inheritance + /// Protocol conformance + /// Extension -// sourcery:inline:TypeName.AutoCoding + var extensions = [T]() + var baseObjects = [T]() - /// :nodoc: - required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { - withVaList(["name"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.name = name - self.generic = aDecoder.decode(forKey: "generic") - self.isProtocolComposition = aDecoder.decode(forKey: "isProtocolComposition") - self.actualTypeName = aDecoder.decode(forKey: "actualTypeName") - guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { - withVaList(["attributes"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.attributes = attributes - guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { - withVaList(["modifiers"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.modifiers = modifiers - self.isOptional = aDecoder.decode(forKey: "isOptional") - self.isImplicitlyUnwrappedOptional = aDecoder.decode(forKey: "isImplicitlyUnwrappedOptional") - guard let unwrappedTypeName: String = aDecoder.decode(forKey: "unwrappedTypeName") else { - withVaList(["unwrappedTypeName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.unwrappedTypeName = unwrappedTypeName - self.tuple = aDecoder.decode(forKey: "tuple") - self.array = aDecoder.decode(forKey: "array") - self.dictionary = aDecoder.decode(forKey: "dictionary") - self.closure = aDecoder.decode(forKey: "closure") - self.set = aDecoder.decode(forKey: "set") + allObjects.forEach { + if isExtension($0) { + extensions.append($0) + } else { + baseObjects.append($0) + } } - /// :nodoc: - public func encode(with aCoder: NSCoder) { - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.generic, forKey: "generic") - aCoder.encode(self.isProtocolComposition, forKey: "isProtocolComposition") - aCoder.encode(self.actualTypeName, forKey: "actualTypeName") - aCoder.encode(self.attributes, forKey: "attributes") - aCoder.encode(self.modifiers, forKey: "modifiers") - aCoder.encode(self.isOptional, forKey: "isOptional") - aCoder.encode(self.isImplicitlyUnwrappedOptional, forKey: "isImplicitlyUnwrappedOptional") - aCoder.encode(self.unwrappedTypeName, forKey: "unwrappedTypeName") - aCoder.encode(self.tuple, forKey: "tuple") - aCoder.encode(self.array, forKey: "array") - aCoder.encode(self.dictionary, forKey: "dictionary") - aCoder.encode(self.closure, forKey: "closure") - aCoder.encode(self.set, forKey: "set") + all.addObjects(from: baseObjects) + + func filteredExtraction(_ target: Type) -> [T] { + // swiftlint:disable:next force_cast + let all = all.array as! [T] + let extracted = extraction(target).filter({ filter(all, $0) }) + return extracted } -// sourcery:end - // sourcery: skipEquality, skipDescription - /// :nodoc: - public override var debugDescription: String { - return name - } + inherits.values.sorted(by: { $0.name < $1.name }).forEach { all.addObjects(from: filteredExtraction($0)) } + implements.values.sorted(by: { $0.name < $1.name }).forEach { all.addObjects(from: filteredExtraction($0)) } - public convenience init(_ description: String) { - self.init(name: description, actualTypeName: nil) + // swiftlint:disable:next force_cast + let array = all.array as! [T] + all.addObjects(from: extensions.filter({ filter(array, $0) })) + + return all.array.compactMap { $0 as? T } } -} -extension TypeName { - public static func unknown(description: String?, attributes: AttributeList = [:]) -> TypeName { - if let description = description { - Log.astWarning("Unknown type, please add type attribution to \\(description)") - } else { - Log.astWarning("Unknown type, please add type attribution") + private func unique(_ extraction: @escaping (Type) -> [T], filter: (T, T) -> Bool) -> [T] { + let all = NSMutableOrderedSet() + for nextItem in extraction(self) { + // swiftlint:disable:next force_cast + if !all.contains(where: { filter($0 as! T, nextItem) }) { + all.add(nextItem) + } } - return TypeName(name: "UnknownTypeSoAddTypeAttributionToVariable", attributes: attributes) - } -} -"""), - .init(name: "Typealias.swift", content: -""" -import Foundation + return all.array.compactMap { $0 as? T } + } -// sourcery: skipJSExport -/// :nodoc: -public final class Typealias: NSObject, Typed, SourceryModel, Diffable { - // New typealias name - public let aliasName: String + /// All initializers defined in this type + public var initializers: [Method] { + return methods.filter { $0.isInitializer } + } - // Target name - public let typeName: TypeName + /// All annotations for this type + public var annotations: Annotations = [:] - // sourcery: skipEquality, skipDescription - public var type: Type? + public var documentation: Documentation = [] - /// module in which this typealias was declared - public var module: String? + /// Static variables defined in this type + public var staticVariables: [Variable] { + return variables.filter { $0.isStatic } + } - // sourcery: skipEquality, skipDescription - public var parent: Type? { - didSet { - parentName = parent?.name - } + /// Static methods defined in this type + public var staticMethods: [Method] { + return methods.filter { $0.isStatic } } - /// Type access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` - public let accessLevel: String + /// Class methods defined in this type + public var classMethods: [Method] { + return methods.filter { $0.isClass } + } - var parentName: String? + /// Instance variables defined in this type + public var instanceVariables: [Variable] { + return variables.filter { !$0.isStatic } + } - public var name: String { - if let parentName = parent?.name { - return "\\(module != nil ? "\\(module!)." : "")\\(parentName).\\(aliasName)" - } else { - return "\\(module != nil ? "\\(module!)." : "")\\(aliasName)" - } + /// Instance methods defined in this type + public var instanceMethods: [Method] { + return methods.filter { !$0.isStatic && !$0.isClass } } - public init(aliasName: String = "", typeName: TypeName, accessLevel: AccessLevel = .internal, parent: Type? = nil, module: String? = nil) { - self.aliasName = aliasName - self.typeName = typeName - self.accessLevel = accessLevel.rawValue - self.parent = parent - self.parentName = parent?.name - self.module = module + /// Computed instance variables defined in this type + public var computedVariables: [Variable] { + return variables.filter { $0.isComputed && !$0.isStatic } } - /// :nodoc: - override public var description: String { - var string = "\\(Swift.type(of: self)): " - string += "aliasName = \\(String(describing: self.aliasName)), " - string += "typeName = \\(String(describing: self.typeName)), " - string += "module = \\(String(describing: self.module)), " - string += "accessLevel = \\(String(describing: self.accessLevel)), " - string += "parentName = \\(String(describing: self.parentName)), " - string += "name = \\(String(describing: self.name))" - return string + /// Stored instance variables defined in this type + public var storedVariables: [Variable] { + return variables.filter { !$0.isComputed && !$0.isStatic } } - public func diffAgainst(_ object: Any?) -> DiffableResult { - let results = DiffableResult() - guard let castObject = object as? Typealias else { - results.append("Incorrect type ") - return results + /// Names of types this type inherits from (for classes only) and protocols it implements, in order of definition + public var inheritedTypes: [String] { + didSet { + based.removeAll() + inheritedTypes.forEach { name in + self.based[name] = name + } } - results.append(contentsOf: DiffableResult(identifier: "aliasName").trackDifference(actual: self.aliasName, expected: castObject.aliasName)) - results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) - results.append(contentsOf: DiffableResult(identifier: "module").trackDifference(actual: self.module, expected: castObject.module)) - results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) - results.append(contentsOf: DiffableResult(identifier: "parentName").trackDifference(actual: self.parentName, expected: castObject.parentName)) - return results } - public override var hash: Int { - var hasher = Hasher() - hasher.combine(self.aliasName) - hasher.combine(self.typeName) - hasher.combine(self.module) - hasher.combine(self.accessLevel) - hasher.combine(self.parentName) + // sourcery: skipEquality, skipDescription + /// Names of types or protocols this type inherits from, including unknown (not scanned) types + public var based = [String: String]() + + // sourcery: skipEquality, skipDescription + /// Types this type inherits from or implements, including unknown (not scanned) types with extensions defined + public var basedTypes = [String: Type]() + + /// Types this type inherits from + public var inherits = [String: Type]() + + // sourcery: skipEquality, skipDescription + /// Protocols this type implements + public var implements = [String: Type]() + + /// Contained types + public var containedTypes: [Type] { + didSet { + containedTypes.forEach { + containedType[$0.localName] = $0 + $0.parent = self + } + } + } + + // sourcery: skipEquality, skipDescription + /// Contained types groupd by their names + public private(set) var containedType: [String: Type] = [:] + + /// Name of parent type (for contained types only) + public private(set) var parentName: String? + + // sourcery: skipEquality, skipDescription + /// Parent type, if known (for contained types only) + public var parent: Type? { + didSet { + parentName = parent?.name + } + } + + // sourcery: skipJSExport + /// :nodoc: + public var parentTypes: AnyIterator { + var next: Type? = self + return AnyIterator { + next = next?.parent + return next + } + } + + // sourcery: skipEquality, skipDescription + /// Superclass type, if known (only for classes) + public var supertype: Type? + + /// Type attributes, i.e. `@objc` + public var attributes: AttributeList + + /// Type modifiers, i.e. `private`, `final` + public var modifiers: [SourceryModifier] + + /// Path to file where the type is defined + // sourcery: skipDescription, skipEquality, skipJSExport + public var path: String? { + didSet { + if let path = path { + fileName = (path as NSString).lastPathComponent + } + } + } + + /// Directory to file where the type is defined + // sourcery: skipDescription, skipEquality, skipJSExport + public var directory: String? { + get { + return (path as? NSString)?.deletingLastPathComponent + } + } + + /// list of generic requirements + public var genericRequirements: [GenericRequirement] { + didSet { + isGeneric = isGeneric || !genericRequirements.isEmpty + } + } + + /// File name where the type was defined + public var fileName: String? + + /// :nodoc: + public init(name: String = "", + parent: Type? = nil, + accessLevel: AccessLevel = .internal, + isExtension: Bool = false, + variables: [Variable] = [], + methods: [Method] = [], + subscripts: [Subscript] = [], + inheritedTypes: [String] = [], + containedTypes: [Type] = [], + typealiases: [Typealias] = [], + genericRequirements: [GenericRequirement] = [], + attributes: AttributeList = [:], + modifiers: [SourceryModifier] = [], + annotations: [String: NSObject] = [:], + documentation: [String] = [], + isGeneric: Bool = false, + implements: [String: Type] = [:]) { + self.localName = name + self.accessLevel = accessLevel.rawValue + self.isExtension = isExtension + self.rawVariables = variables + self.rawMethods = methods + self.rawSubscripts = subscripts + self.inheritedTypes = inheritedTypes + self.containedTypes = containedTypes + self.typealiases = [:] + self.parent = parent + self.parentName = parent?.name + self.attributes = attributes + self.modifiers = modifiers + self.annotations = annotations + self.documentation = documentation + self.isGeneric = isGeneric + self.genericRequirements = genericRequirements + self.implements = implements + super.init() + containedTypes.forEach { + containedType[$0.localName] = $0 + $0.parent = self + } + inheritedTypes.forEach { name in + self.based[name] = name + } + typealiases.forEach({ + $0.parent = self + self.typealiases[$0.aliasName] = $0 + }) + } + + /// :nodoc: + public func extend(_ type: Type) { + type.annotations.forEach { self.annotations[$0.key] = $0.value } + type.inherits.forEach { self.inherits[$0.key] = $0.value } + type.implements.forEach { self.implements[$0.key] = $0.value } + self.inheritedTypes += type.inheritedTypes + self.containedTypes += type.containedTypes + + self.rawVariables += type.rawVariables + self.rawMethods += type.rawMethods + self.rawSubscripts += type.rawSubscripts + } + + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("module = \\(String(describing: self.module)), ") + string.append("imports = \\(String(describing: self.imports)), ") + string.append("allImports = \\(String(describing: self.allImports)), ") + string.append("typealiases = \\(String(describing: self.typealiases)), ") + string.append("isExtension = \\(String(describing: self.isExtension)), ") + string.append("kind = \\(String(describing: self.kind)), ") + string.append("accessLevel = \\(String(describing: self.accessLevel)), ") + string.append("name = \\(String(describing: self.name)), ") + string.append("isUnknownExtension = \\(String(describing: self.isUnknownExtension)), ") + string.append("isGeneric = \\(String(describing: self.isGeneric)), ") + string.append("localName = \\(String(describing: self.localName)), ") + string.append("rawVariables = \\(String(describing: self.rawVariables)), ") + string.append("rawMethods = \\(String(describing: self.rawMethods)), ") + string.append("rawSubscripts = \\(String(describing: self.rawSubscripts)), ") + string.append("initializers = \\(String(describing: self.initializers)), ") + string.append("annotations = \\(String(describing: self.annotations)), ") + string.append("documentation = \\(String(describing: self.documentation)), ") + string.append("staticVariables = \\(String(describing: self.staticVariables)), ") + string.append("staticMethods = \\(String(describing: self.staticMethods)), ") + string.append("classMethods = \\(String(describing: self.classMethods)), ") + string.append("instanceVariables = \\(String(describing: self.instanceVariables)), ") + string.append("instanceMethods = \\(String(describing: self.instanceMethods)), ") + string.append("computedVariables = \\(String(describing: self.computedVariables)), ") + string.append("storedVariables = \\(String(describing: self.storedVariables)), ") + string.append("inheritedTypes = \\(String(describing: self.inheritedTypes)), ") + string.append("inherits = \\(String(describing: self.inherits)), ") + string.append("containedTypes = \\(String(describing: self.containedTypes)), ") + string.append("parentName = \\(String(describing: self.parentName)), ") + string.append("parentTypes = \\(String(describing: self.parentTypes)), ") + string.append("attributes = \\(String(describing: self.attributes)), ") + string.append("modifiers = \\(String(describing: self.modifiers)), ") + string.append("fileName = \\(String(describing: self.fileName)), ") + string.append("genericRequirements = \\(String(describing: self.genericRequirements))") + return string + } + + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? Type else { + results.append("Incorrect type ") + return results + } + results.append(contentsOf: DiffableResult(identifier: "module").trackDifference(actual: self.module, expected: castObject.module)) + results.append(contentsOf: DiffableResult(identifier: "imports").trackDifference(actual: self.imports, expected: castObject.imports)) + results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) + results.append(contentsOf: DiffableResult(identifier: "isExtension").trackDifference(actual: self.isExtension, expected: castObject.isExtension)) + results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) + results.append(contentsOf: DiffableResult(identifier: "isUnknownExtension").trackDifference(actual: self.isUnknownExtension, expected: castObject.isUnknownExtension)) + results.append(contentsOf: DiffableResult(identifier: "isGeneric").trackDifference(actual: self.isGeneric, expected: castObject.isGeneric)) + results.append(contentsOf: DiffableResult(identifier: "localName").trackDifference(actual: self.localName, expected: castObject.localName)) + results.append(contentsOf: DiffableResult(identifier: "rawVariables").trackDifference(actual: self.rawVariables, expected: castObject.rawVariables)) + results.append(contentsOf: DiffableResult(identifier: "rawMethods").trackDifference(actual: self.rawMethods, expected: castObject.rawMethods)) + results.append(contentsOf: DiffableResult(identifier: "rawSubscripts").trackDifference(actual: self.rawSubscripts, expected: castObject.rawSubscripts)) + results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) + results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) + results.append(contentsOf: DiffableResult(identifier: "inheritedTypes").trackDifference(actual: self.inheritedTypes, expected: castObject.inheritedTypes)) + results.append(contentsOf: DiffableResult(identifier: "inherits").trackDifference(actual: self.inherits, expected: castObject.inherits)) + results.append(contentsOf: DiffableResult(identifier: "containedTypes").trackDifference(actual: self.containedTypes, expected: castObject.containedTypes)) + results.append(contentsOf: DiffableResult(identifier: "parentName").trackDifference(actual: self.parentName, expected: castObject.parentName)) + results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) + results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) + results.append(contentsOf: DiffableResult(identifier: "fileName").trackDifference(actual: self.fileName, expected: castObject.fileName)) + results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) + return results + } + + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.module) + hasher.combine(self.imports) + hasher.combine(self.typealiases) + hasher.combine(self.isExtension) + hasher.combine(self.accessLevel) + hasher.combine(self.isUnknownExtension) + hasher.combine(self.isGeneric) + hasher.combine(self.localName) + hasher.combine(self.rawVariables) + hasher.combine(self.rawMethods) + hasher.combine(self.rawSubscripts) + hasher.combine(self.annotations) + hasher.combine(self.documentation) + hasher.combine(self.inheritedTypes) + hasher.combine(self.inherits) + hasher.combine(self.containedTypes) + hasher.combine(self.parentName) + hasher.combine(self.attributes) + hasher.combine(self.modifiers) + hasher.combine(self.fileName) + hasher.combine(self.genericRequirements) + hasher.combine(kind) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? Typealias else { return false } - if self.aliasName != rhs.aliasName { return false } - if self.typeName != rhs.typeName { return false } + guard let rhs = object as? Type else { return false } if self.module != rhs.module { return false } + if self.imports != rhs.imports { return false } + if self.typealiases != rhs.typealiases { return false } + if self.isExtension != rhs.isExtension { return false } if self.accessLevel != rhs.accessLevel { return false } + if self.isUnknownExtension != rhs.isUnknownExtension { return false } + if self.isGeneric != rhs.isGeneric { return false } + if self.localName != rhs.localName { return false } + if self.rawVariables != rhs.rawVariables { return false } + if self.rawMethods != rhs.rawMethods { return false } + if self.rawSubscripts != rhs.rawSubscripts { return false } + if self.annotations != rhs.annotations { return false } + if self.documentation != rhs.documentation { return false } + if self.inheritedTypes != rhs.inheritedTypes { return false } + if self.inherits != rhs.inherits { return false } + if self.containedTypes != rhs.containedTypes { return false } if self.parentName != rhs.parentName { return false } + if self.attributes != rhs.attributes { return false } + if self.modifiers != rhs.modifiers { return false } + if self.fileName != rhs.fileName { return false } + if self.kind != rhs.kind { return false } + if self.genericRequirements != rhs.genericRequirements { return false } return true } -// sourcery:inline:Typealias.AutoCoding +// sourcery:inline:Type.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let aliasName: String = aDecoder.decode(forKey: "aliasName") else { - withVaList(["aliasName"]) { arguments in + self.module = aDecoder.decode(forKey: "module") + guard let imports: [Import] = aDecoder.decode(forKey: "imports") else { + withVaList(["imports"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.aliasName = aliasName - guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { - withVaList(["typeName"]) { arguments in + }; self.imports = imports + guard let typealiases: [String: Typealias] = aDecoder.decode(forKey: "typealiases") else { + withVaList(["typealiases"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.typeName = typeName - self.type = aDecoder.decode(forKey: "type") - self.module = aDecoder.decode(forKey: "module") - self.parent = aDecoder.decode(forKey: "parent") - guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { + }; self.typealiases = typealiases + self.isExtension = aDecoder.decode(forKey: "isExtension") + guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { withVaList(["accessLevel"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.accessLevel = accessLevel - self.parentName = aDecoder.decode(forKey: "parentName") - } - - /// :nodoc: + self.isGeneric = aDecoder.decode(forKey: "isGeneric") + guard let localName: String = aDecoder.decode(forKey: "localName") else { + withVaList(["localName"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.localName = localName + guard let rawVariables: [Variable] = aDecoder.decode(forKey: "rawVariables") else { + withVaList(["rawVariables"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.rawVariables = rawVariables + guard let rawMethods: [Method] = aDecoder.decode(forKey: "rawMethods") else { + withVaList(["rawMethods"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.rawMethods = rawMethods + guard let rawSubscripts: [Subscript] = aDecoder.decode(forKey: "rawSubscripts") else { + withVaList(["rawSubscripts"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.rawSubscripts = rawSubscripts + self.bodyBytesRange = aDecoder.decode(forKey: "bodyBytesRange") + self.completeDeclarationRange = aDecoder.decode(forKey: "completeDeclarationRange") + guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { + withVaList(["annotations"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.annotations = annotations + guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { + withVaList(["documentation"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.documentation = documentation + guard let inheritedTypes: [String] = aDecoder.decode(forKey: "inheritedTypes") else { + withVaList(["inheritedTypes"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.inheritedTypes = inheritedTypes + guard let based: [String: String] = aDecoder.decode(forKey: "based") else { + withVaList(["based"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.based = based + guard let basedTypes: [String: Type] = aDecoder.decode(forKey: "basedTypes") else { + withVaList(["basedTypes"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.basedTypes = basedTypes + guard let inherits: [String: Type] = aDecoder.decode(forKey: "inherits") else { + withVaList(["inherits"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.inherits = inherits + guard let implements: [String: Type] = aDecoder.decode(forKey: "implements") else { + withVaList(["implements"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.implements = implements + guard let containedTypes: [Type] = aDecoder.decode(forKey: "containedTypes") else { + withVaList(["containedTypes"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.containedTypes = containedTypes + guard let containedType: [String: Type] = aDecoder.decode(forKey: "containedType") else { + withVaList(["containedType"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.containedType = containedType + self.parentName = aDecoder.decode(forKey: "parentName") + self.parent = aDecoder.decode(forKey: "parent") + self.supertype = aDecoder.decode(forKey: "supertype") + guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { + withVaList(["attributes"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.attributes = attributes + guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { + withVaList(["modifiers"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.modifiers = modifiers + self.path = aDecoder.decode(forKey: "path") + guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { + withVaList(["genericRequirements"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.genericRequirements = genericRequirements + self.fileName = aDecoder.decode(forKey: "fileName") + } + + /// :nodoc: public func encode(with aCoder: NSCoder) { - aCoder.encode(self.aliasName, forKey: "aliasName") - aCoder.encode(self.typeName, forKey: "typeName") - aCoder.encode(self.type, forKey: "type") aCoder.encode(self.module, forKey: "module") - aCoder.encode(self.parent, forKey: "parent") + aCoder.encode(self.imports, forKey: "imports") + aCoder.encode(self.typealiases, forKey: "typealiases") + aCoder.encode(self.isExtension, forKey: "isExtension") aCoder.encode(self.accessLevel, forKey: "accessLevel") + aCoder.encode(self.isGeneric, forKey: "isGeneric") + aCoder.encode(self.localName, forKey: "localName") + aCoder.encode(self.rawVariables, forKey: "rawVariables") + aCoder.encode(self.rawMethods, forKey: "rawMethods") + aCoder.encode(self.rawSubscripts, forKey: "rawSubscripts") + aCoder.encode(self.bodyBytesRange, forKey: "bodyBytesRange") + aCoder.encode(self.completeDeclarationRange, forKey: "completeDeclarationRange") + aCoder.encode(self.annotations, forKey: "annotations") + aCoder.encode(self.documentation, forKey: "documentation") + aCoder.encode(self.inheritedTypes, forKey: "inheritedTypes") + aCoder.encode(self.based, forKey: "based") + aCoder.encode(self.basedTypes, forKey: "basedTypes") + aCoder.encode(self.inherits, forKey: "inherits") + aCoder.encode(self.implements, forKey: "implements") + aCoder.encode(self.containedTypes, forKey: "containedTypes") + aCoder.encode(self.containedType, forKey: "containedType") aCoder.encode(self.parentName, forKey: "parentName") + aCoder.encode(self.parent, forKey: "parent") + aCoder.encode(self.supertype, forKey: "supertype") + aCoder.encode(self.attributes, forKey: "attributes") + aCoder.encode(self.modifiers, forKey: "modifiers") + aCoder.encode(self.path, forKey: "path") + aCoder.encode(self.genericRequirements, forKey: "genericRequirements") + aCoder.encode(self.fileName, forKey: "fileName") } // sourcery:end -} -"""), - .init(name: "Typed.generated.swift", content: -""" -// Generated using Sourcery 2.0.3 — https://github.com/krzysztofzablocki/Sourcery -// DO NOT EDIT -// swiftlint:disable vertical_whitespace +} +extension Type { -extension AssociatedValue { - /// Whether type is optional. Shorthand for `typeName.isOptional` - public var isOptional: Bool { return typeName.isOptional } - /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` - public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } - /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` - public var unwrappedTypeName: String { return typeName.unwrappedTypeName } - /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` - public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } - /// Whether type is a tuple. Shorthand for `typeName.isTuple` - public var isTuple: Bool { return typeName.isTuple } - /// Whether type is a closure. Shorthand for `typeName.isClosure` - public var isClosure: Bool { return typeName.isClosure } - /// Whether type is an array. Shorthand for `typeName.isArray` - public var isArray: Bool { return typeName.isArray } - /// Whether type is a set. Shorthand for `typeName.isSet` - public var isSet: Bool { return typeName.isSet } - /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` - public var isDictionary: Bool { return typeName.isDictionary } -} -extension ClosureParameter { - /// Whether type is optional. Shorthand for `typeName.isOptional` - public var isOptional: Bool { return typeName.isOptional } - /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` - public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } - /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` - public var unwrappedTypeName: String { return typeName.unwrappedTypeName } - /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` - public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } - /// Whether type is a tuple. Shorthand for `typeName.isTuple` - public var isTuple: Bool { return typeName.isTuple } - /// Whether type is a closure. Shorthand for `typeName.isClosure` - public var isClosure: Bool { return typeName.isClosure } - /// Whether type is an array. Shorthand for `typeName.isArray` - public var isArray: Bool { return typeName.isArray } - /// Whether type is a set. Shorthand for `typeName.isSet` - public var isSet: Bool { return typeName.isSet } - /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` - public var isDictionary: Bool { return typeName.isDictionary } -} -extension MethodParameter { - /// Whether type is optional. Shorthand for `typeName.isOptional` - public var isOptional: Bool { return typeName.isOptional } - /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` - public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } - /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` - public var unwrappedTypeName: String { return typeName.unwrappedTypeName } - /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` - public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } - /// Whether type is a tuple. Shorthand for `typeName.isTuple` - public var isTuple: Bool { return typeName.isTuple } - /// Whether type is a closure. Shorthand for `typeName.isClosure` - public var isClosure: Bool { return typeName.isClosure } - /// Whether type is an array. Shorthand for `typeName.isArray` - public var isArray: Bool { return typeName.isArray } - /// Whether type is a set. Shorthand for `typeName.isSet` - public var isSet: Bool { return typeName.isSet } - /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` - public var isDictionary: Bool { return typeName.isDictionary } -} -extension TupleElement { - /// Whether type is optional. Shorthand for `typeName.isOptional` - public var isOptional: Bool { return typeName.isOptional } - /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` - public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } - /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` - public var unwrappedTypeName: String { return typeName.unwrappedTypeName } - /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` - public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } - /// Whether type is a tuple. Shorthand for `typeName.isTuple` - public var isTuple: Bool { return typeName.isTuple } - /// Whether type is a closure. Shorthand for `typeName.isClosure` - public var isClosure: Bool { return typeName.isClosure } - /// Whether type is an array. Shorthand for `typeName.isArray` - public var isArray: Bool { return typeName.isArray } - /// Whether type is a set. Shorthand for `typeName.isSet` - public var isSet: Bool { return typeName.isSet } - /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` - public var isDictionary: Bool { return typeName.isDictionary } -} -extension Typealias { - /// Whether type is optional. Shorthand for `typeName.isOptional` - public var isOptional: Bool { return typeName.isOptional } - /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` - public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } - /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` - public var unwrappedTypeName: String { return typeName.unwrappedTypeName } - /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` - public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } - /// Whether type is a tuple. Shorthand for `typeName.isTuple` - public var isTuple: Bool { return typeName.isTuple } - /// Whether type is a closure. Shorthand for `typeName.isClosure` - public var isClosure: Bool { return typeName.isClosure } - /// Whether type is an array. Shorthand for `typeName.isArray` - public var isArray: Bool { return typeName.isArray } - /// Whether type is a set. Shorthand for `typeName.isSet` - public var isSet: Bool { return typeName.isSet } - /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` - public var isDictionary: Bool { return typeName.isDictionary } -} -extension Variable { - /// Whether type is optional. Shorthand for `typeName.isOptional` - public var isOptional: Bool { return typeName.isOptional } - /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` - public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } - /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` - public var unwrappedTypeName: String { return typeName.unwrappedTypeName } - /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` - public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } - /// Whether type is a tuple. Shorthand for `typeName.isTuple` - public var isTuple: Bool { return typeName.isTuple } - /// Whether type is a closure. Shorthand for `typeName.isClosure` - public var isClosure: Bool { return typeName.isClosure } - /// Whether type is an array. Shorthand for `typeName.isArray` - public var isArray: Bool { return typeName.isArray } - /// Whether type is a set. Shorthand for `typeName.isSet` - public var isSet: Bool { return typeName.isSet } - /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` - public var isDictionary: Bool { return typeName.isDictionary } + // sourcery: skipDescription, skipJSExport + /// :nodoc: + var isClass: Bool { + let isNotClass = self is Struct || self is Enum || self is Protocol + return !isNotClass && !isExtension + } } +#endif """), - .init(name: "Typed.swift", content: -""" -import Foundation - -/// Descibes typed declaration, i.e. variable, method parameter, tuple element, enum case associated value -public protocol Typed { - - // sourcery: skipEquality, skipDescription - /// Type, if known - var type: Type? { get } - - // sourcery: skipEquality, skipDescription - /// Type name - var typeName: TypeName { get } - - // sourcery: skipEquality, skipDescription - /// Whether type is optional - var isOptional: Bool { get } - - // sourcery: skipEquality, skipDescription - /// Whether type is implicitly unwrapped optional - var isImplicitlyUnwrappedOptional: Bool { get } - - // sourcery: skipEquality, skipDescription - /// Type name without attributes and optional type information - var unwrappedTypeName: String { get } -} - -"""), - .init(name: "Variable.swift", content: + .init(name: "TypesCollection_Linux.swift", content: """ // -// Created by Krzysztof Zablocki on 13/09/2016. +// Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // - +#if !canImport(ObjectiveC) import Foundation /// :nodoc: -public typealias SourceryVariable = Variable - -/// Defines variable -public final class Variable: NSObject, SourceryModel, Typed, Annotated, Documented, Definition, Diffable { - - /// Variable name - public let name: String - - /// Variable type name - public let typeName: TypeName - - // sourcery: skipEquality, skipDescription - /// Variable type, if known, i.e. if the type is declared in the scanned sources. - /// For explanation, see - public var type: Type? - - /// Whether variable is computed and not stored - public let isComputed: Bool - - /// Whether variable is async - public let isAsync: Bool - - /// Whether variable throws - public let `throws`: Bool - - /// Whether variable is static - public let isStatic: Bool - - /// Variable read access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` - public let readAccess: String +public class TypesCollection: NSObject, AutoJSExport, SourceryDynamicMemberLookup { + public subscript(dynamicMember member: String) -> Any? { + return try? types(forKey: member) + } - /// Variable write access, i.e. `internal`, `private`, `fileprivate`, `public`, `open`. - /// For immutable variables this value is empty string - public let writeAccess: String + // sourcery:begin: skipJSExport + let all: [Type] + let types: [String: [Type]] + let validate: ((Type) throws -> Void)? + // sourcery:end - /// composed access level - /// sourcery: skipJSExport - public var accessLevel: (read: AccessLevel, write: AccessLevel) { - (read: AccessLevel(rawValue: readAccess) ?? .none, AccessLevel(rawValue: writeAccess) ?? .none) + init(types: [Type], collection: (Type) -> [String], validate: ((Type) throws -> Void)? = nil) { + self.all = types + var content = [String: [Type]]() + self.all.forEach { type in + collection(type).forEach { name in + var list = content[name] ?? [Type]() + list.append(type) + content[name] = list + } + } + self.types = content + self.validate = validate } - /// Whether variable is mutable or not - public var isMutable: Bool { - return writeAccess != AccessLevel.none.rawValue - } + public func types(forKey key: String) throws -> [Type] { + // In some configurations, the types are keyed by "ModuleName.TypeName" + var longKey: String? - /// Variable default value expression - public var defaultValue: String? + if let validate = validate { + guard let type = all.first(where: { $0.name == key }) else { + throw "Unknown type \\(key), should be used with `based`" + } - /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 - public var annotations: Annotations = [:] + try validate(type) - public var documentation: Documentation = [] + if let module = type.module { + longKey = [module, type.name].joined(separator: ".") + } + } - /// Variable attributes, i.e. `@IBOutlet`, `@IBInspectable` - public var attributes: AttributeList + // If we find the types directly, return them + if let types = types[key] { + return types + } - /// Modifiers, i.e. `private` - public var modifiers: [SourceryModifier] + // if we find a types for the longKey, return them + if let longKey = longKey, let types = types[longKey] { + return types + } - /// Whether variable is final or not - public var isFinal: Bool { - return modifiers.contains { $0.name == Attribute.Identifier.final.rawValue } + return [] } - /// Whether variable is lazy or not - public var isLazy: Bool { - return modifiers.contains { $0.name == Attribute.Identifier.lazy.rawValue } + /// :nodoc: + public func value(forKey key: String) -> Any? { + do { + return try types(forKey: key) + } catch { + Log.error(error) + return nil + } } - /// Whether variable is dynamic or not - public var isDynamic: Bool { - modifiers.contains { $0.name == Attribute.Identifier.dynamic.rawValue } + /// :nodoc: + public subscript(_ key: String) -> [Type] { + do { + return try types(forKey: key) + } catch { + Log.error(error) + return [] + } } +} +#endif - /// Reference to type name where the variable is defined, - /// nil if defined outside of any `enum`, `struct`, `class` etc - public internal(set) var definedInTypeName: TypeName? +"""), + .init(name: "Types_Linux.swift", content: +""" +// +// Created by Krzysztof Zablocki on 31/12/2016. +// Copyright (c) 2016 Pixle. All rights reserved. +// +#if !canImport(ObjectiveC) +import Foundation - /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` - public var actualDefinedInTypeName: TypeName? { - return definedInTypeName?.actualTypeName ?? definedInTypeName +// sourcery: skipJSExport +/// Collection of scanned types for accessing in templates +public final class Types: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { + public subscript(dynamicMember member: String) -> Any? { + switch member { + case "types": + return types + case "enums": + return enums + case "all": + return all + case "protocols": + return protocols + case "classes": + return classes + case "structs": + return structs + case "extensions": + return extensions + case "implementing": + return implementing + case "inheriting": + return inheriting + case "based": + return based + default: + fatalError("unable to lookup: \\(member) in \\(self)") + } } - // sourcery: skipEquality, skipDescription - /// Reference to actual type where the object is defined, - /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown - public var definedInType: Type? - /// :nodoc: - public init(name: String = "", - typeName: TypeName, - type: Type? = nil, - accessLevel: (read: AccessLevel, write: AccessLevel) = (.internal, .internal), - isComputed: Bool = false, - isAsync: Bool = false, - `throws`: Bool = false, - isStatic: Bool = false, - defaultValue: String? = nil, - attributes: AttributeList = [:], - modifiers: [SourceryModifier] = [], - annotations: [String: NSObject] = [:], - documentation: [String] = [], - definedInTypeName: TypeName? = nil) { + public let types: [Type] - self.name = name - self.typeName = typeName - self.type = type - self.isComputed = isComputed - self.isAsync = isAsync - self.`throws` = `throws` - self.isStatic = isStatic - self.defaultValue = defaultValue - self.readAccess = accessLevel.read.rawValue - self.writeAccess = accessLevel.write.rawValue - self.attributes = attributes - self.modifiers = modifiers - self.annotations = annotations - self.documentation = documentation - self.definedInTypeName = definedInTypeName + /// All known typealiases + public let typealiases: [Typealias] + + /// :nodoc: + public init(types: [Type], typealiases: [Typealias] = []) { + self.types = types + self.typealiases = typealiases } /// :nodoc: + // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " - string += "name = \\(String(describing: self.name)), " - string += "typeName = \\(String(describing: self.typeName)), " - string += "isComputed = \\(String(describing: self.isComputed)), " - string += "isAsync = \\(String(describing: self.isAsync)), " - string += "`throws` = \\(String(describing: self.`throws`)), " - string += "isStatic = \\(String(describing: self.isStatic)), " - string += "readAccess = \\(String(describing: self.readAccess)), " - string += "writeAccess = \\(String(describing: self.writeAccess)), " - string += "accessLevel = \\(String(describing: self.accessLevel)), " - string += "isMutable = \\(String(describing: self.isMutable)), " - string += "defaultValue = \\(String(describing: self.defaultValue)), " - string += "annotations = \\(String(describing: self.annotations)), " - string += "documentation = \\(String(describing: self.documentation)), " - string += "attributes = \\(String(describing: self.attributes)), " - string += "modifiers = \\(String(describing: self.modifiers)), " - string += "isFinal = \\(String(describing: self.isFinal)), " - string += "isLazy = \\(String(describing: self.isLazy)), " - string += "isDynamic = \\(String(describing: self.isDynamic)), " - string += "definedInTypeName = \\(String(describing: self.definedInTypeName)), " - string += "actualDefinedInTypeName = \\(String(describing: self.actualDefinedInTypeName))" + string.append("types = \\(String(describing: self.types)), ") + string.append("typealiases = \\(String(describing: self.typealiases))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() - guard let castObject = object as? Variable else { - results.append("Incorrect type ") + guard let castObject = object as? Types else { + results.append("Incorrect type ") return results } - results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) - results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) - results.append(contentsOf: DiffableResult(identifier: "isComputed").trackDifference(actual: self.isComputed, expected: castObject.isComputed)) - results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) - results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) - results.append(contentsOf: DiffableResult(identifier: "isStatic").trackDifference(actual: self.isStatic, expected: castObject.isStatic)) - results.append(contentsOf: DiffableResult(identifier: "readAccess").trackDifference(actual: self.readAccess, expected: castObject.readAccess)) - results.append(contentsOf: DiffableResult(identifier: "writeAccess").trackDifference(actual: self.writeAccess, expected: castObject.writeAccess)) - results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) - results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) - results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) - results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) - results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) - results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) + results.append(contentsOf: DiffableResult(identifier: "types").trackDifference(actual: self.types, expected: castObject.types)) + results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) return results } + /// :nodoc: + // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() - hasher.combine(self.name) - hasher.combine(self.typeName) - hasher.combine(self.isComputed) - hasher.combine(self.isAsync) - hasher.combine(self.`throws`) - hasher.combine(self.isStatic) - hasher.combine(self.readAccess) - hasher.combine(self.writeAccess) - hasher.combine(self.defaultValue) - hasher.combine(self.annotations) - hasher.combine(self.documentation) - hasher.combine(self.attributes) - hasher.combine(self.modifiers) - hasher.combine(self.definedInTypeName) + hasher.combine(self.types) + hasher.combine(self.typealiases) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { - guard let rhs = object as? Variable else { return false } - if self.name != rhs.name { return false } - if self.typeName != rhs.typeName { return false } - if self.isComputed != rhs.isComputed { return false } - if self.isAsync != rhs.isAsync { return false } - if self.`throws` != rhs.`throws` { return false } - if self.isStatic != rhs.isStatic { return false } - if self.readAccess != rhs.readAccess { return false } - if self.writeAccess != rhs.writeAccess { return false } - if self.defaultValue != rhs.defaultValue { return false } - if self.annotations != rhs.annotations { return false } - if self.documentation != rhs.documentation { return false } - if self.attributes != rhs.attributes { return false } - if self.modifiers != rhs.modifiers { return false } - if self.definedInTypeName != rhs.definedInTypeName { return false } + guard let rhs = object as? Types else { return false } + if self.types != rhs.types { return false } + if self.typealiases != rhs.typealiases { return false } return true } -// sourcery:inline:Variable.AutoCoding +// sourcery:inline:Types.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { - guard let name: String = aDecoder.decode(forKey: "name") else { - withVaList(["name"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.name = name - guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { - withVaList(["typeName"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.typeName = typeName - self.type = aDecoder.decode(forKey: "type") - self.isComputed = aDecoder.decode(forKey: "isComputed") - self.isAsync = aDecoder.decode(forKey: "isAsync") - self.`throws` = aDecoder.decode(forKey: "`throws`") - self.isStatic = aDecoder.decode(forKey: "isStatic") - guard let readAccess: String = aDecoder.decode(forKey: "readAccess") else { - withVaList(["readAccess"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.readAccess = readAccess - guard let writeAccess: String = aDecoder.decode(forKey: "writeAccess") else { - withVaList(["writeAccess"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.writeAccess = writeAccess - self.defaultValue = aDecoder.decode(forKey: "defaultValue") - guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { - withVaList(["annotations"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.annotations = annotations - guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { - withVaList(["documentation"]) { arguments in - NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) - } - fatalError() - }; self.documentation = documentation - guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { - withVaList(["attributes"]) { arguments in + guard let types: [Type] = aDecoder.decode(forKey: "types") else { + withVaList(["types"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.attributes = attributes - guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { - withVaList(["modifiers"]) { arguments in + }; self.types = types + guard let typealiases: [Typealias] = aDecoder.decode(forKey: "typealiases") else { + withVaList(["typealiases"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() - }; self.modifiers = modifiers - self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") - self.definedInType = aDecoder.decode(forKey: "definedInType") + }; self.typealiases = typealiases } /// :nodoc: public func encode(with aCoder: NSCoder) { - aCoder.encode(self.name, forKey: "name") - aCoder.encode(self.typeName, forKey: "typeName") - aCoder.encode(self.type, forKey: "type") - aCoder.encode(self.isComputed, forKey: "isComputed") - aCoder.encode(self.isAsync, forKey: "isAsync") - aCoder.encode(self.`throws`, forKey: "`throws`") - aCoder.encode(self.isStatic, forKey: "isStatic") - aCoder.encode(self.readAccess, forKey: "readAccess") - aCoder.encode(self.writeAccess, forKey: "writeAccess") - aCoder.encode(self.defaultValue, forKey: "defaultValue") - aCoder.encode(self.annotations, forKey: "annotations") - aCoder.encode(self.documentation, forKey: "documentation") - aCoder.encode(self.attributes, forKey: "attributes") - aCoder.encode(self.modifiers, forKey: "modifiers") - aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") - aCoder.encode(self.definedInType, forKey: "definedInType") + aCoder.encode(self.types, forKey: "types") + aCoder.encode(self.typealiases, forKey: "typealiases") } // sourcery:end + + // sourcery: skipDescription, skipEquality, skipCoding + /// :nodoc: + public lazy internal(set) var typesByName: [String: Type] = { + var typesByName = [String: Type]() + self.types.forEach { typesByName[$0.globalName] = $0 } + return typesByName + }() + + // sourcery: skipDescription, skipEquality, skipCoding + /// :nodoc: + public lazy internal(set) var typesaliasesByName: [String: Typealias] = { + var typesaliasesByName = [String: Typealias]() + self.typealiases.forEach { typesaliasesByName[$0.name] = $0 } + return typesaliasesByName + }() + + // sourcery: skipDescription, skipEquality, skipCoding + /// All known types, excluding protocols or protocol compositions. + public lazy internal(set) var all: [Type] = { + return self.types.filter { !($0 is Protocol || $0 is ProtocolComposition) } + }() + + // sourcery: skipDescription, skipEquality, skipCoding + /// All known protocols + public lazy internal(set) var protocols: [Protocol] = { + return self.types.compactMap { $0 as? Protocol } + }() + + // sourcery: skipDescription, skipEquality, skipCoding + /// All known protocol compositions + public lazy internal(set) var protocolCompositions: [ProtocolComposition] = { + return self.types.compactMap { $0 as? ProtocolComposition } + }() + + // sourcery: skipDescription, skipEquality, skipCoding + /// All known classes + public lazy internal(set) var classes: [Class] = { + return self.all.compactMap { $0 as? Class } + }() + + // sourcery: skipDescription, skipEquality, skipCoding + /// All known structs + public lazy internal(set) var structs: [Struct] = { + return self.all.compactMap { $0 as? Struct } + }() + + // sourcery: skipDescription, skipEquality, skipCoding + /// All known enums + public lazy internal(set) var enums: [Enum] = { + return self.all.compactMap { $0 as? Enum } + }() + + // sourcery: skipDescription, skipEquality, skipCoding + /// All known extensions + public lazy internal(set) var extensions: [Type] = { + return self.all.compactMap { $0.isExtension ? $0 : nil } + }() + + // sourcery: skipDescription, skipEquality, skipCoding + /// Types based on any other type, grouped by its name, even if they are not known. + /// `types.based.MyType` returns list of types based on `MyType` + public lazy internal(set) var based: TypesCollection = { + TypesCollection( + types: self.types, + collection: { Array($0.based.keys) } + ) + }() + + // sourcery: skipDescription, skipEquality, skipCoding + /// Classes inheriting from any known class, grouped by its name. + /// `types.inheriting.MyClass` returns list of types inheriting from `MyClass` + public lazy internal(set) var inheriting: TypesCollection = { + TypesCollection( + types: self.types, + collection: { Array($0.inherits.keys) }, + validate: { type in + guard type is Class else { + throw "\\(type.name) is not a class and should be used with `implementing` or `based`" + } + }) + }() + + // sourcery: skipDescription, skipEquality, skipCoding + /// Types implementing known protocol, grouped by its name. + /// `types.implementing.MyProtocol` returns list of types implementing `MyProtocol` + public lazy internal(set) var implementing: TypesCollection = { + TypesCollection( + types: self.types, + collection: { Array($0.implements.keys) }, + validate: { type in + guard type is Protocol else { + throw "\\(type.name) is a class and should be used with `inheriting` or `based`" + } + }) + }() +} +#endif + +"""), + .init(name: "Variable_Linux.swift", content: +""" +// +// Created by Krzysztof Zablocki on 13/09/2016. +// Copyright (c) 2016 Pixle. All rights reserved. +// +#if !canImport(ObjectiveC) +import Foundation + +/// :nodoc: +public typealias SourceryVariable = Variable + +/// Defines variable +public final class Variable: NSObject, SourceryModel, Typed, Annotated, Documented, Definition, Diffable, SourceryDynamicMemberLookup { + public subscript(dynamicMember member: String) -> Any? { + switch member { + case "readAccess": + return readAccess + case "annotations": + return annotations + case "isOptional": + return isOptional + case "name": + return name + case "typeName": + return typeName + case "type": + return type + case "definedInType": + return definedInType + case "isStatic": + return isStatic + case "isAsync": + return isAsync + case "throws": + return `throws` + case "isArray": + return isArray + case "isDictionary": + return isDictionary + case "isDynamic": + return isDynamic + default: + fatalError("unable to lookup: \\(member) in \\(self)") + } + } + + /// Variable name + public let name: String + + /// Variable type name + public let typeName: TypeName + + // sourcery: skipEquality, skipDescription + /// Variable type, if known, i.e. if the type is declared in the scanned sources. + /// For explanation, see + public var type: Type? + + /// Whether variable is computed and not stored + public let isComputed: Bool + + /// Whether variable is async + public let isAsync: Bool + + /// Whether variable throws + public let `throws`: Bool + + /// Whether variable is static + public let isStatic: Bool + + /// Variable read access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` + public let readAccess: String + + /// Variable write access, i.e. `internal`, `private`, `fileprivate`, `public`, `open`. + /// For immutable variables this value is empty string + public let writeAccess: String + + /// composed access level + /// sourcery: skipJSExport + public var accessLevel: (read: AccessLevel, write: AccessLevel) { + (read: AccessLevel(rawValue: readAccess) ?? .none, AccessLevel(rawValue: writeAccess) ?? .none) + } + + /// Whether variable is mutable or not + public var isMutable: Bool { + return writeAccess != AccessLevel.none.rawValue + } + + /// Variable default value expression + public var defaultValue: String? + + /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 + public var annotations: Annotations = [:] + + public var documentation: Documentation = [] + + /// Variable attributes, i.e. `@IBOutlet`, `@IBInspectable` + public var attributes: AttributeList + + /// Modifiers, i.e. `private` + public var modifiers: [SourceryModifier] + + /// Whether variable is final or not + public var isFinal: Bool { + return modifiers.contains { $0.name == Attribute.Identifier.final.rawValue } + } + + /// Whether variable is lazy or not + public var isLazy: Bool { + return modifiers.contains { $0.name == Attribute.Identifier.lazy.rawValue } + } + + /// Whether variable is dynamic or not + public var isDynamic: Bool { + modifiers.contains { $0.name == Attribute.Identifier.dynamic.rawValue } + } + + /// Reference to type name where the variable is defined, + /// nil if defined outside of any `enum`, `struct`, `class` etc + public internal(set) var definedInTypeName: TypeName? + + /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` + public var actualDefinedInTypeName: TypeName? { + return definedInTypeName?.actualTypeName ?? definedInTypeName + } + + // sourcery: skipEquality, skipDescription + /// Reference to actual type where the object is defined, + /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown + public var definedInType: Type? + + /// :nodoc: + public init(name: String = "", + typeName: TypeName, + type: Type? = nil, + accessLevel: (read: AccessLevel, write: AccessLevel) = (.internal, .internal), + isComputed: Bool = false, + isAsync: Bool = false, + `throws`: Bool = false, + isStatic: Bool = false, + defaultValue: String? = nil, + attributes: AttributeList = [:], + modifiers: [SourceryModifier] = [], + annotations: [String: NSObject] = [:], + documentation: [String] = [], + definedInTypeName: TypeName? = nil) { + + self.name = name + self.typeName = typeName + self.type = type + self.isComputed = isComputed + self.isAsync = isAsync + self.`throws` = `throws` + self.isStatic = isStatic + self.defaultValue = defaultValue + self.readAccess = accessLevel.read.rawValue + self.writeAccess = accessLevel.write.rawValue + self.attributes = attributes + self.modifiers = modifiers + self.annotations = annotations + self.documentation = documentation + self.definedInTypeName = definedInTypeName + } + + /// :nodoc: + // sourcery: skipJSExport + override public var description: String { + var string = "\\(Swift.type(of: self)): " + string.append("name = \\(String(describing: self.name)), ") + string.append("typeName = \\(String(describing: self.typeName)), ") + string.append("isComputed = \\(String(describing: self.isComputed)), ") + string.append("isAsync = \\(String(describing: self.isAsync)), ") + string.append("`throws` = \\(String(describing: self.`throws`)), ") + string.append("isStatic = \\(String(describing: self.isStatic)), ") + string.append("readAccess = \\(String(describing: self.readAccess)), ") + string.append("writeAccess = \\(String(describing: self.writeAccess)), ") + string.append("accessLevel = \\(String(describing: self.accessLevel)), ") + string.append("isMutable = \\(String(describing: self.isMutable)), ") + string.append("defaultValue = \\(String(describing: self.defaultValue)), ") + string.append("annotations = \\(String(describing: self.annotations)), ") + string.append("documentation = \\(String(describing: self.documentation)), ") + string.append("attributes = \\(String(describing: self.attributes)), ") + string.append("modifiers = \\(String(describing: self.modifiers)), ") + string.append("isFinal = \\(String(describing: self.isFinal)), ") + string.append("isLazy = \\(String(describing: self.isLazy)), ") + string.append("isDynamic = \\(String(describing: self.isDynamic)), ") + string.append("definedInTypeName = \\(String(describing: self.definedInTypeName)), ") + string.append("actualDefinedInTypeName = \\(String(describing: self.actualDefinedInTypeName))") + return string + } + + public func diffAgainst(_ object: Any?) -> DiffableResult { + let results = DiffableResult() + guard let castObject = object as? Variable else { + results.append("Incorrect type ") + return results + } + results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) + results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) + results.append(contentsOf: DiffableResult(identifier: "isComputed").trackDifference(actual: self.isComputed, expected: castObject.isComputed)) + results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) + results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) + results.append(contentsOf: DiffableResult(identifier: "isStatic").trackDifference(actual: self.isStatic, expected: castObject.isStatic)) + results.append(contentsOf: DiffableResult(identifier: "readAccess").trackDifference(actual: self.readAccess, expected: castObject.readAccess)) + results.append(contentsOf: DiffableResult(identifier: "writeAccess").trackDifference(actual: self.writeAccess, expected: castObject.writeAccess)) + results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) + results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) + results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) + results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) + results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) + results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) + return results + } + + /// :nodoc: + // sourcery: skipJSExport + public override var hash: Int { + var hasher = Hasher() + hasher.combine(self.name) + hasher.combine(self.typeName) + hasher.combine(self.isComputed) + hasher.combine(self.isAsync) + hasher.combine(self.`throws`) + hasher.combine(self.isStatic) + hasher.combine(self.readAccess) + hasher.combine(self.writeAccess) + hasher.combine(self.defaultValue) + hasher.combine(self.annotations) + hasher.combine(self.documentation) + hasher.combine(self.attributes) + hasher.combine(self.modifiers) + hasher.combine(self.definedInTypeName) + return hasher.finalize() + } + + /// :nodoc: + public override func isEqual(_ object: Any?) -> Bool { + guard let rhs = object as? Variable else { return false } + if self.name != rhs.name { return false } + if self.typeName != rhs.typeName { return false } + if self.isComputed != rhs.isComputed { return false } + if self.isAsync != rhs.isAsync { return false } + if self.`throws` != rhs.`throws` { return false } + if self.isStatic != rhs.isStatic { return false } + if self.readAccess != rhs.readAccess { return false } + if self.writeAccess != rhs.writeAccess { return false } + if self.defaultValue != rhs.defaultValue { return false } + if self.annotations != rhs.annotations { return false } + if self.documentation != rhs.documentation { return false } + if self.attributes != rhs.attributes { return false } + if self.modifiers != rhs.modifiers { return false } + if self.definedInTypeName != rhs.definedInTypeName { return false } + return true + } + +// sourcery:inline:Variable.AutoCoding + + /// :nodoc: + required public init?(coder aDecoder: NSCoder) { + guard let name: String = aDecoder.decode(forKey: "name") else { + withVaList(["name"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.name = name + guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { + withVaList(["typeName"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.typeName = typeName + self.type = aDecoder.decode(forKey: "type") + self.isComputed = aDecoder.decode(forKey: "isComputed") + self.isAsync = aDecoder.decode(forKey: "isAsync") + self.`throws` = aDecoder.decode(forKey: "`throws`") + self.isStatic = aDecoder.decode(forKey: "isStatic") + guard let readAccess: String = aDecoder.decode(forKey: "readAccess") else { + withVaList(["readAccess"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.readAccess = readAccess + guard let writeAccess: String = aDecoder.decode(forKey: "writeAccess") else { + withVaList(["writeAccess"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.writeAccess = writeAccess + self.defaultValue = aDecoder.decode(forKey: "defaultValue") + guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { + withVaList(["annotations"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.annotations = annotations + guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { + withVaList(["documentation"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.documentation = documentation + guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { + withVaList(["attributes"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.attributes = attributes + guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { + withVaList(["modifiers"]) { arguments in + NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) + } + fatalError() + }; self.modifiers = modifiers + self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") + self.definedInType = aDecoder.decode(forKey: "definedInType") + } + + /// :nodoc: + public func encode(with aCoder: NSCoder) { + aCoder.encode(self.name, forKey: "name") + aCoder.encode(self.typeName, forKey: "typeName") + aCoder.encode(self.type, forKey: "type") + aCoder.encode(self.isComputed, forKey: "isComputed") + aCoder.encode(self.isAsync, forKey: "isAsync") + aCoder.encode(self.`throws`, forKey: "`throws`") + aCoder.encode(self.isStatic, forKey: "isStatic") + aCoder.encode(self.readAccess, forKey: "readAccess") + aCoder.encode(self.writeAccess, forKey: "writeAccess") + aCoder.encode(self.defaultValue, forKey: "defaultValue") + aCoder.encode(self.annotations, forKey: "annotations") + aCoder.encode(self.documentation, forKey: "documentation") + aCoder.encode(self.attributes, forKey: "attributes") + aCoder.encode(self.modifiers, forKey: "modifiers") + aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") + aCoder.encode(self.definedInType, forKey: "definedInType") + } +// sourcery:end +} +#endif + +"""), + .init(name: "AutoHashable.generated.swift", content: +""" +// Generated using Sourcery 1.3.1 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT +// swiftlint:disable all + + +// MARK: - AutoHashable for classes, protocols, structs + +// MARK: - AutoHashable for Enums + +"""), + .init(name: "Coding.generated.swift", content: +""" +// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT +// swiftlint:disable vertical_whitespace trailing_newline + +import Foundation + + +extension NSCoder { + + @nonobjc func decode(forKey: String) -> String? { + return self.maybeDecode(forKey: forKey) as String? + } + + @nonobjc func decode(forKey: String) -> TypeName? { + return self.maybeDecode(forKey: forKey) as TypeName? + } + + @nonobjc func decode(forKey: String) -> AccessLevel? { + return self.maybeDecode(forKey: forKey) as AccessLevel? + } + + @nonobjc func decode(forKey: String) -> Bool { + return self.decodeBool(forKey: forKey) + } + + @nonobjc func decode(forKey: String) -> Int { + return self.decodeInteger(forKey: forKey) + } + + func decode(forKey: String) -> E? { + return maybeDecode(forKey: forKey) as E? + } + + fileprivate func maybeDecode(forKey: String) -> E? { + guard let object = self.decodeObject(forKey: forKey) else { + return nil + } + + return object as? E + } + +} + +extension ArrayType: NSCoding {} + +extension AssociatedType: NSCoding {} + +extension AssociatedValue: NSCoding {} + +extension Attribute: NSCoding {} + +extension BytesRange: NSCoding {} + + +extension ClosureParameter: NSCoding {} + +extension ClosureType: NSCoding {} + +extension DictionaryType: NSCoding {} + + +extension EnumCase: NSCoding {} + +extension FileParserResult: NSCoding {} + +extension GenericParameter: NSCoding {} + +extension GenericRequirement: NSCoding {} + +extension GenericType: NSCoding {} + +extension GenericTypeParameter: NSCoding {} + +extension Import: NSCoding {} + +extension Method: NSCoding {} + +extension MethodParameter: NSCoding {} + +extension Modifier: NSCoding {} + + + +extension SetType: NSCoding {} + + +extension Subscript: NSCoding {} + +extension TupleElement: NSCoding {} + +extension TupleType: NSCoding {} + +extension Type: NSCoding {} + +extension TypeName: NSCoding {} + +extension Typealias: NSCoding {} + +extension Types: NSCoding {} + +extension Variable: NSCoding {} + + +"""), + .init(name: "JSExport.generated.swift", content: +""" +// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT +// swiftlint:disable vertical_whitespace trailing_newline + +#if canImport(JavaScriptCore) +import JavaScriptCore + +@objc protocol ActorAutoJSExport: JSExport { + var kind: String { get } + var isFinal: Bool { get } + var module: String? { get } + var imports: [Import] { get } + var allImports: [Import] { get } + var typealiases: [String: Typealias] { get } + var accessLevel: String { get } + var name: String { get } + var isUnknownExtension: Bool { get } + var globalName: String { get } + var isGeneric: Bool { get } + var localName: String { get } + var variables: [Variable] { get } + var rawVariables: [Variable] { get } + var allVariables: [Variable] { get } + var methods: [Method] { get } + var rawMethods: [Method] { get } + var allMethods: [Method] { get } + var subscripts: [Subscript] { get } + var rawSubscripts: [Subscript] { get } + var allSubscripts: [Subscript] { get } + var initializers: [Method] { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var staticVariables: [Variable] { get } + var staticMethods: [Method] { get } + var classMethods: [Method] { get } + var instanceVariables: [Variable] { get } + var instanceMethods: [Method] { get } + var computedVariables: [Variable] { get } + var storedVariables: [Variable] { get } + var inheritedTypes: [String] { get } + var based: [String: String] { get } + var basedTypes: [String: Type] { get } + var inherits: [String: Type] { get } + var implements: [String: Type] { get } + var containedTypes: [Type] { get } + var containedType: [String: Type] { get } + var parentName: String? { get } + var parent: Type? { get } + var supertype: Type? { get } + var attributes: AttributeList { get } + var modifiers: [SourceryModifier] { get } + var genericRequirements: [GenericRequirement] { get } + var fileName: String? { get } +} + +extension Actor: ActorAutoJSExport {} + +@objc protocol ArrayTypeAutoJSExport: JSExport { + var name: String { get } + var elementTypeName: TypeName { get } + var elementType: Type? { get } + var asGeneric: GenericType { get } + var asSource: String { get } +} + +extension ArrayType: ArrayTypeAutoJSExport {} + +@objc protocol AssociatedTypeAutoJSExport: JSExport { + var name: String { get } + var typeName: TypeName? { get } + var type: Type? { get } +} + +extension AssociatedType: AssociatedTypeAutoJSExport {} + +@objc protocol AssociatedValueAutoJSExport: JSExport { + var localName: String? { get } + var externalName: String? { get } + var typeName: TypeName { get } + var type: Type? { get } + var defaultValue: String? { get } + var annotations: Annotations { get } + var isOptional: Bool { get } + var isImplicitlyUnwrappedOptional: Bool { get } + var unwrappedTypeName: String { get } +} + +extension AssociatedValue: AssociatedValueAutoJSExport {} + +@objc protocol AttributeAutoJSExport: JSExport { + var name: String { get } + var arguments: [String: NSObject] { get } + var asSource: String { get } + var description: String { get } +} + +extension Attribute: AttributeAutoJSExport {} + +@objc protocol BytesRangeAutoJSExport: JSExport { + var offset: Int64 { get } + var length: Int64 { get } +} + +extension BytesRange: BytesRangeAutoJSExport {} + +@objc protocol ClassAutoJSExport: JSExport { + var kind: String { get } + var isFinal: Bool { get } + var module: String? { get } + var imports: [Import] { get } + var allImports: [Import] { get } + var typealiases: [String: Typealias] { get } + var accessLevel: String { get } + var name: String { get } + var isUnknownExtension: Bool { get } + var globalName: String { get } + var isGeneric: Bool { get } + var localName: String { get } + var variables: [Variable] { get } + var rawVariables: [Variable] { get } + var allVariables: [Variable] { get } + var methods: [Method] { get } + var rawMethods: [Method] { get } + var allMethods: [Method] { get } + var subscripts: [Subscript] { get } + var rawSubscripts: [Subscript] { get } + var allSubscripts: [Subscript] { get } + var initializers: [Method] { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var staticVariables: [Variable] { get } + var staticMethods: [Method] { get } + var classMethods: [Method] { get } + var instanceVariables: [Variable] { get } + var instanceMethods: [Method] { get } + var computedVariables: [Variable] { get } + var storedVariables: [Variable] { get } + var inheritedTypes: [String] { get } + var based: [String: String] { get } + var basedTypes: [String: Type] { get } + var inherits: [String: Type] { get } + var implements: [String: Type] { get } + var containedTypes: [Type] { get } + var containedType: [String: Type] { get } + var parentName: String? { get } + var parent: Type? { get } + var supertype: Type? { get } + var attributes: AttributeList { get } + var modifiers: [SourceryModifier] { get } + var genericRequirements: [GenericRequirement] { get } + var fileName: String? { get } +} + +extension Class: ClassAutoJSExport {} + +@objc protocol ClosureParameterAutoJSExport: JSExport { + var argumentLabel: String? { get } + var name: String? { get } + var typeName: TypeName { get } + var `inout`: Bool { get } + var type: Type? { get } + var isVariadic: Bool { get } + var typeAttributes: AttributeList { get } + var defaultValue: String? { get } + var annotations: Annotations { get } + var asSource: String { get } + var isOptional: Bool { get } + var isImplicitlyUnwrappedOptional: Bool { get } + var unwrappedTypeName: String { get } +} + +extension ClosureParameter: ClosureParameterAutoJSExport {} + +@objc protocol ClosureTypeAutoJSExport: JSExport { + var name: String { get } + var parameters: [ClosureParameter] { get } + var returnTypeName: TypeName { get } + var actualReturnTypeName: TypeName { get } + var returnType: Type? { get } + var isOptionalReturnType: Bool { get } + var isImplicitlyUnwrappedOptionalReturnType: Bool { get } + var unwrappedReturnTypeName: String { get } + var isAsync: Bool { get } + var asyncKeyword: String? { get } + var `throws`: Bool { get } + var throwsOrRethrowsKeyword: String? { get } + var asSource: String { get } +} + +extension ClosureType: ClosureTypeAutoJSExport {} + +@objc protocol DictionaryTypeAutoJSExport: JSExport { + var name: String { get } + var valueTypeName: TypeName { get } + var valueType: Type? { get } + var keyTypeName: TypeName { get } + var keyType: Type? { get } + var asGeneric: GenericType { get } + var asSource: String { get } +} + +extension DictionaryType: DictionaryTypeAutoJSExport {} + +@objc protocol EnumAutoJSExport: JSExport { + var kind: String { get } + var cases: [EnumCase] { get } + var rawTypeName: TypeName? { get } + var hasRawType: Bool { get } + var rawType: Type? { get } + var based: [String: String] { get } + var hasAssociatedValues: Bool { get } + var module: String? { get } + var imports: [Import] { get } + var allImports: [Import] { get } + var typealiases: [String: Typealias] { get } + var accessLevel: String { get } + var name: String { get } + var isUnknownExtension: Bool { get } + var globalName: String { get } + var isGeneric: Bool { get } + var localName: String { get } + var variables: [Variable] { get } + var rawVariables: [Variable] { get } + var allVariables: [Variable] { get } + var methods: [Method] { get } + var rawMethods: [Method] { get } + var allMethods: [Method] { get } + var subscripts: [Subscript] { get } + var rawSubscripts: [Subscript] { get } + var allSubscripts: [Subscript] { get } + var initializers: [Method] { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var staticVariables: [Variable] { get } + var staticMethods: [Method] { get } + var classMethods: [Method] { get } + var instanceVariables: [Variable] { get } + var instanceMethods: [Method] { get } + var computedVariables: [Variable] { get } + var storedVariables: [Variable] { get } + var inheritedTypes: [String] { get } + var basedTypes: [String: Type] { get } + var inherits: [String: Type] { get } + var implements: [String: Type] { get } + var containedTypes: [Type] { get } + var containedType: [String: Type] { get } + var parentName: String? { get } + var parent: Type? { get } + var supertype: Type? { get } + var attributes: AttributeList { get } + var modifiers: [SourceryModifier] { get } + var genericRequirements: [GenericRequirement] { get } + var fileName: String? { get } +} + +extension Enum: EnumAutoJSExport {} + +@objc protocol EnumCaseAutoJSExport: JSExport { + var name: String { get } + var rawValue: String? { get } + var associatedValues: [AssociatedValue] { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var indirect: Bool { get } + var hasAssociatedValue: Bool { get } +} + +extension EnumCase: EnumCaseAutoJSExport {} + + +@objc protocol GenericParameterAutoJSExport: JSExport { + var name: String { get } + var inheritedTypeName: TypeName? { get } +} + +extension GenericParameter: GenericParameterAutoJSExport {} + +@objc protocol GenericRequirementAutoJSExport: JSExport { + var leftType: AssociatedType { get } + var rightType: GenericTypeParameter { get } + var relationship: String { get } + var relationshipSyntax: String { get } +} + +extension GenericRequirement: GenericRequirementAutoJSExport {} + +@objc protocol GenericTypeAutoJSExport: JSExport { + var name: String { get } + var typeParameters: [GenericTypeParameter] { get } + var asSource: String { get } + var description: String { get } +} + +extension GenericType: GenericTypeAutoJSExport {} + +@objc protocol GenericTypeParameterAutoJSExport: JSExport { + var typeName: TypeName { get } + var type: Type? { get } +} + +extension GenericTypeParameter: GenericTypeParameterAutoJSExport {} + +@objc protocol ImportAutoJSExport: JSExport { + var kind: String? { get } + var path: String { get } + var description: String { get } + var moduleName: String { get } +} + +extension Import: ImportAutoJSExport {} + +@objc protocol MethodAutoJSExport: JSExport { + var name: String { get } + var selectorName: String { get } + var shortName: String { get } + var callName: String { get } + var parameters: [MethodParameter] { get } + var returnTypeName: TypeName { get } + var actualReturnTypeName: TypeName { get } + var returnType: Type? { get } + var isOptionalReturnType: Bool { get } + var isImplicitlyUnwrappedOptionalReturnType: Bool { get } + var unwrappedReturnTypeName: String { get } + var isAsync: Bool { get } + var `throws`: Bool { get } + var `rethrows`: Bool { get } + var accessLevel: String { get } + var isStatic: Bool { get } + var isClass: Bool { get } + var isInitializer: Bool { get } + var isDeinitializer: Bool { get } + var isFailableInitializer: Bool { get } + var isConvenienceInitializer: Bool { get } + var isRequired: Bool { get } + var isFinal: Bool { get } + var isMutating: Bool { get } + var isGeneric: Bool { get } + var isOptional: Bool { get } + var isNonisolated: Bool { get } + var isDynamic: Bool { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var definedInTypeName: TypeName? { get } + var actualDefinedInTypeName: TypeName? { get } + var definedInType: Type? { get } + var attributes: AttributeList { get } + var modifiers: [SourceryModifier] { get } + var genericRequirements: [GenericRequirement] { get } +} + +extension Method: MethodAutoJSExport {} + +@objc protocol MethodParameterAutoJSExport: JSExport { + var argumentLabel: String? { get } + var name: String { get } + var typeName: TypeName { get } + var `inout`: Bool { get } + var isVariadic: Bool { get } + var type: Type? { get } + var typeAttributes: AttributeList { get } + var defaultValue: String? { get } + var annotations: Annotations { get } + var asSource: String { get } + var isOptional: Bool { get } + var isImplicitlyUnwrappedOptional: Bool { get } + var unwrappedTypeName: String { get } +} + +extension MethodParameter: MethodParameterAutoJSExport {} + +@objc protocol ModifierAutoJSExport: JSExport { + var name: String { get } + var detail: String? { get } + var asSource: String { get } +} + +extension Modifier: ModifierAutoJSExport {} + +@objc protocol ProtocolAutoJSExport: JSExport { + var kind: String { get } + var associatedTypes: [String: AssociatedType] { get } + var genericRequirements: [GenericRequirement] { get } + var module: String? { get } + var imports: [Import] { get } + var allImports: [Import] { get } + var typealiases: [String: Typealias] { get } + var accessLevel: String { get } + var name: String { get } + var isUnknownExtension: Bool { get } + var globalName: String { get } + var isGeneric: Bool { get } + var localName: String { get } + var variables: [Variable] { get } + var rawVariables: [Variable] { get } + var allVariables: [Variable] { get } + var methods: [Method] { get } + var rawMethods: [Method] { get } + var allMethods: [Method] { get } + var subscripts: [Subscript] { get } + var rawSubscripts: [Subscript] { get } + var allSubscripts: [Subscript] { get } + var initializers: [Method] { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var staticVariables: [Variable] { get } + var staticMethods: [Method] { get } + var classMethods: [Method] { get } + var instanceVariables: [Variable] { get } + var instanceMethods: [Method] { get } + var computedVariables: [Variable] { get } + var storedVariables: [Variable] { get } + var inheritedTypes: [String] { get } + var based: [String: String] { get } + var basedTypes: [String: Type] { get } + var inherits: [String: Type] { get } + var implements: [String: Type] { get } + var containedTypes: [Type] { get } + var containedType: [String: Type] { get } + var parentName: String? { get } + var parent: Type? { get } + var supertype: Type? { get } + var attributes: AttributeList { get } + var modifiers: [SourceryModifier] { get } + var fileName: String? { get } +} + +extension Protocol: ProtocolAutoJSExport {} + +@objc protocol ProtocolCompositionAutoJSExport: JSExport { + var kind: String { get } + var composedTypeNames: [TypeName] { get } + var composedTypes: [Type]? { get } + var module: String? { get } + var imports: [Import] { get } + var allImports: [Import] { get } + var typealiases: [String: Typealias] { get } + var accessLevel: String { get } + var name: String { get } + var isUnknownExtension: Bool { get } + var globalName: String { get } + var isGeneric: Bool { get } + var localName: String { get } + var variables: [Variable] { get } + var rawVariables: [Variable] { get } + var allVariables: [Variable] { get } + var methods: [Method] { get } + var rawMethods: [Method] { get } + var allMethods: [Method] { get } + var subscripts: [Subscript] { get } + var rawSubscripts: [Subscript] { get } + var allSubscripts: [Subscript] { get } + var initializers: [Method] { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var staticVariables: [Variable] { get } + var staticMethods: [Method] { get } + var classMethods: [Method] { get } + var instanceVariables: [Variable] { get } + var instanceMethods: [Method] { get } + var computedVariables: [Variable] { get } + var storedVariables: [Variable] { get } + var inheritedTypes: [String] { get } + var based: [String: String] { get } + var basedTypes: [String: Type] { get } + var inherits: [String: Type] { get } + var implements: [String: Type] { get } + var containedTypes: [Type] { get } + var containedType: [String: Type] { get } + var parentName: String? { get } + var parent: Type? { get } + var supertype: Type? { get } + var attributes: AttributeList { get } + var modifiers: [SourceryModifier] { get } + var genericRequirements: [GenericRequirement] { get } + var fileName: String? { get } +} + +extension ProtocolComposition: ProtocolCompositionAutoJSExport {} + +@objc protocol SetTypeAutoJSExport: JSExport { + var name: String { get } + var elementTypeName: TypeName { get } + var elementType: Type? { get } + var asGeneric: GenericType { get } + var asSource: String { get } +} + +extension SetType: SetTypeAutoJSExport {} + + + +@objc protocol StructAutoJSExport: JSExport { + var kind: String { get } + var module: String? { get } + var imports: [Import] { get } + var allImports: [Import] { get } + var typealiases: [String: Typealias] { get } + var accessLevel: String { get } + var name: String { get } + var isUnknownExtension: Bool { get } + var globalName: String { get } + var isGeneric: Bool { get } + var localName: String { get } + var variables: [Variable] { get } + var rawVariables: [Variable] { get } + var allVariables: [Variable] { get } + var methods: [Method] { get } + var rawMethods: [Method] { get } + var allMethods: [Method] { get } + var subscripts: [Subscript] { get } + var rawSubscripts: [Subscript] { get } + var allSubscripts: [Subscript] { get } + var initializers: [Method] { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var staticVariables: [Variable] { get } + var staticMethods: [Method] { get } + var classMethods: [Method] { get } + var instanceVariables: [Variable] { get } + var instanceMethods: [Method] { get } + var computedVariables: [Variable] { get } + var storedVariables: [Variable] { get } + var inheritedTypes: [String] { get } + var based: [String: String] { get } + var basedTypes: [String: Type] { get } + var inherits: [String: Type] { get } + var implements: [String: Type] { get } + var containedTypes: [Type] { get } + var containedType: [String: Type] { get } + var parentName: String? { get } + var parent: Type? { get } + var supertype: Type? { get } + var attributes: AttributeList { get } + var modifiers: [SourceryModifier] { get } + var genericRequirements: [GenericRequirement] { get } + var fileName: String? { get } +} + +extension Struct: StructAutoJSExport {} + +@objc protocol SubscriptAutoJSExport: JSExport { + var parameters: [MethodParameter] { get } + var returnTypeName: TypeName { get } + var actualReturnTypeName: TypeName { get } + var returnType: Type? { get } + var isOptionalReturnType: Bool { get } + var isImplicitlyUnwrappedOptionalReturnType: Bool { get } + var unwrappedReturnTypeName: String { get } + var isFinal: Bool { get } + var readAccess: String { get } + var writeAccess: String { get } + var isAsync: Bool { get } + var `throws`: Bool { get } + var isMutable: Bool { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var definedInTypeName: TypeName? { get } + var actualDefinedInTypeName: TypeName? { get } + var definedInType: Type? { get } + var attributes: AttributeList { get } + var modifiers: [SourceryModifier] { get } + var genericParameters: [GenericParameter] { get } + var genericRequirements: [GenericRequirement] { get } + var isGeneric: Bool { get } +} + +extension Subscript: SubscriptAutoJSExport {} + +@objc protocol TemplateContextAutoJSExport: JSExport { + var functions: [SourceryMethod] { get } + var types: Types { get } + var argument: [String: NSObject] { get } + var type: [String: Type] { get } + var stencilContext: [String: Any] { get } + var jsContext: [String: Any] { get } +} + +extension TemplateContext: TemplateContextAutoJSExport {} + +@objc protocol TupleElementAutoJSExport: JSExport { + var name: String? { get } + var typeName: TypeName { get } + var type: Type? { get } + var asSource: String { get } + var isOptional: Bool { get } + var isImplicitlyUnwrappedOptional: Bool { get } + var unwrappedTypeName: String { get } +} + +extension TupleElement: TupleElementAutoJSExport {} + +@objc protocol TupleTypeAutoJSExport: JSExport { + var name: String { get } + var elements: [TupleElement] { get } +} + +extension TupleType: TupleTypeAutoJSExport {} + +@objc protocol TypeAutoJSExport: JSExport { + var module: String? { get } + var imports: [Import] { get } + var allImports: [Import] { get } + var typealiases: [String: Typealias] { get } + var kind: String { get } + var accessLevel: String { get } + var name: String { get } + var isUnknownExtension: Bool { get } + var globalName: String { get } + var isGeneric: Bool { get } + var localName: String { get } + var variables: [Variable] { get } + var rawVariables: [Variable] { get } + var allVariables: [Variable] { get } + var methods: [Method] { get } + var rawMethods: [Method] { get } + var allMethods: [Method] { get } + var subscripts: [Subscript] { get } + var rawSubscripts: [Subscript] { get } + var allSubscripts: [Subscript] { get } + var initializers: [Method] { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var staticVariables: [Variable] { get } + var staticMethods: [Method] { get } + var classMethods: [Method] { get } + var instanceVariables: [Variable] { get } + var instanceMethods: [Method] { get } + var computedVariables: [Variable] { get } + var storedVariables: [Variable] { get } + var inheritedTypes: [String] { get } + var based: [String: String] { get } + var basedTypes: [String: Type] { get } + var inherits: [String: Type] { get } + var implements: [String: Type] { get } + var containedTypes: [Type] { get } + var containedType: [String: Type] { get } + var parentName: String? { get } + var parent: Type? { get } + var supertype: Type? { get } + var attributes: AttributeList { get } + var modifiers: [SourceryModifier] { get } + var genericRequirements: [GenericRequirement] { get } + var fileName: String? { get } +} + +extension Type: TypeAutoJSExport {} + +@objc protocol TypeNameAutoJSExport: JSExport { + var name: String { get } + var generic: GenericType? { get } + var isGeneric: Bool { get } + var isProtocolComposition: Bool { get } + var actualTypeName: TypeName? { get } + var attributes: AttributeList { get } + var modifiers: [SourceryModifier] { get } + var isOptional: Bool { get } + var isImplicitlyUnwrappedOptional: Bool { get } + var unwrappedTypeName: String { get } + var isVoid: Bool { get } + var isTuple: Bool { get } + var tuple: TupleType? { get } + var isArray: Bool { get } + var array: ArrayType? { get } + var isDictionary: Bool { get } + var dictionary: DictionaryType? { get } + var isClosure: Bool { get } + var closure: ClosureType? { get } + var isSet: Bool { get } + var set: SetType? { get } + var asSource: String { get } + var description: String { get } + var debugDescription: String { get } +} + +extension TypeName: TypeNameAutoJSExport {} + +@objc protocol TypealiasAutoJSExport: JSExport { + var aliasName: String { get } + var typeName: TypeName { get } + var type: Type? { get } + var module: String? { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var parent: Type? { get } + var accessLevel: String { get } + var parentName: String? { get } + var name: String { get } + var isOptional: Bool { get } + var isImplicitlyUnwrappedOptional: Bool { get } + var unwrappedTypeName: String { get } +} + +extension Typealias: TypealiasAutoJSExport {} + + +@objc protocol TypesCollectionAutoJSExport: JSExport { +} + +extension TypesCollection: TypesCollectionAutoJSExport {} + +@objc protocol VariableAutoJSExport: JSExport { + var name: String { get } + var typeName: TypeName { get } + var type: Type? { get } + var isComputed: Bool { get } + var isAsync: Bool { get } + var `throws`: Bool { get } + var isStatic: Bool { get } + var readAccess: String { get } + var writeAccess: String { get } + var isMutable: Bool { get } + var defaultValue: String? { get } + var annotations: Annotations { get } + var documentation: Documentation { get } + var attributes: AttributeList { get } + var modifiers: [SourceryModifier] { get } + var isFinal: Bool { get } + var isLazy: Bool { get } + var isDynamic: Bool { get } + var definedInTypeName: TypeName? { get } + var actualDefinedInTypeName: TypeName? { get } + var definedInType: Type? { get } + var isOptional: Bool { get } + var isImplicitlyUnwrappedOptional: Bool { get } + var unwrappedTypeName: String { get } +} + +extension Variable: VariableAutoJSExport {} + + +#endif +"""), + .init(name: "Typed.generated.swift", content: +""" +// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT +// swiftlint:disable vertical_whitespace + + +extension AssociatedValue { + /// Whether type is optional. Shorthand for `typeName.isOptional` + public var isOptional: Bool { return typeName.isOptional } + /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` + public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } + /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` + public var unwrappedTypeName: String { return typeName.unwrappedTypeName } + /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` + public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } + /// Whether type is a tuple. Shorthand for `typeName.isTuple` + public var isTuple: Bool { return typeName.isTuple } + /// Whether type is a closure. Shorthand for `typeName.isClosure` + public var isClosure: Bool { return typeName.isClosure } + /// Whether type is an array. Shorthand for `typeName.isArray` + public var isArray: Bool { return typeName.isArray } + /// Whether type is a set. Shorthand for `typeName.isSet` + public var isSet: Bool { return typeName.isSet } + /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` + public var isDictionary: Bool { return typeName.isDictionary } +} +extension ClosureParameter { + /// Whether type is optional. Shorthand for `typeName.isOptional` + public var isOptional: Bool { return typeName.isOptional } + /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` + public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } + /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` + public var unwrappedTypeName: String { return typeName.unwrappedTypeName } + /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` + public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } + /// Whether type is a tuple. Shorthand for `typeName.isTuple` + public var isTuple: Bool { return typeName.isTuple } + /// Whether type is a closure. Shorthand for `typeName.isClosure` + public var isClosure: Bool { return typeName.isClosure } + /// Whether type is an array. Shorthand for `typeName.isArray` + public var isArray: Bool { return typeName.isArray } + /// Whether type is a set. Shorthand for `typeName.isSet` + public var isSet: Bool { return typeName.isSet } + /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` + public var isDictionary: Bool { return typeName.isDictionary } +} +extension MethodParameter { + /// Whether type is optional. Shorthand for `typeName.isOptional` + public var isOptional: Bool { return typeName.isOptional } + /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` + public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } + /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` + public var unwrappedTypeName: String { return typeName.unwrappedTypeName } + /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` + public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } + /// Whether type is a tuple. Shorthand for `typeName.isTuple` + public var isTuple: Bool { return typeName.isTuple } + /// Whether type is a closure. Shorthand for `typeName.isClosure` + public var isClosure: Bool { return typeName.isClosure } + /// Whether type is an array. Shorthand for `typeName.isArray` + public var isArray: Bool { return typeName.isArray } + /// Whether type is a set. Shorthand for `typeName.isSet` + public var isSet: Bool { return typeName.isSet } + /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` + public var isDictionary: Bool { return typeName.isDictionary } +} +extension TupleElement { + /// Whether type is optional. Shorthand for `typeName.isOptional` + public var isOptional: Bool { return typeName.isOptional } + /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` + public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } + /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` + public var unwrappedTypeName: String { return typeName.unwrappedTypeName } + /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` + public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } + /// Whether type is a tuple. Shorthand for `typeName.isTuple` + public var isTuple: Bool { return typeName.isTuple } + /// Whether type is a closure. Shorthand for `typeName.isClosure` + public var isClosure: Bool { return typeName.isClosure } + /// Whether type is an array. Shorthand for `typeName.isArray` + public var isArray: Bool { return typeName.isArray } + /// Whether type is a set. Shorthand for `typeName.isSet` + public var isSet: Bool { return typeName.isSet } + /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` + public var isDictionary: Bool { return typeName.isDictionary } +} +extension Typealias { + /// Whether type is optional. Shorthand for `typeName.isOptional` + public var isOptional: Bool { return typeName.isOptional } + /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` + public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } + /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` + public var unwrappedTypeName: String { return typeName.unwrappedTypeName } + /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` + public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } + /// Whether type is a tuple. Shorthand for `typeName.isTuple` + public var isTuple: Bool { return typeName.isTuple } + /// Whether type is a closure. Shorthand for `typeName.isClosure` + public var isClosure: Bool { return typeName.isClosure } + /// Whether type is an array. Shorthand for `typeName.isArray` + public var isArray: Bool { return typeName.isArray } + /// Whether type is a set. Shorthand for `typeName.isSet` + public var isSet: Bool { return typeName.isSet } + /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` + public var isDictionary: Bool { return typeName.isDictionary } +} +extension Variable { + /// Whether type is optional. Shorthand for `typeName.isOptional` + public var isOptional: Bool { return typeName.isOptional } + /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` + public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } + /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` + public var unwrappedTypeName: String { return typeName.unwrappedTypeName } + /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` + public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } + /// Whether type is a tuple. Shorthand for `typeName.isTuple` + public var isTuple: Bool { return typeName.isTuple } + /// Whether type is a closure. Shorthand for `typeName.isClosure` + public var isClosure: Bool { return typeName.isClosure } + /// Whether type is an array. Shorthand for `typeName.isArray` + public var isArray: Bool { return typeName.isArray } + /// Whether type is a set. Shorthand for `typeName.isSet` + public var isSet: Bool { return typeName.isSet } + /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` + public var isDictionary: Bool { return typeName.isDictionary } } """), diff --git a/SourceryTests/Models/TypedSpec.generated.swift b/SourceryTests/Models/TypedSpec.generated.swift index 69f49a6f6..bc45a9386 100644 --- a/SourceryTests/Models/TypedSpec.generated.swift +++ b/SourceryTests/Models/TypedSpec.generated.swift @@ -1,4 +1,4 @@ -// Generated using Sourcery 2.1.3 — https://github.com/krzysztofzablocki/Sourcery +// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT import Quick import Nimble @@ -27,6 +27,7 @@ class TypedSpec: QuickSpec { let variable = result?.types.first?.variables.first return variable?.typeName ?? TypeName(name: "") } + #if canImport(ObjectiveC) it("can report optional via KVC") { expect(AssociatedValue(typeName: typeName("Int?")).value(forKeyPath: "isOptional") as? Bool).to(equal(true)) @@ -140,6 +141,7 @@ class TypedSpec: QuickSpec { let variable = result?.types.first?.variables.first return variable?.typeName ?? TypeName(name: "") } + #if canImport(ObjectiveC) it("can report optional via KVC") { expect(MethodParameter(typeName: typeName("Int?")).value(forKeyPath: "isOptional") as? Bool).to(equal(true)) @@ -196,6 +198,7 @@ class TypedSpec: QuickSpec { let variable = result?.types.first?.variables.first return variable?.typeName ?? TypeName(name: "") } + #if canImport(ObjectiveC) it("can report optional via KVC") { expect(TupleElement(typeName: typeName("Int?")).value(forKeyPath: "isOptional") as? Bool).to(equal(true)) @@ -309,6 +312,7 @@ class TypedSpec: QuickSpec { let variable = result?.types.first?.variables.first return variable?.typeName ?? TypeName(name: "") } + #if canImport(ObjectiveC) it("can report optional via KVC") { expect(Variable(typeName: typeName("Int?")).value(forKeyPath: "isOptional") as? Bool).to(equal(true))