passsy / avoid-sealed-classes-in-public-apisr3
Avoid Sealed Classes in Public APIs
PublicAvoid sealed classes and enums in a package's public API when cases may grow, because each new case breaks every caller's exhaustive switch.
tests, run by the registry7 passed · slowest 4.1 ms
✓fires2.7 ms
fires on a public sealed class the agent writes in lib
write lib/outcome.dartfired: line 1
sealed class Outcome {}
class Ok extends Outcome {}✓quiet2.5 ms
stays quiet on a private sealed class
write lib/outcome.dartstayed quiet
sealed class _Outcome {}✓skips0.0 ms
stays quiet outside lib and in tests
write bin/outcome.dartno handler of the detector wants this event
sealed class Outcome {}
class Ok extends Outcome {}write test/outcome_test.dartno handler of the detector wants this event
sealed class Outcome {}
class Ok extends Outcome {}✓quiet2.7 ms
stays quiet on a legacy sealed class when the agent edits elsewhere or reads
write lib/outcome.dart · wrote line 3stayed quiet
sealed class Outcome {}
class Ok extends Outcome {}read lib/outcome.dartno handler of the detector wants this event
sealed class Outcome {}
class Ok extends Outcome {}✓quiet2.9 ms
stays quiet on sealed in a comment
write lib/outcome.dartstayed quiet
// Not a sealed class Outcome on purpose.
class Outcome {}✓fires4.1 ms
points at the principle when the user asks about exhaustiveness
prompt · in fixtures/dart_appfired: "exhaustive"
should this switch be exhaustive✓quiet2.6 ms
stays quiet on the same words outside a Dart project
promptstayed quiet
should this switch be exhaustivedetector.test.tseach detect() call runs the real detectorEdit
import { expect, test } from "vitest";
import { detect, edit, prompt, read, source, write } from "@wellactually/sdk/v3/test";
const outcome = source`
sealed class Outcome {}
class Ok extends Outcome {}
`;
test("fires on a public sealed class the agent writes in lib", () => {
expect(detect(write("lib/outcome.dart", outcome))).toEqual([{ line: 1 }]);
});
test("stays quiet on a private sealed class", () => {
expect(detect(write("lib/outcome.dart", "sealed class _Outcome {}"))).toEqual([]);
});
test("stays quiet outside lib and in tests", () => {
expect(detect(write("bin/outcome.dart", outcome))).toEqual([]);
expect(detect(write("test/outcome_test.dart", outcome))).toEqual([]);
});
test("stays quiet on a legacy sealed class when the agent edits elsewhere or reads", () => {
expect(detect(edit("lib/outcome.dart", outcome, { written: "class Ok extends Outcome {}" }))).toEqual([]);
expect(detect(read("lib/outcome.dart", outcome))).toEqual([]);
});
test("stays quiet on sealed in a comment", () => {
expect(detect(write("lib/outcome.dart", "// Not a sealed class Outcome on purpose.\nclass Outcome {}"))).toEqual([]);
});
const dartApp = { project: "fixtures/dart_app" };
test("points at the principle when the user asks about exhaustiveness", () => {
expect(detect(prompt("should this switch be exhaustive"), dartApp)).toEqual([{ match: "exhaustive", depth: "pointer" }]);
});
test("stays quiet on the same words outside a Dart project", () => {
expect(detect(prompt("should this switch be exhaustive"))).toEqual([]);
});