Compare commits

...

1 Commits

Author SHA1 Message Date
Lukas
8dbff66ce1 Fix "undefined" in PF2e stat block weaknesses/resistances
All checks were successful
CI / check (push) Successful in 2m23s
CI / build-image (push) Successful in 30s
Some PF2e creatures (e.g. Giant Mining Bee) have qualitative
weaknesses without a numeric amount, causing "undefined" to
render in the stat block. Handle missing amounts gracefully.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 12:06:22 +02:00
2 changed files with 109 additions and 14 deletions

View File

@@ -0,0 +1,91 @@
import { describe, expect, it } from "vitest";
import { normalizePf2eBestiary } from "../pf2e-bestiary-adapter.js";
function minimalCreature(defenses?: Record<string, unknown>) {
return {
name: "Test Creature",
source: "TST",
defenses,
};
}
describe("normalizePf2eBestiary", () => {
describe("weaknesses formatting", () => {
it("formats weakness with numeric amount", () => {
const [creature] = normalizePf2eBestiary({
creature: [
minimalCreature({
weaknesses: [{ name: "fire", amount: 5 }],
}),
],
});
expect(creature.weaknesses).toBe("Fire 5");
});
it("formats weakness without amount (qualitative)", () => {
const [creature] = normalizePf2eBestiary({
creature: [
minimalCreature({
weaknesses: [{ name: "smoke susceptibility" }],
}),
],
});
expect(creature.weaknesses).toBe("Smoke susceptibility");
});
it("formats weakness with note and amount", () => {
const [creature] = normalizePf2eBestiary({
creature: [
minimalCreature({
weaknesses: [
{ name: "cold iron", amount: 5, note: "except daggers" },
],
}),
],
});
expect(creature.weaknesses).toBe("Cold iron 5 (except daggers)");
});
it("formats weakness with note but no amount", () => {
const [creature] = normalizePf2eBestiary({
creature: [
minimalCreature({
weaknesses: [{ name: "smoke susceptibility", note: "see below" }],
}),
],
});
expect(creature.weaknesses).toBe("Smoke susceptibility (see below)");
});
it("returns undefined when no weaknesses", () => {
const [creature] = normalizePf2eBestiary({
creature: [minimalCreature({})],
});
expect(creature.weaknesses).toBeUndefined();
});
});
describe("resistances formatting", () => {
it("formats resistance without amount", () => {
const [creature] = normalizePf2eBestiary({
creature: [
minimalCreature({
resistances: [{ name: "physical" }],
}),
],
});
expect(creature.resistances).toBe("Physical");
});
it("formats resistance with amount", () => {
const [creature] = normalizePf2eBestiary({
creature: [
minimalCreature({
resistances: [{ name: "fire", amount: 10 }],
}),
],
});
expect(creature.resistances).toBe("Fire 10");
});
});
});

View File

@@ -40,8 +40,8 @@ interface RawDefenses {
};
hp?: { hp?: number }[];
immunities?: (string | { name: string })[];
resistances?: { amount: number; name: string; note?: string }[];
weaknesses?: { amount: number; name: string; note?: string }[];
resistances?: { amount?: number; name: string; note?: string }[];
weaknesses?: { amount?: number; name: string; note?: string }[];
}
interface RawAbility {
@@ -150,31 +150,35 @@ function formatImmunities(
function formatResistances(
resistances:
| readonly { amount: number; name: string; note?: string }[]
| readonly { amount?: number; name: string; note?: string }[]
| undefined,
): string | undefined {
if (!resistances || resistances.length === 0) return undefined;
return resistances
.map((r) =>
r.note
? `${capitalize(r.name)} ${r.amount} (${r.note})`
: `${capitalize(r.name)} ${r.amount}`,
)
.map((r) => {
const base =
r.amount == null
? capitalize(r.name)
: `${capitalize(r.name)} ${r.amount}`;
return r.note ? `${base} (${r.note})` : base;
})
.join(", ");
}
function formatWeaknesses(
weaknesses:
| readonly { amount: number; name: string; note?: string }[]
| readonly { amount?: number; name: string; note?: string }[]
| undefined,
): string | undefined {
if (!weaknesses || weaknesses.length === 0) return undefined;
return weaknesses
.map((w) =>
w.note
? `${capitalize(w.name)} ${w.amount} (${w.note})`
: `${capitalize(w.name)} ${w.amount}`,
)
.map((w) => {
const base =
w.amount == null
? capitalize(w.name)
: `${capitalize(w.name)} ${w.amount}`;
return w.note ? `${base} (${w.note})` : base;
})
.join(", ");
}