diff --git a/src/commands/doctor-config-flow.ts b/src/commands/doctor-config-flow.ts index 2d785ecda5c..4bb29761c2d 100644 --- a/src/commands/doctor-config-flow.ts +++ b/src/commands/doctor-config-flow.ts @@ -7,6 +7,7 @@ import { noteOpencodeProviderOverrides } from "./doctor-config-analysis.js"; import { runDoctorConfigPreflight } from "./doctor-config-preflight.js"; import { normalizeCompatibilityConfigValues } from "./doctor-legacy-config.js"; import type { DoctorOptions } from "./doctor-prompter.js"; +import { emitDoctorNotes } from "./doctor/emit-notes.js"; import { finalizeDoctorConfigFlow } from "./doctor/finalize-config-flow.js"; import { runMatrixDoctorSequence } from "./doctor/providers/matrix.js"; import { runDoctorRepairSequence } from "./doctor/repair-sequencing.js"; @@ -80,12 +81,11 @@ export async function loadAndMaybeMigrateDoctorConfig(params: { env: process.env, shouldRepair, }); - for (const change of matrixSequence.changeNotes) { - note(change, "Doctor changes"); - } - for (const warning of matrixSequence.warningNotes) { - note(warning, "Doctor warnings"); - } + emitDoctorNotes({ + note, + changeNotes: matrixSequence.changeNotes, + warningNotes: matrixSequence.warningNotes, + }); const missingDefaultAccountBindingWarnings = collectMissingDefaultAccountBindingWarnings(candidate); @@ -103,19 +103,19 @@ export async function loadAndMaybeMigrateDoctorConfig(params: { doctorFixCommand, }); ({ cfg, candidate, pendingChanges, fixHints } = repairSequence.state); - for (const change of repairSequence.changeNotes) { - note(change, "Doctor changes"); - } - for (const warning of repairSequence.warningNotes) { - note(warning, "Doctor warnings"); - } + emitDoctorNotes({ + note, + changeNotes: repairSequence.changeNotes, + warningNotes: repairSequence.warningNotes, + }); } else { - for (const warning of collectDoctorPreviewWarnings({ - cfg: candidate, - doctorFixCommand, - })) { - note(warning, "Doctor warnings"); - } + emitDoctorNotes({ + note, + warningNotes: collectDoctorPreviewWarnings({ + cfg: candidate, + doctorFixCommand, + }), + }); } const mutableAllowlistHits = scanMutableAllowlistEntries(candidate); diff --git a/src/commands/doctor/emit-notes.test.ts b/src/commands/doctor/emit-notes.test.ts new file mode 100644 index 00000000000..315dfba8877 --- /dev/null +++ b/src/commands/doctor/emit-notes.test.ts @@ -0,0 +1,40 @@ +import { describe, expect, it, vi } from "vitest"; +import { emitDoctorNotes } from "./emit-notes.js"; + +describe("doctor note emission", () => { + it("emits grouped change and warning notes with the correct titles", () => { + const note = vi.fn(); + + emitDoctorNotes({ + note, + changeNotes: ["change one", "change two"], + warningNotes: ["warning one"], + }); + + expect(note.mock.calls).toEqual([ + ["change one", "Doctor changes"], + ["change two", "Doctor changes"], + ["warning one", "Doctor warnings"], + ]); + }); + + it("emits only warning notes when changeNotes is omitted", () => { + const note = vi.fn(); + + emitDoctorNotes({ + note, + warningNotes: ["warning only"], + }); + + expect(note.mock.calls).toEqual([["warning only", "Doctor warnings"]]); + }); + + it("emits nothing when note groups are omitted or empty", () => { + const note = vi.fn(); + + emitDoctorNotes({ note }); + emitDoctorNotes({ note, changeNotes: [], warningNotes: [] }); + + expect(note).not.toHaveBeenCalled(); + }); +}); diff --git a/src/commands/doctor/emit-notes.ts b/src/commands/doctor/emit-notes.ts new file mode 100644 index 00000000000..884bf26c89f --- /dev/null +++ b/src/commands/doctor/emit-notes.ts @@ -0,0 +1,12 @@ +export function emitDoctorNotes(params: { + note: (message: string, title?: string) => void; + changeNotes?: string[]; + warningNotes?: string[]; +}): void { + for (const change of params.changeNotes ?? []) { + params.note(change, "Doctor changes"); + } + for (const warning of params.warningNotes ?? []) { + params.note(warning, "Doctor warnings"); + } +}