Skip to content

Commit 1680448

Browse files
committed
Normalize name to produce a token path
1 parent 275fe9f commit 1680448

File tree

2 files changed

+93
-5
lines changed

2 files changed

+93
-5
lines changed

Sources/FifthEdition/Bestiary.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,26 @@ public struct Creature: Equatable, Sendable {
318318
// TODO: variant, ? defs/entryVariantBestiary
319319
// TODO: _versions, array /creatureVersion
320320
// TODO: _isCopy, _copy
321+
322+
/// Returns the expected token path.
323+
public var tokenPath: String? {
324+
guard let name = token?.name ?? name,
325+
let source = token?.source ?? source else {
326+
return nil
327+
}
328+
329+
let tokenName = String(
330+
name
331+
.replacingOccurrences(of: "Æ", with: "AE")
332+
.replacingOccurrences(of: "æ", with: "ae")
333+
.replacingOccurrences(of: "\"", with: "")
334+
.decomposedStringWithCanonicalMapping
335+
.unicodeScalars
336+
.filter { $0.isASCII }
337+
)
338+
339+
return "bestiary/tokens/\(source)/\(tokenName).webp"
340+
}
321341
}
322342

323343
// MARK: - Codable

Tests/FifthEditionTests/BestiaryTests.swift

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,11 @@ struct CreatureCodableTests {
232232
.underdark,
233233
.planarLower
234234
],
235+
gear: [
236+
.init("dagger|xphb", quantity: 6),
237+
.init("studded leather armor|xphb"),
238+
],
239+
treasure: [.arcana],
235240
actionTags: [
236241
.frightfulPresence,
237242
],
@@ -252,11 +257,6 @@ struct CreatureCodableTests {
252257
.falseAppearance,
253258
.unusualNature,
254259
],
255-
gear: [
256-
.init("dagger|xphb", quantity: 6),
257-
.init("studded leather armor|xphb"),
258-
],
259-
treasure: [.arcana],
260260
canBeFamiliar: true,
261261
hasToken: true,
262262
hasFluff: true,
@@ -447,6 +447,74 @@ struct CreatureCodableTests {
447447

448448
}
449449

450+
struct CreatureTokenPathTests {
451+
452+
@Test("Token path")
453+
func tokenPath() throws {
454+
let creature = Creature(
455+
name: "Blink Dog",
456+
source: "XMM"
457+
)
458+
#expect(creature.tokenPath == "bestiary/tokens/XMM/Blink Dog.webp")
459+
}
460+
461+
@Test("Token path has diacritics removed")
462+
func tokenPathWithoutDiacritics() throws {
463+
let creature = Creature(
464+
name: "Kupalué",
465+
source: "ToA"
466+
)
467+
#expect(creature.tokenPath == "bestiary/tokens/ToA/Kupalue.webp")
468+
}
469+
470+
@Test("Token path has æ dipthong replaced")
471+
func tokenPathWithoutAeDipthong() throws {
472+
let creature = Creature(
473+
name: "Môrgæn",
474+
source: "AI"
475+
)
476+
#expect(creature.tokenPath == "bestiary/tokens/AI/Morgaen.webp")
477+
}
478+
479+
@Test("Token path has quotes removed")
480+
func tokenPathWithoutQuotes() throws {
481+
let creature = Creature(
482+
name: "\"The Demogorgon\"",
483+
source: "IMR"
484+
)
485+
#expect(creature.tokenPath == "bestiary/tokens/IMR/The Demogorgon.webp")
486+
}
487+
488+
@Test("Token path from token")
489+
func tokenPathFromToken() throws {
490+
let creature = Creature(
491+
name: "Demilich",
492+
source: "WDMM",
493+
token: Token(
494+
name: "Acererak",
495+
source: "MM"),
496+
)
497+
#expect(creature.tokenPath == "bestiary/tokens/MM/Acererak.webp")
498+
}
499+
500+
@Test("No token if no name")
501+
func noName() throws {
502+
let creature = Creature(
503+
source: "XMM",
504+
)
505+
#expect(creature.tokenPath == nil)
506+
}
507+
508+
@Test("No token if no source")
509+
func noSource() throws {
510+
let creature = Creature(
511+
name: "Blink Dog",
512+
)
513+
#expect(creature.tokenPath == nil)
514+
}
515+
516+
}
517+
450518
struct CreatureAbilityScoreCodableTests {
451519

452520
@Test("Ability score")

0 commit comments

Comments
 (0)