Skip to content

Commit 321806c

Browse files
authored
Merge pull request #50 from puzzmo-com/amuse-json-fallbacks
Adds a fallback for missing data on an amuse import
2 parents 579235e + 82304c1 commit 321806c

File tree

2 files changed

+51
-6
lines changed

2 files changed

+51
-6
lines changed

packages/xd-crossword-tools/src/amuseJSONToXD.ts

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { JSONToXD } from "./JSONtoXD"
2-
import type { Clue, Position as CluePosition, CrosswordJSON } from "xd-crossword-tools-parser"
2+
import type { Clue, Position as CluePosition, CrosswordJSON, Report } from "xd-crossword-tools-parser"
33

44
import type { CellInfo, PlacedWord, AmuseTopLevel } from "./amuseJSONToXD.types.d.ts"
55

@@ -207,11 +207,31 @@ export function convertAmuseToCrosswordJSON(amuseJson: AmuseTopLevel): Crossword
207207
const cluesStructure: Clues = { across: [], down: [] }
208208
const cluePositionsMap: Record<string, CluePosition> = {}
209209

210+
const errorReports: Report[] = []
211+
210212
amuseData.placedWords.forEach((placedWord: PlacedWord) => {
211-
const direction = placedWord.clueSection === "Across" ? "across" : "down"
213+
let direction: "across" | "down" | null = null
214+
215+
// I think different ages of amuse json's have different data structures,
216+
// as one crossword we have does not include "clueSection" - so we fall back to "acrossNotDown"
217+
if (placedWord.clueSection) direction = placedWord.clueSection === "Across" ? "across" : "down"
218+
if ("acrossNotDown" in placedWord && !direction) direction = placedWord.acrossNotDown ? "across" : "down"
219+
if (!direction) {
220+
errorReports.push({
221+
type: "syntax",
222+
message: `Could not determine a direction for placed word ${placedWord.word}.`,
223+
length: -1,
224+
position: {
225+
col: placedWord.x,
226+
index: placedWord.y,
227+
},
228+
})
229+
return
230+
}
231+
212232
const clueText = convertHtmlToXdMarkup(placedWord.clue.clue)
213233
const clueNumberStr = placedWord.clueNum // This is already a string from AmuseData
214-
const word = placedWord.word || ""
234+
const word = placedWord.word || placedWord.originalTerm || ""
215235
let answer
216236
let alt
217237

@@ -239,7 +259,7 @@ export function convertAmuseToCrosswordJSON(amuseJson: AmuseTopLevel): Crossword
239259
body: clueText,
240260
answer: answer,
241261
tiles: [],
242-
direction: direction,
262+
direction,
243263
display: [],
244264
position: {
245265
col: placedWord.x,
@@ -408,9 +428,16 @@ export function convertHtmlToXdMarkup(html: string | undefined): string {
408428
)
409429
}
410430

431+
// Don't think this is actually a goal: https://github.com/puzzmo-com/xd-crossword-tools/issues/46
432+
// Convert spaced dots to ellipsis
433+
// result = result.replace(/\. \. \./g, "…")
434+
411435
// Clean up excessive whitespace and newlines
412436
result = result.replace(/\n+/g, "\n").trim()
413437

438+
// Remove extra HTML entities like "&#039;"
439+
result = result.replace(/&#(\d+);/g, (match, dec) => String.fromCharCode(dec))
440+
414441
return result
415442
}
416443

packages/xd-crossword-tools/tests/amuseJSONToXD.test.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ const exampleJSONPath = "/Users/orta/dev/workshop/packages/amuse-to-xd/examples/
88
const fullExamplePath = exampleJSONPath
99

1010
const hasCirclesPath = "/Users/orta/dev/workshop/packages/amuse-to-xd/examples/2025_04_01-themed.json"
11-
1211
const largeGrid = "/Users/orta/dev/workshop/packages/amuse-to-xd/examples/2021_01_01-oversize.json"
12+
const cartoon = "/Users/orta/dev/workshop/packages/amuse-to-xd/examples/2019_12_23-cartoon.json"
1313

1414
// Only run tests if the example JSON files exist
1515
const shouldRunTests = existsSync(fullExamplePath) && existsSync(hasCirclesPath)
1616

1717
const describeConditional = shouldRunTests ? describe : describe.skip
1818

19-
describe("amuseJSONToXD", () => {
19+
describeConditional("amuseJSONToXD", () => {
2020
it("handles schrodinger clues correctly", () => {
2121
const result = convertAmuseToCrosswordJSON(schrodingerAmuseExample)
2222

@@ -202,6 +202,13 @@ describe("amuseJSONToXD", () => {
202202
})
203203
})
204204

205+
it.skip("handles converting ellipsis", () => {
206+
const result = convertAmuseToCrosswordJSON(amuseJSON)
207+
208+
const across7 = result.clues.across.find((clue) => clue.number === 7)
209+
expect(across7?.body).toMatchInlineSnapshot(`"Single ensign full of exuberance … (4)"`)
210+
})
211+
205212
describe("amuseToXD", () => {
206213
it("converts amuse JSON to XD string format", () => {
207214
const result = amuseToXD(amuseJSON)
@@ -575,4 +582,15 @@ describe("amuseJSONToXD", () => {
575582
expect(a8Clue?.answer).toEqual("FCC")
576583
})
577584
})
585+
586+
describe(cartoon, () => {
587+
it("has answers for the clues", () => {
588+
const xdOutput = convertAmuseToCrosswordJSON(JSON.parse(readFileSync(cartoon, "utf-8")))
589+
590+
const a1Clue = xdOutput.clues.across.find((clue) => clue.number === 1)
591+
expect(a1Clue).toBeDefined()
592+
expect(a1Clue?.body).toEqual("Hairdo")
593+
expect(a1Clue?.answer).toEqual("COIF")
594+
})
595+
})
578596
})

0 commit comments

Comments
 (0)