Skip to content

Commit

Permalink
alias generator
Browse files Browse the repository at this point in the history
  • Loading branch information
kattouf committed Oct 4, 2024
1 parent adbf19c commit 8b5d5fe
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 0 deletions.
60 changes: 60 additions & 0 deletions Sources/Sake/AliasGenerator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
enum AliasGenerator {
static func generateAliases(for phrases: [String], specificPrefixes: [String: [String: Int]] = [:]) -> [String: String] {
let phrases = phrases.filter { !$0.isEmpty }
let aliases = phrases.map { generateAlias(for: $0, specificPrefixPerWord: specificPrefixes[$0] ?? [:]) }
if aliases.count == Set(aliases).count {
return Dictionary(uniqueKeysWithValues: zip(phrases, aliases))
} else {
var specificPrefixes = specificPrefixes
var colidedAliasesToPhrases = [String: [String]]()
for (phrase, alias) in zip(phrases, aliases) {
if colidedAliasesToPhrases[alias] == nil {
colidedAliasesToPhrases[alias] = [phrase]
} else {
colidedAliasesToPhrases[alias]?.append(phrase)
}
}
for phrases in colidedAliasesToPhrases.values {
if phrases.count > 1 {
let wordsForPhrases = phrases.map(splitPhraseToWords(_:))
let numberOfWordsPerPhrase = wordsForPhrases.map(\.count).min() ?? 0
let specificPrefixPerWord = (0 ..< numberOfWordsPerPhrase).reduce(into: [String: Int]()) { result, index in
let sameIndexWords = wordsForPhrases.map { $0[index] }
if Set(sameIndexWords).count == 1 {
return
}
let commonPrefix = commonPrefix(sameIndexWords)
for word in sameIndexWords {
result[word] = commonPrefix.count + 1
}
}
for phrase in phrases {
specificPrefixes[phrase] = specificPrefixPerWord
}
}
}

return generateAliases(for: phrases, specificPrefixes: specificPrefixes)
}
}

private static func generateAlias(for phrase: String, specificPrefixPerWord: [String: Int]) -> String {
let words = splitPhraseToWords(phrase)
let firstLetters = words.compactMap { $0.prefix(specificPrefixPerWord[$0] ?? 1) }
return firstLetters.joined()
}

private static func splitPhraseToWords(_ phrase: String) -> [String] {
let snakeCaseName = phrase.toSnakeCase()
return snakeCaseName.split(separator: "_").map(String.init)
}

private static func commonPrefix(_ strings: [String]) -> String {
guard let first = strings.first else {
return ""
}
return strings.dropFirst().reduce(first) { prefix, string in
prefix.commonPrefix(with: string)
}
}
}
28 changes: 28 additions & 0 deletions Tests/SakeTests/AliasGeneratorTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
@testable import Sake
import XCTest

final class AliasGeneratorTests: XCTestCase {
func testGenerate() {
let phrases = [
"command_aqua",
"command_apple",
"command_beer",
"command_boo",
"command_book",
"command_duck",
"command_car",
"command",
""
]
let aliases = AliasGenerator.generateAliases(for: phrases)
XCTAssertEqual(aliases["command_aqua"], "caq")
XCTAssertEqual(aliases["command_apple"], "cap")
XCTAssertEqual(aliases["command_boo"], "cboo")
XCTAssertEqual(aliases["command_book"], "cbook")
XCTAssertEqual(aliases["command_beer"], "cbe")
XCTAssertEqual(aliases["command_duck"], "cd")
XCTAssertEqual(aliases["command_car"], "cc")
XCTAssertEqual(aliases["command"], "c")
XCTAssertNil(aliases[""])
}
}

0 comments on commit 8b5d5fe

Please sign in to comment.