fix(audiobooks): satisfy noUncheckedIndexedAccess in audiobook code
tsc -b runs with noUncheckedIndexedAccess on, so indexed reads must guard for undefined even when the loop bounds make it provably safe. Bind the indexed value to a local in findChapterAt and ChaptersSection, and use non-null assertions in tests where the test data shape makes the indexed element guaranteed. No runtime change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
67fb38f762
commit
32ba81d395
@@ -39,8 +39,9 @@ function findChapterAt(
|
||||
seconds: number,
|
||||
): { label: string; index: number } | null {
|
||||
for (let i = chapters.length - 1; i >= 0; i--) {
|
||||
if (seconds >= chapters[i].absoluteStart) {
|
||||
return { label: chapters[i].label, index: i + 1 };
|
||||
const ch = chapters[i];
|
||||
if (ch && seconds >= ch.absoluteStart) {
|
||||
return { label: ch.label, index: i + 1 };
|
||||
}
|
||||
}
|
||||
return chapters[0] ? { label: chapters[0].label, index: 1 } : null;
|
||||
|
||||
@@ -32,13 +32,13 @@ describe("ChaptersSection", () => {
|
||||
it("sort menu switches between position and longest-first orders", async () => {
|
||||
render(<ChaptersSection files={files} currentPositionSeconds={null} onSelect={vi.fn()} />);
|
||||
const rowsBefore = screen.getAllByRole("button", { name: /Prologue|Memory/ });
|
||||
expect(within(rowsBefore[0]).getByText("Prologue")).toBeInTheDocument();
|
||||
expect(within(rowsBefore[0]!).getByText("Prologue")).toBeInTheDocument();
|
||||
|
||||
await userEvent.click(screen.getByRole("button", { name: /sort/i }));
|
||||
await userEvent.click(screen.getByRole("menuitem", { name: /longest first/i }));
|
||||
|
||||
const rowsAfter = screen.getAllByRole("button", { name: /Prologue|Memory/ });
|
||||
expect(within(rowsAfter[0]).getByText("Memory")).toBeInTheDocument();
|
||||
expect(within(rowsAfter[0]!).getByText("Memory")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("calls onSelect with absolute start seconds when a chapter is clicked", async () => {
|
||||
|
||||
@@ -68,7 +68,8 @@ export function ChaptersSection({ files, currentPositionSeconds, onSelect }: Cha
|
||||
const currentIndex = useMemo(() => {
|
||||
if (currentPositionSeconds == null) return -1;
|
||||
for (let i = rows.length - 1; i >= 0; i--) {
|
||||
if (currentPositionSeconds >= rows[i].absoluteStart) return i;
|
||||
const row = rows[i];
|
||||
if (row && currentPositionSeconds >= row.absoluteStart) return i;
|
||||
}
|
||||
return -1;
|
||||
}, [rows, currentPositionSeconds]);
|
||||
|
||||
@@ -41,8 +41,8 @@ describe("useAudiobookPlayback", () => {
|
||||
useAudiobookPlayback({ contentId: "c", files, initialPositionSeconds: 0 }),
|
||||
);
|
||||
expect(result.current.chapters).toHaveLength(2);
|
||||
expect(result.current.chapters[0].start_seconds).toBe(0);
|
||||
expect(result.current.chapters[1].start_seconds).toBe(300);
|
||||
expect(result.current.chapters[0]!.start_seconds).toBe(0);
|
||||
expect(result.current.chapters[1]!.start_seconds).toBe(300);
|
||||
});
|
||||
|
||||
it("computes streamUrl from the first file id", () => {
|
||||
|
||||
Reference in New Issue
Block a user