commit e5bdc671f85244ebe9094c5edf52765573e53f75
parent 28968fea513baec6bad506f7101e36a00a601ee6
Author: Michael Camilleri <[email protected]>
Date: Fri, 26 Jun 2026 09:39:41 +0900
Preserve puzzle titles from external providers
This commit keeps the title supplied by an external puzzle's JSON when
one is present. Untitled puzzles still derive the existing '<Weekday>
Crossword'-style title from their publication date, and the converter
coverage now exercises both paths through the same fixture.
Co-Authored-By: Codex GPT 5.5 <[email protected]>
Diffstat:
2 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/Crossmate/Services/NYTToXDConverter.swift b/Crossmate/Services/NYTToXDConverter.swift
@@ -52,6 +52,13 @@ enum NYTToXDConverter {
// -- Metadata --
let publicationDate = root["publicationDate"] as? String ?? ""
+ let nytTitle = (root["title"] as? String)?
+ .trimmingCharacters(in: .whitespacesAndNewlines)
+ let title = if let nytTitle, !nytTitle.isEmpty {
+ nytTitle
+ } else {
+ title(forPublicationDate: publicationDate)
+ }
let constructors = root["constructors"] as? [String] ?? []
let editor = root["editor"] as? String
let copyright = root["copyright"] as? String
@@ -263,7 +270,7 @@ enum NYTToXDConverter {
// Metadata section
var metadata: [String] = []
- metadata.append("Title: \(title(forPublicationDate: publicationDate))")
+ metadata.append("Title: \(title)")
metadata.append("CmVer: \(XD.currentCmVersion)")
metadata.append("Publisher: New York Times")
if !publicationDate.isEmpty {
diff --git a/Tests/Unit/NYTToXDConverterTests.swift b/Tests/Unit/NYTToXDConverterTests.swift
@@ -15,6 +15,7 @@ struct NYTToXDConverterTests {
/// entirely.
private func puzzleJSON(
relatives: [[Int]?],
+ title: String? = nil,
formattedClueIndices: Set<Int> = [],
formattedOverrides: [Int: String] = [:],
clueTexts: [Int: String] = [:],
@@ -62,7 +63,7 @@ struct NYTToXDConverterTests {
}
return cell
}
- let root: [String: Any] = [
+ var root: [String: Any] = [
"publicationDate": "2025-01-01",
"constructors": ["Tester"],
"body": [[
@@ -71,6 +72,9 @@ struct NYTToXDConverterTests {
"clues": clueDicts
]]
]
+ if let title {
+ root["title"] = title
+ }
return try JSONSerialization.data(withJSONObject: root)
}
@@ -134,6 +138,20 @@ struct NYTToXDConverterTests {
#expect(puzzle.publisher == "New York Times")
}
+ @Test("NYT metadata preserves supplied puzzle title")
+ func nytMetadataPreservesSuppliedPuzzleTitle() throws {
+ let data = try puzzleJSON(
+ relatives: [nil, nil, nil, nil, nil, nil],
+ title: "Big Draw"
+ )
+ let xd = try NYTToXDConverter.convert(jsonData: data)
+ #expect(header("Title", in: xd) == "Big Draw")
+
+ let parsed = try XD.parse(xd)
+ let puzzle = Puzzle(xd: parsed)
+ #expect(puzzle.title == "Big Draw")
+ }
+
@Test("NYT moreAnswers.valid emits XD Accept metadata and round-trips")
func moreAnswersEmitAcceptMetadata() throws {
let data = try puzzleJSON(