fix: stabilize draft diagnostics

This commit is contained in:
lda
2026-08-09 06:37:55 +07:00 Verified
parent d4c28850d8
commit 29cbcc66c5
2 changed files with 60 additions and 19 deletions
@@ -13,22 +13,61 @@ const diagnostic = (overrides: Partial<DraftDiagnostic> = {}): DraftDiagnostic =
});
describe("withDiagnosticKeys", () => {
it("keeps unchanged diagnostic keys stable when another diagnostic is inserted", () => {
const first = withDiagnosticKeys([diagnostic(), diagnostic({ code: "invalid_step" })]);
const second = withDiagnosticKeys([
diagnostic({ code: "missing_start" }),
diagnostic(),
diagnostic({ code: "invalid_step" }),
it("collapses exact duplicates while preserving distinct diagnostics and order", () => {
const first = diagnostic();
const second = diagnostic({ code: "invalid_step" });
const entries = withDiagnosticKeys([first, first, second, first]);
expect(entries).toHaveLength(2);
expect(entries.map(({ diagnostic: entryDiagnostic }) => entryDiagnostic)).toEqual([
first,
second,
]);
expect(entries[0]?.key).toBe(withDiagnosticKeys([first])[0]?.key);
});
it("keeps distinct diagnostic keys stable across insertion and reorder", () => {
const review = diagnostic();
const invalid = diagnostic({ code: "invalid_step" });
const start = diagnostic({ code: "missing_start" });
const initial = withDiagnosticKeys([review, invalid]);
const reordered = withDiagnosticKeys([start, invalid, review]);
const keyFor = (
entries: ReturnType<typeof withDiagnosticKeys>,
code: string,
): string | undefined => entries.find(({ diagnostic: entryDiagnostic }) => entryDiagnostic.code === code)?.key;
expect(keyFor(reordered, review.code)).toBe(keyFor(initial, review.code));
expect(keyFor(reordered, invalid.code)).toBe(keyFor(initial, invalid.code));
expect(reordered.map(({ diagnostic: entryDiagnostic }) => entryDiagnostic.code)).toEqual([
start.code,
invalid.code,
review.code,
]);
});
it("keeps diagnostics distinct when details, step, or hint differ", () => {
const withDifferentDetails = diagnostic({ details: { field: "title" } });
const withOtherDetails = diagnostic({ details: { field: "name" } });
const withDifferentStep = diagnostic({ stepId: "collect" });
const withDifferentHint = diagnostic({ repairHint: "Choose another route." });
const entries = withDiagnosticKeys([
withDifferentDetails,
withOtherDetails,
withDifferentStep,
withDifferentHint,
]);
expect(second[1]?.key).toBe(first[0]?.key);
expect(second[2]?.key).toBe(first[1]?.key);
});
it("gives duplicate diagnostics distinct stable occurrence keys", () => {
const entries = withDiagnosticKeys([diagnostic(), diagnostic()]);
expect(entries[0]?.key).not.toBe(entries[1]?.key);
expect(entries[0]?.key).toBe(withDiagnosticKeys([diagnostic()])[0]?.key);
expect(entries).toHaveLength(4);
expect(new Set(entries.map(({ key }) => key)).size).toBe(4);
expect(entries.map(({ diagnostic: entryDiagnostic }) => entryDiagnostic)).toEqual([
withDifferentDetails,
withOtherDetails,
withDifferentStep,
withDifferentHint,
]);
});
});
@@ -18,15 +18,17 @@ const diagnosticIdentity = (diagnostic: DraftDiagnostic): string =>
export const withDiagnosticKeys = (
diagnostics: ReadonlyArray<DraftDiagnostic>,
): ReadonlyArray<DiagnosticEntry> => {
const occurrenceByIdentity = new Map<string, number>();
const seenIdentities = new Set<string>();
const entries: DiagnosticEntry[] = [];
for (const diagnostic of diagnostics) {
const identity = diagnosticIdentity(diagnostic);
const occurrence = occurrenceByIdentity.get(identity) ?? 0;
occurrenceByIdentity.set(identity, occurrence + 1);
if (seenIdentities.has(identity)) {
continue;
}
seenIdentities.add(identity);
entries.push({
diagnostic,
key: `diagnostic-${identity}-${occurrence}`,
key: `diagnostic-${identity}`,
});
}
return entries;