From f8f99ed2f8fd337c6640a1a500ef4eb00cef9bc7 Mon Sep 17 00:00:00 2001 From: Liam Nichols Date: Sun, 13 Oct 2024 17:13:15 +0200 Subject: [PATCH] Update logic to improve variableIdentifiers generated for strings containing accronyms (#116) --- .../SwiftIdentifier+Extra.swift | 22 ++++++++-- .../SwiftIdentifierTests.swift | 41 +++++++++++++++++++ 2 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 Tests/XCStringsToolTests/SwiftIdentifierTests.swift diff --git a/Sources/SwiftIdentifier/SwiftIdentifier+Extra.swift b/Sources/SwiftIdentifier/SwiftIdentifier+Extra.swift index 0ee4d5f..f6d6adc 100644 --- a/Sources/SwiftIdentifier/SwiftIdentifier+Extra.swift +++ b/Sources/SwiftIdentifier/SwiftIdentifier+Extra.swift @@ -1,14 +1,28 @@ import Foundation private extension String { - var lowercaseFirst: String { - guard let first = unicodeScalars.first else { return self } - return String(first).lowercased() + String(unicodeScalars.dropFirst()) + func lowercaseFirst(_ n: Int) -> String { + guard unicodeScalars.count >= n else { return self } + return String(unicodeScalars.prefix(n)).lowercased() + String(unicodeScalars.dropFirst(n)) } } extension SwiftIdentifier { public static func variableIdentifier(for string: String) -> String { - identifier(from: string).lowercaseFirst + let identifier = identifier(from: string) + let uppercasedPrefix = identifier.prefix(while: \.isUppercase) + + if uppercasedPrefix.isEmpty { + return identifier + } else if uppercasedPrefix.unicodeScalars.count == 1 { + // i.e "Localizable" >> "localizable" or "MyStrings" >> "myStrings" + return identifier.lowercaseFirst(1) + } else if uppercasedPrefix.count == identifier.count { + // i.e "LOCALIZABLE" >> "localizable" + return identifier.lowercased() + } else { + // i.e "URLStrings" >> "urlStrings" or "URLStringCollection" >> "urlStringCollection" + return identifier.lowercaseFirst(uppercasedPrefix.unicodeScalars.count - 1) + } } } diff --git a/Tests/XCStringsToolTests/SwiftIdentifierTests.swift b/Tests/XCStringsToolTests/SwiftIdentifierTests.swift new file mode 100644 index 0000000..b41eab1 --- /dev/null +++ b/Tests/XCStringsToolTests/SwiftIdentifierTests.swift @@ -0,0 +1,41 @@ +import SwiftIdentifier +import XCTest + +final class SwiftIdentifierTests: XCTestCase { + func testSwiftIdentifier() { + assert(value: "Localizable", escapesTo: "Localizable", "localizable") + assert(value: "localizable", escapesTo: "Localizable", "localizable") + assert(value: "LOCALIZABLE", escapesTo: "LOCALIZABLE", "localizable") + + assert(value: "URL Strings", escapesTo: "URLStrings", "urlStrings") + assert(value: "URLStrings", escapesTo: "URLStrings", "urlStrings") + + assert(value: "FeatureFoo", escapesTo: "FeatureFoo", "featureFoo") + assert(value: "Feature Foo", escapesTo: "FeatureFoo", "featureFoo") + assert(value: "Feature URL", escapesTo: "FeatureURL", "featureURL") + } + + private func assert( + value: String, + escapesTo expectedIdentifier: String, + _ expectedVariableIdentifier: String, + file: StaticString = #filePath, + line: UInt = #line + ) { + XCTAssertEqual( + SwiftIdentifier.identifier(from: value), + expectedIdentifier, + "identifier", + file: file, + line: line + ) + + XCTAssertEqual( + SwiftIdentifier.variableIdentifier(for: value), + expectedVariableIdentifier, + "variableIdentifier", + file: file, + line: line + ) + } +}