feat: add Arknights: Endfield, and stop passing off requirements as summaries

Endfield was previously written off as undatable. That was wrong: a first
pass only inspected its Duration rows (all "Permanently Available") and its
year-less version grid, and missed an "Event | Schedule & Summary" table
whose cells read "Period: 08/09/26 - 08/30/26 During the event...". Two real
events, with a year.

Adds MM/DD/YY range parsing for that shape. Month-first ordering is not
assumed lightly — Endfield's own version grid reads 01/22, 04/17, 07/16 for
versions 1.0, 1.2 and 1.4, chronological only if the month comes first.

Also stops presenting unlock conditions as descriptions. Several templates
put "Reach Union Level 8" where a blurb would go; filling the summary slot
with text that never says what the event is is worse than leaving it empty.
Wuthering Waves correctly drops to zero summaries as a result.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
Lucas Winther
2026-08-15 01:07:39 +02:00
co-authored by Claude Opus 5
parent 65f1660718
commit ad45b52c84
11 changed files with 237 additions and 19 deletions
+19
View File
@@ -25,6 +25,7 @@ const CASES: Array<{ adapter: Adapter; fixture: string }> = [
{ adapter: adapter("hsr-game8-events"), fixture: "fixtures/hsr/game8-events-2026-08-14" },
{ adapter: adapter("wuwa-game8-events"), fixture: "fixtures/wuwa/game8-events-2026-08-14" },
{ adapter: adapter("zzz-game8-events"), fixture: "fixtures/zzz/game8-events-2026-08-14" },
{ adapter: adapter("endfield-game8-events"), fixture: "fixtures/endfield/game8-events-2026-08-14" },
];
async function runAdapter(adapter: Adapter, fixture: string) {
@@ -205,3 +206,21 @@ describe("new source shapes", () => {
expect(jade?.endsAt).toBe("2026-08-13T00:00:00.000Z");
});
});
describe("endfield", () => {
test("reads MM/DD/YY ranges from a combined schedule cell", async () => {
// This page hides its only dated events in an "Event | Schedule & Summary"
// table, where one cell holds the label, the range and the blurb.
const events = await runAdapter(
adapter("endfield-game8-events"),
"fixtures/endfield/game8-events-2026-08-14",
);
expect(events).toHaveLength(2);
const rooted = events.find((e) => e.title === "The Rooted Realm");
expect(rooted?.startsAt).toBe("2026-08-09T00:00:00.000Z");
expect(rooted?.endsAt).toBe("2026-08-30T00:00:00.000Z");
// The prose after the dates becomes the blurb, without the label.
expect(rooted?.summary).not.toBeNull();
expect(rooted?.summary).not.toMatch(/^Period:/);
});
});