Scaffold v1.0.0
This commit is contained in:
102
Sources/EmbedderTool/IdentifierSanitizer.swift
Normal file
102
Sources/EmbedderTool/IdentifierSanitizer.swift
Normal file
@@ -0,0 +1,102 @@
|
||||
import Foundation
|
||||
|
||||
enum IdentifierSanitizer {
|
||||
static func propertyName(fromFilename filename: String) -> String {
|
||||
let words = words(from: filename)
|
||||
let camelCased = joinAsLowerCamelCase(words)
|
||||
return escapeForSwift(camelCased)
|
||||
}
|
||||
|
||||
static func typeName(from directoryName: String) -> String {
|
||||
let words = words(from: directoryName)
|
||||
let pascalCased = joinAsUpperCamelCase(words)
|
||||
return escapeForSwift(pascalCased)
|
||||
}
|
||||
}
|
||||
|
||||
private extension IdentifierSanitizer {
|
||||
static func words(from rawString: String) -> [String] {
|
||||
let segments = splitOnNonAlphanumerics(rawString)
|
||||
return segments.flatMap(splitCamelCaseBoundaries)
|
||||
}
|
||||
|
||||
static func splitOnNonAlphanumerics(_ string: String) -> [String] {
|
||||
string
|
||||
.split(whereSeparator: { !$0.isLetter && !$0.isNumber })
|
||||
.map(String.init)
|
||||
}
|
||||
|
||||
static func splitCamelCaseBoundaries(_ word: String) -> [String] {
|
||||
var results: [String] = []
|
||||
var currentWord = ""
|
||||
for character in word {
|
||||
if shouldStartNewWord(at: character, currentWord: currentWord) {
|
||||
results.append(currentWord)
|
||||
currentWord = String(character)
|
||||
} else {
|
||||
currentWord.append(character)
|
||||
}
|
||||
}
|
||||
if !currentWord.isEmpty {
|
||||
results.append(currentWord)
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
static func shouldStartNewWord(at character: Character, currentWord: String) -> Bool {
|
||||
guard !currentWord.isEmpty, let lastCharacter = currentWord.last else {
|
||||
return false
|
||||
}
|
||||
return lastCharacter.isLowercase && character.isUppercase
|
||||
}
|
||||
|
||||
static func joinAsLowerCamelCase(_ words: [String]) -> String {
|
||||
guard let firstWord = words.first else { return "" }
|
||||
let remainingWords = words.dropFirst().map(capitalizeFirstLetter)
|
||||
return firstWord.lowercased() + remainingWords.joined()
|
||||
}
|
||||
|
||||
static func joinAsUpperCamelCase(_ words: [String]) -> String {
|
||||
words.map(capitalizeFirstLetter).joined()
|
||||
}
|
||||
|
||||
static func capitalizeFirstLetter(_ word: String) -> String {
|
||||
guard let firstCharacter = word.first else { return "" }
|
||||
return firstCharacter.uppercased() + word.dropFirst().lowercased()
|
||||
}
|
||||
|
||||
static func escapeForSwift(_ identifier: String) -> String {
|
||||
let nonEmpty = fallbackIfEmpty(identifier)
|
||||
let leadingDigitSafe = prefixIfStartsWithDigit(nonEmpty)
|
||||
return wrapInBackticksIfReservedKeyword(leadingDigitSafe)
|
||||
}
|
||||
|
||||
static func fallbackIfEmpty(_ identifier: String) -> String {
|
||||
identifier.isEmpty ? "_" : identifier
|
||||
}
|
||||
|
||||
static func prefixIfStartsWithDigit(_ identifier: String) -> String {
|
||||
guard let first = identifier.first, first.isNumber else {
|
||||
return identifier
|
||||
}
|
||||
return "_" + identifier
|
||||
}
|
||||
|
||||
static func wrapInBackticksIfReservedKeyword(_ identifier: String) -> String {
|
||||
SwiftReservedKeywords.all.contains(identifier) ? "`\(identifier)`" : identifier
|
||||
}
|
||||
}
|
||||
|
||||
private enum SwiftReservedKeywords {
|
||||
static let all: Set<String> = [
|
||||
"associatedtype", "class", "deinit", "enum", "extension", "fileprivate",
|
||||
"func", "import", "init", "inout", "internal", "let", "open", "operator",
|
||||
"private", "precedencegroup", "protocol", "public", "rethrows", "static",
|
||||
"struct", "subscript", "typealias", "var",
|
||||
"break", "case", "catch", "continue", "default", "defer", "do", "else",
|
||||
"fallthrough", "for", "guard", "if", "in", "repeat", "return", "throw",
|
||||
"switch", "where", "while",
|
||||
"Any", "as", "false", "is", "nil", "self", "Self", "super", "throws",
|
||||
"true", "try"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user