style: apply prettier across the tree

One-shot prettier pass so the new format:check gate starts from a clean
baseline. Formatting only — no behaviour change. Generator-owned and
vendored artifacts stay untouched via .prettierignore.
This commit is contained in:
Marc-André Bombeck committed 2026-06-19 22:20:31 +02:00
1 parent b3fea2ef59
commit 1f4ba5939d
1000 files changed
+12130 -8385

No files matched your search

@@ -60,12 +60,14 @@ vi.mock("next/headers", () => ({
// `recomputeUserMoodRollups` aggregate. The warm-up is fire-and-
// forget on the route so its return value is irrelevant for parity.
vi.mock("@/lib/rollups/mood-rollups", async () => {
const actual = await vi.importActual<typeof import("@/lib/rollups/mood-rollups")>(
"@/lib/rollups/mood-rollups",
);
const actual = await vi.importActual<
typeof import("@/lib/rollups/mood-rollups")
>("@/lib/rollups/mood-rollups");
return {
...actual,
ensureUserMoodRollupsFresh: vi.fn().mockResolvedValue({ recomputed: false }),
ensureUserMoodRollupsFresh: vi
.fn()
.mockResolvedValue({ recomputed: false }),
};
});
@@ -24,12 +24,20 @@ vi.mock("@/lib/crypto", () => ({
decrypt: (s: string) => s.replace(/^enc:/, ""),
}));
vi.mock("@/lib/auth/session", () => ({ getSession: vi.fn() }));
vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined) }));
vi.mock("@/lib/auth/audit", () => ({
auditLog: vi.fn().mockResolvedValue(undefined),
}));
vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() }));
vi.mock("@/lib/db-compat", () => ({ ensureDbCompatibility: vi.fn().mockResolvedValue(undefined) }));
vi.mock("@/lib/db-compat", () => ({
ensureDbCompatibility: vi.fn().mockResolvedValue(undefined),
}));
vi.mock("next/headers", () => ({
headers: vi.fn(async () => ({ get: () => null })),
cookies: vi.fn(async () => ({ get: () => undefined, set: () => {}, delete: () => {} })),
cookies: vi.fn(async () => ({
get: () => undefined,
set: () => {},
delete: () => {},
})),
}));
import { POST } from "../custom/route";
@@ -59,19 +67,40 @@ describe("POST /api/mood/tags/custom", () => {
it("creates a custom tag and returns it (custom:true, decrypted label)", async () => {
db.moodTag.count.mockResolvedValue(3);
db.moodTag.create.mockResolvedValue({
key: "custom:abc", icon: "Heart", kind: "BINARY", scaleMin: 1, scaleMax: 5, inverse: false,
key: "custom:abc",
icon: "Heart",
kind: "BINARY",
scaleMin: 1,
scaleMax: 5,
inverse: false,
});
const res = await POST(jsonReq("http://localhost/api/mood/tags/custom", "POST", { label: "Date night", icon: "Heart" }));
const res = await POST(
jsonReq("http://localhost/api/mood/tags/custom", "POST", {
label: "Date night",
icon: "Heart",
}),
);
expect(res.status).toBe(201);
const body = (await res.json()) as { data: { custom: boolean; label: string; labelKey: null; key: string } };
expect(body.data).toMatchObject({ custom: true, label: "Date night", labelKey: null, key: "custom:abc" });
const body = (await res.json()) as {
data: { custom: boolean; label: string; labelKey: null; key: string };
};
expect(body.data).toMatchObject({
custom: true,
label: "Date night",
labelKey: null,
key: "custom:abc",
});
// Label is stored encrypted, never plaintext.
expect(db.moodTag.create.mock.calls[0][0].data.labelEncrypted).toBe("enc:Date night");
expect(db.moodTag.create.mock.calls[0][0].data.labelEncrypted).toBe(
"enc:Date night",
);
});
it("rejects over the per-user cap with 422", async () => {
db.moodTag.count.mockResolvedValue(50);
const res = await POST(jsonReq("http://localhost/api/mood/tags/custom", "POST", { label: "X" }));
const res = await POST(
jsonReq("http://localhost/api/mood/tags/custom", "POST", { label: "X" }),
);
expect(res.status).toBe(422);
expect(db.moodTag.create).not.toHaveBeenCalled();
});
@@ -79,21 +108,38 @@ describe("POST /api/mood/tags/custom", () => {
it("defaults to the seeded custom category without a categoryKey (v1.13 contract)", async () => {
db.moodTag.count.mockResolvedValue(0);
db.moodTag.create.mockResolvedValue({
key: "custom:x", icon: null, kind: "BINARY", scaleMin: 1, scaleMax: 5, inverse: false,
key: "custom:x",
icon: null,
kind: "BINARY",
scaleMin: 1,
scaleMax: 5,
inverse: false,
});
await POST(jsonReq("http://localhost/api/mood/tags/custom", "POST", { label: "X" }));
await POST(
jsonReq("http://localhost/api/mood/tags/custom", "POST", { label: "X" }),
);
expect(db.moodTagCategory.findFirst).not.toHaveBeenCalled();
expect(db.moodTag.create.mock.calls[0][0].data.categoryId).toBe("mtc_custom");
expect(db.moodTag.create.mock.calls[0][0].data.categoryId).toBe(
"mtc_custom",
);
});
it("resolves categoryKey to a seeded OR own group (v1.17.0) and 422s an unknown one", async () => {
db.moodTag.count.mockResolvedValue(0);
db.moodTagCategory.findFirst.mockResolvedValue({ id: "cg1" });
db.moodTag.create.mockResolvedValue({
key: "custom:x", icon: null, kind: "BINARY", scaleMin: 1, scaleMax: 5, inverse: false,
key: "custom:x",
icon: null,
kind: "BINARY",
scaleMin: 1,
scaleMax: 5,
inverse: false,
});
const ok = await POST(
jsonReq("http://localhost/api/mood/tags/custom", "POST", { label: "X", categoryKey: "customcat:g1" }),
jsonReq("http://localhost/api/mood/tags/custom", "POST", {
label: "X",
categoryKey: "customcat:g1",
}),
);
expect(ok.status).toBe(201);
expect(db.moodTag.create.mock.calls[0][0].data.categoryId).toBe("cg1");
@@ -107,7 +153,10 @@ describe("POST /api/mood/tags/custom", () => {
db.moodTagCategory.findFirst.mockResolvedValue(null);
const bad = await POST(
jsonReq("http://localhost/api/mood/tags/custom", "POST", { label: "X", categoryKey: "customcat:theirs" }),
jsonReq("http://localhost/api/mood/tags/custom", "POST", {
label: "X",
categoryKey: "customcat:theirs",
}),
);
expect(bad.status).toBe(422);
});
@@ -119,14 +168,19 @@ describe("PATCH/DELETE /api/mood/tags/custom/:key", () => {
it("404s when the key is not the caller's own custom tag", async () => {
db.moodTag.findFirst.mockResolvedValue(null);
const res = await PATCH(
jsonReq("http://localhost/api/mood/tags/custom/custom:x", "PATCH", { isActive: false }),
jsonReq("http://localhost/api/mood/tags/custom/custom:x", "PATCH", {
isActive: false,
}),
params("custom:x"),
);
expect(res.status).toBe(404);
});
it("404s a non-custom key without touching the DB", async () => {
const res = await DELETE(new NextRequest("http://localhost/api/mood/tags/custom/happy"), params("happy"));
const res = await DELETE(
new NextRequest("http://localhost/api/mood/tags/custom/happy"),
params("happy"),
);
expect(res.status).toBe(404);
expect(db.moodTag.findFirst).not.toHaveBeenCalled();
});
@@ -135,22 +189,34 @@ describe("PATCH/DELETE /api/mood/tags/custom/:key", () => {
db.moodTag.findFirst.mockResolvedValue({ id: "id1" });
db.moodTagCategory.findFirst.mockResolvedValue({ id: "cg1" });
db.moodTag.update.mockResolvedValue({
key: "custom:x", icon: null, kind: "BINARY", scaleMin: 1, scaleMax: 5,
inverse: false, isActive: true, labelEncrypted: "enc:X",
key: "custom:x",
icon: null,
kind: "BINARY",
scaleMin: 1,
scaleMax: 5,
inverse: false,
isActive: true,
labelEncrypted: "enc:X",
});
const res = await PATCH(
jsonReq("http://localhost/api/mood/tags/custom/custom:x", "PATCH", { categoryKey: "customcat:g1" }),
jsonReq("http://localhost/api/mood/tags/custom/custom:x", "PATCH", {
categoryKey: "customcat:g1",
}),
params("custom:x"),
);
expect(res.status).toBe(200);
expect(db.moodTag.update.mock.calls[0][0].data).toEqual({ categoryId: "cg1" });
expect(db.moodTag.update.mock.calls[0][0].data).toEqual({
categoryId: "cg1",
});
});
it("422s a move to an unknown / foreign group without writing", async () => {
db.moodTag.findFirst.mockResolvedValue({ id: "id1" });
db.moodTagCategory.findFirst.mockResolvedValue(null);
const res = await PATCH(
jsonReq("http://localhost/api/mood/tags/custom/custom:x", "PATCH", { categoryKey: "ghost" }),
jsonReq("http://localhost/api/mood/tags/custom/custom:x", "PATCH", {
categoryKey: "ghost",
}),
params("custom:x"),
);
expect(res.status).toBe(422);
@@ -159,15 +225,26 @@ describe("PATCH/DELETE /api/mood/tags/custom/:key", () => {
it("soft-deactivates by default and hard-deletes on ?purge=true", async () => {
db.moodTag.findFirst.mockResolvedValue({ id: "id1" });
const soft = await DELETE(new NextRequest("http://localhost/api/mood/tags/custom/custom:abc"), params("custom:abc"));
const soft = await DELETE(
new NextRequest("http://localhost/api/mood/tags/custom/custom:abc"),
params("custom:abc"),
);
expect(soft.status).toBe(200);
expect(db.moodTag.update).toHaveBeenCalledWith({ where: { id: "id1" }, data: { isActive: false } });
expect(db.moodTag.update).toHaveBeenCalledWith({
where: { id: "id1" },
data: { isActive: false },
});
expect(db.moodTag.delete).not.toHaveBeenCalled();
vi.clearAllMocks();
vi.mocked(getSession).mockResolvedValue(SESSION_OK as never);
db.moodTag.findFirst.mockResolvedValue({ id: "id1" });
const purge = await DELETE(new NextRequest("http://localhost/api/mood/tags/custom/custom:abc?purge=true"), params("custom:abc"));
const purge = await DELETE(
new NextRequest(
"http://localhost/api/mood/tags/custom/custom:abc?purge=true",
),
params("custom:abc"),
);
expect(purge.status).toBe(200);
expect(db.moodTag.delete).toHaveBeenCalledWith({ where: { id: "id1" } });
});
@@ -176,7 +253,9 @@ describe("PATCH/DELETE /api/mood/tags/custom/:key", () => {
describe("PUT /api/mood/tags/:key/hidden", () => {
it("rejects a custom key with 400 (custom tags hide via isActive)", async () => {
const res = await PUT(
jsonReq("http://localhost/api/mood/tags/custom:abc/hidden", "PUT", { hidden: true }),
jsonReq("http://localhost/api/mood/tags/custom:abc/hidden", "PUT", {
hidden: true,
}),
{ params: Promise.resolve({ key: "custom:abc" }) },
);
expect(res.status).toBe(400);
@@ -185,7 +264,9 @@ describe("PUT /api/mood/tags/:key/hidden", () => {
it("upserts a hide row for a catalogue tag", async () => {
db.moodTag.findFirst.mockResolvedValue({ id: "t_sad" });
const res = await PUT(
jsonReq("http://localhost/api/mood/tags/sad/hidden", "PUT", { hidden: true }),
jsonReq("http://localhost/api/mood/tags/sad/hidden", "PUT", {
hidden: true,
}),
{ params: Promise.resolve({ key: "sad" }) },
);
expect(res.status).toBe(200);
@@ -29,19 +29,27 @@ const db = vi.hoisted(() => {
vi.mock("@/lib/db", () => ({
prisma: db,
toJson: <T,>(v: T) => v,
toJson: <T>(v: T) => v,
}));
vi.mock("@/lib/crypto", () => ({
encrypt: (s: string) => `enc:${s}`,
decrypt: (s: string) => s.replace(/^enc:/, ""),
}));
vi.mock("@/lib/auth/session", () => ({ getSession: vi.fn() }));
vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined) }));
vi.mock("@/lib/auth/audit", () => ({
auditLog: vi.fn().mockResolvedValue(undefined),
}));
vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() }));
vi.mock("@/lib/db-compat", () => ({ ensureDbCompatibility: vi.fn().mockResolvedValue(undefined) }));
vi.mock("@/lib/db-compat", () => ({
ensureDbCompatibility: vi.fn().mockResolvedValue(undefined),
}));
vi.mock("next/headers", () => ({
headers: vi.fn(async () => ({ get: () => null })),
cookies: vi.fn(async () => ({ get: () => undefined, set: () => {}, delete: () => {} })),
cookies: vi.fn(async () => ({
get: () => undefined,
set: () => {},
delete: () => {},
})),
}));
import { POST } from "../groups/route";
@@ -115,7 +123,9 @@ describe("POST /api/mood/tags/groups", () => {
describe("PATCH /api/mood/tags/groups/:key", () => {
it("404s a seeded category key without touching the DB", async () => {
const res = await PATCH(
jsonReq("http://localhost/api/mood/tags/groups/feelings", "PATCH", { label: "x" }),
jsonReq("http://localhost/api/mood/tags/groups/feelings", "PATCH", {
label: "x",
}),
params("feelings"),
);
expect(res.status).toBe(404);
@@ -125,7 +135,9 @@ describe("PATCH /api/mood/tags/groups/:key", () => {
it("404s when the key is not the caller's own group", async () => {
db.moodTagCategory.findFirst.mockResolvedValue(null);
const res = await PATCH(
jsonReq("http://localhost/api/mood/tags/groups/customcat:x", "PATCH", { label: "x" }),
jsonReq("http://localhost/api/mood/tags/groups/customcat:x", "PATCH", {
label: "x",
}),
params("customcat:x"),
);
expect(res.status).toBe(404);
@@ -140,11 +152,15 @@ describe("PATCH /api/mood/tags/groups/:key", () => {
labelEncrypted: "enc:Neu",
});
const res = await PATCH(
jsonReq("http://localhost/api/mood/tags/groups/customcat:x", "PATCH", { label: "Neu" }),
jsonReq("http://localhost/api/mood/tags/groups/customcat:x", "PATCH", {
label: "Neu",
}),
params("customcat:x"),
);
expect(res.status).toBe(200);
const body = (await res.json()) as { data: { label: string; isActive: boolean } };
const body = (await res.json()) as {
data: { label: string; isActive: boolean };
};
expect(body.data).toMatchObject({ label: "Neu", isActive: true });
expect(db.moodTagCategory.update.mock.calls[0][0].data).toEqual({
labelEncrypted: "enc:Neu",
@@ -200,7 +216,9 @@ describe("DELETE /api/mood/tags/groups/:key", () => {
it("hard-deletes the emptied group row on ?purge=true", async () => {
const res = await DELETE(
new NextRequest("http://localhost/api/mood/tags/groups/customcat:x?purge=true"),
new NextRequest(
"http://localhost/api/mood/tags/groups/customcat:x?purge=true",
),
params("customcat:x"),
);
expect(res.status).toBe(200);
+22 -6
View File
@@ -13,15 +13,23 @@ const db = vi.hoisted(() => ({
vi.mock("@/lib/db", () => ({
prisma: db,
toJson: <T,>(v: T) => v,
toJson: <T>(v: T) => v,
}));
vi.mock("@/lib/auth/session", () => ({ getSession: vi.fn() }));
vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined) }));
vi.mock("@/lib/auth/audit", () => ({
auditLog: vi.fn().mockResolvedValue(undefined),
}));
vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() }));
vi.mock("@/lib/db-compat", () => ({ ensureDbCompatibility: vi.fn().mockResolvedValue(undefined) }));
vi.mock("@/lib/db-compat", () => ({
ensureDbCompatibility: vi.fn().mockResolvedValue(undefined),
}));
vi.mock("next/headers", () => ({
headers: vi.fn(async () => ({ get: () => null })),
cookies: vi.fn(async () => ({ get: () => undefined, set: () => {}, delete: () => {} })),
cookies: vi.fn(async () => ({
get: () => undefined,
set: () => {},
delete: () => {},
})),
}));
import { GET, PUT } from "../layout/route";
@@ -77,7 +85,11 @@ describe("GET /api/mood/tags/layout", () => {
const body = (await res.json()) as {
data: { groupOrder: string[]; placements: Record<string, string[]> };
};
expect(body.data.groupOrder).toEqual(["customcat:g1", "feelings", "custom"]);
expect(body.data.groupOrder).toEqual([
"customcat:g1",
"feelings",
"custom",
]);
expect(body.data.placements).toEqual({ "customcat:g1": ["happy"] });
});
});
@@ -101,7 +113,11 @@ describe("PUT /api/mood/tags/layout", () => {
const body = (await res.json()) as {
data: { groupOrder: string[]; placements: Record<string, string[]> };
};
expect(body.data.groupOrder).toEqual(["custom", "feelings", "customcat:g1"]);
expect(body.data.groupOrder).toEqual([
"custom",
"feelings",
"customcat:g1",
]);
expect(body.data.placements).toEqual({ feelings: ["sad"] });
});
+66 -6
View File
@@ -58,8 +58,22 @@ const SESSION_OK = {
};
const CATEGORIES = [
{ id: "c1", key: "feelings", labelKey: "mood.tagCategory.feelings", icon: "Smile", userId: null, labelEncrypted: null },
{ id: "mtc_custom", key: "custom", labelKey: "mood.tagCategory.custom", icon: "Tag", userId: null, labelEncrypted: null },
{
id: "c1",
key: "feelings",
labelKey: "mood.tagCategory.feelings",
icon: "Smile",
userId: null,
labelEncrypted: null,
},
{
id: "mtc_custom",
key: "custom",
labelKey: "mood.tagCategory.custom",
icon: "Tag",
userId: null,
labelEncrypted: null,
},
];
const OWN_GROUP = {
@@ -72,9 +86,48 @@ const OWN_GROUP = {
};
const TAGS = [
{ id: "t_happy", categoryId: "c1", key: "happy", labelKey: "mood.tag.happy", icon: "Smile", kind: "BINARY", scaleMin: 1, scaleMax: 5, inverse: false, isActive: true, userId: null, labelEncrypted: null },
{ id: "t_sad", categoryId: "c1", key: "sad", labelKey: "mood.tag.sad", icon: "Frown", kind: "BINARY", scaleMin: 1, scaleMax: 5, inverse: false, isActive: true, userId: null, labelEncrypted: null },
{ id: "t_custom", categoryId: "mtc_custom", key: "custom:abc", labelKey: "custom:abc", icon: "Heart", kind: "BINARY", scaleMin: 1, scaleMax: 5, inverse: false, isActive: true, userId: "user-1", labelEncrypted: "enc:Migräne" },
{
id: "t_happy",
categoryId: "c1",
key: "happy",
labelKey: "mood.tag.happy",
icon: "Smile",
kind: "BINARY",
scaleMin: 1,
scaleMax: 5,
inverse: false,
isActive: true,
userId: null,
labelEncrypted: null,
},
{
id: "t_sad",
categoryId: "c1",
key: "sad",
labelKey: "mood.tag.sad",
icon: "Frown",
kind: "BINARY",
scaleMin: 1,
scaleMax: 5,
inverse: false,
isActive: true,
userId: null,
labelEncrypted: null,
},
{
id: "t_custom",
categoryId: "mtc_custom",
key: "custom:abc",
labelKey: "custom:abc",
icon: "Heart",
kind: "BINARY",
scaleMin: 1,
scaleMax: 5,
inverse: false,
isActive: true,
userId: "user-1",
labelEncrypted: "enc:Migräne",
},
];
const ARCHIVED_TAG = {
@@ -188,7 +241,14 @@ describe("GET /api/mood/tags — groups + layout + archived + usage (v1.17.0)",
categoryFindMany.mockResolvedValue([...CATEGORIES, OWN_GROUP]);
tagFindMany.mockResolvedValue([
...TAGS,
{ ...TAGS[2], id: "t_c2", categoryId: "cg1", key: "custom:ing1", labelKey: "custom:ing1", labelEncrypted: "enc:Sitzung" },
{
...TAGS[2],
id: "t_c2",
categoryId: "cg1",
key: "custom:ing1",
labelKey: "custom:ing1",
labelEncrypted: "enc:Sitzung",
},
]);
const res = await GET(req());
const body = (await res.json()) as Body;
+3 -1
View File
@@ -125,7 +125,9 @@ export const DELETE = apiHandler(
if (layout.groupOrder !== undefined || layout.placements !== undefined) {
await tx.user.update({
where: { id: user.id },
data: { moodTagLayoutJson: toJson(stripGroupFromLayout(layout, key)) },
data: {
moodTagLayoutJson: toJson(stripGroupFromLayout(layout, key)),
},
});
}
+1 -5
View File
@@ -1,11 +1,7 @@
import { NextRequest } from "next/server";
import { prisma, toJson } from "@/lib/db";
import {
apiSuccess,
returnAllZodIssues,
safeJson,
} from "@/lib/api-response";
import { apiSuccess, returnAllZodIssues, safeJson } from "@/lib/api-response";
import { apiHandler, requireAuth } from "@/lib/api-handler";
import { annotate } from "@/lib/logging/context";
import {
+1 -3
View File
@@ -165,9 +165,7 @@ export const GET = apiHandler(async (request: NextRequest) => {
...(includeHidden && !isCustom
? { hidden: hiddenIds.has(t.id) }
: {}),
...(includeArchived && isCustom
? { archived: !t.isActive }
: {}),
...(includeArchived && isCustom ? { archived: !t.isActive } : {}),
...(includeUsage
? { usageCount: usageByTagId.get(t.id) ?? 0 }
: {}),