feat(spreadsheet): 2단계 여섯째 — 메모(풍선 설명 · 빨간 세모)
브레인 답(2026-09-27) — 저장 자리는 `Sheet.comments?: Record<A1, 글>`(sub3 가 0 계약에 보탬 · 이 창은 손대지 않고 `SheetWithComments` 로 모양만 가정). 명령 전용 「메모」 종류가 아직 없어 `시트통째` 명령에 얹음(전용 명령이 생기면 `applyComments` 한 곳만 고치면 됨). 행열 넣기·지우기 때 메모 주소 옮김은 A 의 refshift 를 부르는 자리로 파일 머리에 적어 둠(지금은 비움). 시험 harness(test_stage2_helpers.ts) 에 「시트통째」 명령 적용도 더함(다른 2단계 시험도 씀). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K7JS47SacjPxZ718QsZKyr
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
/* =============================================================================
|
||||
* test_stage2_comments.ts — spreadsheet_comments 시험. 돌리기: npx tsx <이 파일> (el 때문에 @ui 필요).
|
||||
* ========================================================================== */
|
||||
|
||||
import {
|
||||
countComments,
|
||||
deleteComment,
|
||||
getComment,
|
||||
hasComment,
|
||||
listComments,
|
||||
remapComments,
|
||||
setComment,
|
||||
type SheetWithComments,
|
||||
} from "../../../A00_Common/spreadsheet/spreadsheet_comments.ts";
|
||||
import { assertEqual, makeBook, makeCtx, makeSheet, v } from "./test_stage2_helpers.ts";
|
||||
|
||||
const sheet = makeSheet("s1", { A1: v(1), B2: v(2) }) as SheetWithComments;
|
||||
sheet.comments = { A1: "돌뒷길이+직고*0.1" };
|
||||
const book = makeBook([sheet]);
|
||||
|
||||
assertEqual(getComment(sheet, 0, 0), "돌뒷길이+직고*0.1", "getComment 있음");
|
||||
assertEqual(getComment(sheet, 1, 1), null, "getComment 없으면 null");
|
||||
assertEqual(hasComment(sheet, 0, 0), true, "hasComment 참");
|
||||
assertEqual(hasComment(sheet, 5, 5), false, "hasComment 거짓");
|
||||
assertEqual(countComments(book, "s1"), 1, "countComments");
|
||||
assertEqual(listComments(sheet), [{ r: 0, c: 0, 글: "돌뒷길이+직고*0.1" }], "listComments");
|
||||
|
||||
const ctx = makeCtx(book, "s1");
|
||||
setComment(ctx, 1, 1, "새 메모");
|
||||
const updated = ctx.applied.at(-1);
|
||||
assertEqual(updated?.종류, "시트통째", "setComment 는 시트통째 명령으로 나감");
|
||||
assertEqual(
|
||||
(updated as { 시트: SheetWithComments }).시트.comments,
|
||||
{ A1: "돌뒷길이+직고*0.1", B2: "새 메모" },
|
||||
"메모 칸에 더해짐(다른 메모는 그대로)",
|
||||
);
|
||||
|
||||
setComment(ctx, 0, 0, "");
|
||||
const cleared = ctx.applied.at(-1);
|
||||
assertEqual(
|
||||
(cleared as { 시트: SheetWithComments }).시트.comments,
|
||||
{ B2: "새 메모" },
|
||||
"빈 글로 지움(안 적음)",
|
||||
);
|
||||
|
||||
const moved = remapComments({ A1: "위쪽", C3: "아래쪽" }, (at) =>
|
||||
at.r === 0 ? { r: at.r + 1, c: at.c } : at,
|
||||
);
|
||||
assertEqual(moved, { A2: "위쪽", C3: "아래쪽" }, "remapComments 옮김 함수대로 자리를 바꿈");
|
||||
|
||||
const dropped = remapComments({ A1: "지워질 것" }, () => null);
|
||||
assertEqual(dropped, {}, "remapComments — shift 가 null 이면 버림");
|
||||
|
||||
deleteComment(ctx, 1, 1);
|
||||
const afterDelete = (ctx.applied.at(-1) as { 시트: SheetWithComments }).시트.comments;
|
||||
assertEqual(afterDelete?.B2, undefined, "deleteComment 로 지워짐");
|
||||
|
||||
if (process.exitCode) process.exit(process.exitCode);
|
||||
console.log("spreadsheet_comments 시험 끝");
|
||||
@@ -90,6 +90,10 @@ export function makeCtx(
|
||||
sheet.열 = sheet.열 ?? {};
|
||||
for (const c of cmd.열)
|
||||
sheet.열[colLetters(c)] = { ...sheet.열[colLetters(c)], 폭: cmd.폭 ?? undefined };
|
||||
} else if (cmd.종류 === "시트통째") {
|
||||
const idx = book.시트.findIndex((s) => s.id === cmd.시트.id);
|
||||
if (idx >= 0) book.시트[idx] = cmd.시트;
|
||||
if (cmd.서식) book.서식 = cmd.서식;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user