feat(spreadsheet): 2단계 — 데이터 도구(텍스트 나누기·중복 제거·연속 채우기)

텍스트 나누기(구분 기호 탭·세미콜론·쉼표·공백·사용자 지정 또는 고정 폭 · 미리보기) ·
중복된 항목 제거(비교할 열 고르기 · 머리글 포함 여부 · 지운 수를 토스트로 알림) ·
채우기 연속 데이터(단계 값 · 끝 값 · 행/열 방향)를 새 파일로 짬. 셋 다 「칸」 명령
하나로만 문서를 바꿈. 순수 로직(나누기 · 중복 찾기 · 등차수열 짓기)은 DOM 없이도
시험 가능해 resources/tester/spreadsheet/test_stage2_data_tools.ts 로 다 검증함.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K7JS47SacjPxZ718QsZKyr
This commit is contained in:
2026-09-27 21:27:45 +09:00
co-authored by Claude Sonnet 5
parent 7aa9f2229d
commit de94486af7
2 changed files with 535 additions and 0 deletions
@@ -0,0 +1,113 @@
/* =============================================================================
* test_stage2_data_tools.ts — spreadsheet_data_tools 시험(텍스트 나누기 · 중복 제거 · 연속 채우기).
* 돌리기: npx tsx <이 파일> (`@ui/*` 별칭 때문에 plain node 안 됨)
* ========================================================================== */
import {
applyFillSeries,
applyTextToColumns,
buildLinearSeries,
findDuplicateRowIndexes,
removeDuplicateRows,
splitDelimited,
splitFixedWidth,
} from "../../../A00_Common/spreadsheet/spreadsheet_data_tools.ts";
import { a1, assertEqual, makeBook, makeCtx, makeSheet, v } from "./test_stage2_helpers.ts";
// ── 텍스트 나누기 ──────────────────────────────────────────────
assertEqual(splitDelimited("가,나,다", ["쉼표"], ""), ["가", "나", "다"], "쉼표 나누기");
assertEqual(splitDelimited("가\t나", ["탭"], ""), ["가", "나"], "탭 나누기");
assertEqual(
splitDelimited("가;나,다", ["세미콜론", "쉼표"], ""),
["가", "나", "다"],
"복수 구분 기호",
);
assertEqual(splitDelimited("가|나", ["사용자"], "|"), ["가", "나"], "사용자 지정 구분 기호");
assertEqual(splitDelimited("가나다", [], ""), ["가나다"], "구분 기호 없으면 한 칸 그대로");
assertEqual(splitFixedWidth("2026-09-27", [4, 7]), ["2026", "-09", "-27"], "고정 폭 나누기");
assertEqual(splitFixedWidth("ABC", [10]), ["ABC"], "자리가 글보다 길면 한 칸");
{
const book = makeBook([makeSheet("s1", {})]);
const ctx = makeCtx(book, "s1");
applyTextToColumns(ctx, { r: 0, c: 0 }, [
["가", "나"],
["1", "2"],
]);
assertEqual(book.시트[0].칸[a1(0, 0)], { 값: "가" }, "나누기 결과 A1");
assertEqual(book.시트[0].칸[a1(0, 1)], { 값: "나" }, "나누기 결과 B1");
assertEqual(book.시트[0].칸[a1(1, 0)], { 값: 1 }, "나누기 결과 숫자는 수로");
assertEqual(book.시트[0].칸[a1(1, 1)], { 값: 2 }, "나누기 결과 B2");
}
// ── 중복된 항목 제거 ──────────────────────────────────────────
assertEqual(
findDuplicateRowIndexes(
[
["가", "1"],
["나", "2"],
["가", "1"],
["다", "3"],
["나", "2"],
],
[0, 1],
),
[2, 4],
"중복 자리 찾기(모든 열 비교)",
);
assertEqual(
findDuplicateRowIndexes(
[
["가", "1"],
["가", "9"],
],
[0],
),
[1],
"일부 열만 비교",
);
{
const book = makeBook([
makeSheet("s1", {
[a1(0, 0)]: v("가"),
[a1(1, 0)]: v("나"),
[a1(2, 0)]: v("가"),
[a1(3, 0)]: v("다"),
}),
]);
const ctx = makeCtx(book, "s1", {
s1: { A1: "가", A2: "나", A3: "가", A4: "다" },
});
const removed = removeDuplicateRows(ctx, { r0: 0, c0: 0, r1: 3, c1: 0 }, [0], false);
assertEqual(removed, 1, "지운 중복 행 수");
assertEqual(book.시트[0].칸[a1(0, 0)], { 값: "가" }, "중복 제거 뒤 A1 그대로");
assertEqual(book.시트[0].칸[a1(1, 0)], { 값: "나" }, "중복 제거 뒤 A2 그대로");
assertEqual(book.시트[0].칸[a1(2, 0)], { 값: "다" }, "중복 제거 뒤 위로 당김");
assertEqual(book.시트[0].칸[a1(3, 0)], undefined, "중복 제거 뒤 마지막 칸 비움");
}
// ── 채우기 연속 데이터 ──────────────────────────────────────────
assertEqual(buildLinearSeries(1, 1, null, 5), [1, 2, 3, 4, 5], "단계 1 · 5개");
assertEqual(buildLinearSeries(0, 2, 6, 100), [0, 2, 4, 6], "끝값에서 멈춤");
assertEqual(buildLinearSeries(10, -2, 4, 100), [10, 8, 6, 4], "내림차순 끝값에서 멈춤");
{
const book = makeBook([makeSheet("s1", {})]);
const ctx = makeCtx(book, "s1");
applyFillSeries(ctx, { r: 0, c: 0 }, "열", [1, 2, 3]);
assertEqual(book.시트[0].칸[a1(0, 0)], { 값: 1 }, "세로 채우기 A1");
assertEqual(book.시트[0].칸[a1(1, 0)], { 값: 2 }, "세로 채우기 A2");
assertEqual(book.시트[0].칸[a1(2, 0)], { 값: 3 }, "세로 채우기 A3");
}
{
const book = makeBook([makeSheet("s1", {})]);
const ctx = makeCtx(book, "s1");
applyFillSeries(ctx, { r: 0, c: 0 }, "행", [1, 2]);
assertEqual(book.시트[0].칸[a1(0, 0)], { 값: 1 }, "가로 채우기 A1");
assertEqual(book.시트[0].칸[a1(0, 1)], { 값: 2 }, "가로 채우기 B1");
}
if (process.exitCode) process.exit(process.exitCode);
console.log("spreadsheet_data_tools 시험 끝");