diff --git a/Sources/KnitCodeGen/TypeNamer.swift b/Sources/KnitCodeGen/TypeNamer.swift index 51b4820..f1abf4b 100644 --- a/Sources/KnitCodeGen/TypeNamer.swift +++ b/Sources/KnitCodeGen/TypeNamer.swift @@ -32,12 +32,13 @@ enum TypeNamer { } // Drop any annotation var type = type.replacingOccurrences(of: "any ", with: "") - let removedCharacters = CharacterSet(charactersIn: "?[]():&, ") + let removedCharacters = CharacterSet(charactersIn: "?[]():& ") type = type.components(separatedBy: removedCharacters).joined(separator: "") let regex = try! NSRegularExpression(pattern: "<.*>") let nsString = type as NSString if let match = regex.firstMatch(in: type, range: .init(location: 0, length: type.count)) { let range = match.range + let mainType = nsString.replacingCharacters(in: match.range, with: "") if keepGenerics { var genericName = nsString.substring( with: .init(location: range.location + 1, length: range.length - 2) @@ -47,18 +48,38 @@ enum TypeNamer { .replacingOccurrences(of: ",", with: "_") .replacingOccurrences(of: " ", with: "") type = nsString.replacingCharacters(in: match.range, with: "_\(genericName)") + } else if let suffix = Self.suffixedGenericTypes.first(where: { mainType.hasSuffix($0)} ) { + let genericName = nsString.substring( + with: .init(location: range.location + 1, length: range.length - 2) + ) + if let mainGeneric = genericName.components(separatedBy: .init(charactersIn: ",")).first { + type = mainGeneric + suffix + } else { + type = mainType + } } else { - type = nsString.replacingCharacters(in: match.range, with: "") + type = mainType } + } else { + type = type.components(separatedBy: .init(charactersIn: ",")).joined(separator: "") } - if let dotIndex = type.firstIndex(of: ".") { + if let dotIndex = type.lastIndex(of: ".") { let nameStart = type.index(after: dotIndex) - type = String(type[nameStart...]) + let lastType = String(type[nameStart...]) + // Types with a Factory subtype should keep the subject of the factory + if lastType == "Factory" { + let components = type.components(separatedBy: .init(charactersIn: ".")) + type = components.suffix(2).joined(separator: "") + } else { + type = lastType + } } return type } + private static let suffixedGenericTypes = ["Publisher", "Subject", "Provider"] + static func isClosure(type: String) -> Bool { return type.contains("->") } diff --git a/Tests/KnitCodeGenTests/TypeNamerTests.swift b/Tests/KnitCodeGenTests/TypeNamerTests.swift index d8f1528..703ae0f 100644 --- a/Tests/KnitCodeGenTests/TypeNamerTests.swift +++ b/Tests/KnitCodeGenTests/TypeNamerTests.swift @@ -78,7 +78,7 @@ final class TypeNamerTests: XCTestCase { XCTAssertEqual( TypeNamer.sanitizeType(type: "Result", keepGenerics: true), - "Result_StringError" + "Result_String_Error" ) XCTAssertEqual( @@ -110,6 +110,45 @@ final class TypeNamerTests: XCTestCase { ) } + func testFactoryRule() { + assertComputedIdentifier( + type: "MyClass.Factory", + expectedIdentifier: "myClassFactory" + ) + + assertComputedIdentifier( + type: "Module.MyClass.Factory", + expectedIdentifier: "myClassFactory" + ) + + assertComputedIdentifier( + type: "Factory", + expectedIdentifier: "factory" + ) + } + + func testSuffixRule() { + assertComputedIdentifier( + type: "AnyPublisher", + expectedIdentifier: "stringPublisher" + ) + + assertComputedIdentifier( + type: "AnyPublisher", + expectedIdentifier: "myTypePublisher" + ) + + assertComputedIdentifier( + type: "CurrentValueSubject", + expectedIdentifier: "stringSubject" + ) + + assertComputedIdentifier( + type: "ValueProvider", + expectedIdentifier: "intProvider" + ) + } + } private func assertComputedIdentifier(