passsy / prefer-immutabler4
Prefer Immutable Objects
PublicKeep model objects immutable and hold changing state, such as which items are checked, separately, because mutating a field may not trigger setState and leaves the UI stale.
tests, run by the registry9 passed · slowest 3.8 ms
✓fires3.7 ms
fires on a public mutable field the agent writes on a model
write lib/item.dartfired: line 5
class Item {
Item(this.name);
final String name;
bool checked = false;
}✓fires3.1 ms
reports at most three fields
write lib/form.dartfired: line 2, line 3, line 4
class Form {
String name;
String email;
int age;
bool accepted;
}✓quiet3.8 ms
stays quiet on final, private and late fields
write lib/item.dartstayed quiet
class Item {
final String name;
int _retries = 0;
late final int size;
static int count = 0;
}✓quiet3.1 ms
stays quiet in a State class
write lib/page.dartstayed quiet
class _PageState extends State<Page> {
bool expanded = false;
}✓skips0.0 ms
stays quiet in tests
write test/item_test.dartno handler of the detector wants this event
class Item {
Item(this.name);
final String name;
bool checked = false;
}✓quiet3.0 ms
stays quiet on a field the agent did not write
write lib/item.dart · wrote line 4stayed quiet
class Item {
Item(this.name);
final String name;
bool checked = false;
}✓skips0.0 ms
stays quiet when the agent only reads the file
read lib/item.dartno handler of the detector wants this event
class Item {
Item(this.name);
final String name;
bool checked = false;
}✓fires3.8 ms
points at the principle when the user mentions mutable state
prompt · in fixtures/dart_appfired: "mutable"
Make the item mutable so we can toggle it✓quiet2.5 ms
stays quiet on the same words outside a Dart project
promptstayed quiet
Make the item mutable so we can toggle itdetector.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 item = source`
class Item {
Item(this.name);
final String name;
bool checked = false;
}
`;
test("fires on a public mutable field the agent writes on a model", () => {
expect(detect(write("lib/item.dart", item))).toEqual([{ line: 5 }]);
});
test("reports at most three fields", () => {
const code = source`
class Form {
String name;
String email;
int age;
bool accepted;
}
`;
expect(detect(write("lib/form.dart", code))).toHaveLength(3);
});
test("stays quiet on final, private and late fields", () => {
const code = source`
class Item {
final String name;
int _retries = 0;
late final int size;
static int count = 0;
}
`;
expect(detect(write("lib/item.dart", code))).toEqual([]);
});
test("stays quiet in a State class", () => {
const code = source`
class _PageState extends State<Page> {
bool expanded = false;
}
`;
expect(detect(write("lib/page.dart", code))).toEqual([]);
});
test("stays quiet in tests", () => {
expect(detect(write("test/item_test.dart", item))).toEqual([]);
});
test("stays quiet on a field the agent did not write", () => {
expect(detect(edit("lib/item.dart", item, { written: " final String name;" }))).toEqual([]);
});
test("stays quiet when the agent only reads the file", () => {
expect(detect(read("lib/item.dart", item))).toEqual([]);
});
const dartApp = { project: "fixtures/dart_app" };
test("points at the principle when the user mentions mutable state", () => {
expect(detect(prompt("Make the item mutable so we can toggle it"), dartApp)).toEqual([{ match: "mutable", depth: "pointer" }]);
});
test("stays quiet on the same words outside a Dart project", () => {
expect(detect(prompt("Make the item mutable so we can toggle it"))).toEqual([]);
});