feat(m01-sl): 시트 로직 Model · Eval 타입 · 함수 머리 올림

SheetLogic · SlNode · SlPill · SlEdge · SlOutside · SlKind · SlEnd · SlUserTable · SlValue · SlOutsideValue · SlEvalResult
newLogic · addNode · removeNode · connect · disconnect · setPill · removePill · outsideCells · applyOutside · evalLogic · checkLogic (속은 준비 중)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBToTCGk5dqDKeXCEP3vhk
This commit is contained in:
2026-10-01 12:59:19 +09:00
co-authored by Claude Opus 5.5
parent 89220e3d3f
commit ddaff8a6b8
2 changed files with 182 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
/* =============================================================================
* M01_SL_Eval.ts
* 시트 로직 화면 계산 — 바깥 값 넣기 → 우리 스프레드시트 엔진(브라우저) → 출력 알약 · 결과 읽기 · 검사
* 저장 때는 서버가 같은 엔진을 Node 로(정함 5) · DOM 없음
* ========================================================================== */
import type { SheetLogic, SlOutside } from "./M01_SL_Model";
/** 알약 값 — 수 · 글 · 참거짓 · 빈 칸 */
export type SlValue = number | string | boolean | null;
/** 바깥 값 하나 — 표는 칸 덩어리(cell 이 왼위) */
export interface SlOutsideValue {
node: string;
cell: string;
value: SlValue | SlValue[][];
}
export interface SlEvalResult {
/** 상자 id → 출력 알약 이름 → 값 */
pills: Record<string, Record<string, SlValue>>;
result: { 노무비: number | null; 재료비: number | null; 경비: number | null; 계: number | null };
/** 쉬운 말 */
errors: string[];
}
const notReady = (): never => {
throw new Error("준비 중");
};
/** 바깥 값 칸 목록 — 화면 · 서버가 이 칸에 값을 넣음 */
export function outsideCells(_sl: SheetLogic): SlOutside[] {
return notReady();
}
/** 바깥 값 넣기 — 새 시트 로직(받은 것은 안 바꿈) */
export function applyOutside(_sl: SheetLogic, _values: SlOutsideValue[]): SheetLogic {
return notReady();
}
/** 화면 계산 */
export function evalLogic(_sl: SheetLogic): SlEvalResult {
return notReady();
}
/** 검사 — 빈 입력 알약 · 순환 · 오류 칸(쉬운 말 목록) */
export function checkLogic(_sl: SheetLogic): string[] {
return notReady();
}
+133
View File
@@ -0,0 +1,133 @@
/* =============================================================================
* M01_SL_Model.ts
* 시트 로직 Model — 로직 한 벌 = 통합문서 하나 · 상자 하나 = 시트 하나 · 알약 = 이름 붙은 칸
* 선 = 받는 입력 알약 칸에 「'시트 이름'!칸」 참조 수식 · DOM 없음
* 모양은 `docs/raw/M01_쉬운단가/시트로직_정함.md` 정함 1~5 그대로
* ========================================================================== */
import type { Workbook } from "../../A00_Common/spreadsheet/spreadsheet_types";
/** 상자 종류 — 입력값 · 고정값 · 표 · 계산 · 항목 · 다른 로직 · 결과 */
export type SlKind = "input" | "const" | "table" | "calc" | "item" | "logic" | "result";
/** 알약 = 이름 붙은 칸 */
export interface SlPill {
name: string;
/** 「B3」 */
cell: string;
unit?: string;
/** 바깥 값 칸 — 열 때 · 저장 때 마스터에서 넣음 */
outside?: boolean;
}
/** 상자 = 시트 하나 */
export interface SlNode {
id: string;
kind: SlKind;
name: string;
sheetId: string;
pillsIn: SlPill[];
pillsOut: SlPill[];
/** 표 키 · 요소 · 기존 로직 키 · 내 표 id */
ref?: string;
/** 띠 단계 — 0 입력값 · 1 표 · 2 계산 · 3 항목 · 4 결과 */
stage: number;
}
/** 선 — 출력 알약 → 입력 알약 */
export interface SlEdge {
id: string;
from: { node: string; pill: string };
to: { node: string; pill: string };
}
/** 바깥 값 칸 */
export interface SlOutside {
node: string;
cell: string;
kind: "table" | "price" | "logic";
ref: string;
}
/** 내 표 — 품셈에 없는 표(사용자가 만듦) */
export interface SlUserTable {
id: string;
name: string;
cols: string[];
rows: (number | string | null)[][];
}
export interface SheetLogic {
key: string | null;
name: string;
resultUnit: string;
workbook: Workbook;
nodes: SlNode[];
edges: SlEdge[];
userTables?: SlUserTable[];
}
/** 알약 한쪽 끝 */
export interface SlEnd {
node: string;
pill: string;
}
const notReady = (): never => {
throw new Error("준비 중");
};
/** 빈 시트 로직 */
export function newLogic(_name?: string, _resultUnit?: string): SheetLogic {
return notReady();
}
/** 상자 더하기 — 그 종류 틀(칸 A 이름 · B 값 · C 설명)로 시트를 만듦 */
export function addNode(
_sl: SheetLogic,
_kind: SlKind,
_name: string,
): { sl: SheetLogic; node: SlNode } {
return notReady();
}
/** 상자 지우기 — 시트 · 이어진 선 · 받던 참조 수식을 함께 지움 */
export function removeNode(_sl: SheetLogic, _node: string): SheetLogic {
return notReady();
}
/** 선 잇기 — 받는 알약 칸에 참조 수식 · 순환 · 없는 알약이면 막고 까닭(쉬운 말) */
export function connect(
_sl: SheetLogic,
_from: SlEnd,
_to: SlEnd,
): { sl: SheetLogic; why: string | null } {
return notReady();
}
/** 선 끊기 — 그 참조를 받는 칸 수식에서 뺌 */
export function disconnect(_sl: SheetLogic, _edge: string): SheetLogic {
return notReady();
}
/** 알약 정하기 — 같은 칸이나 같은 이름이 있으면 바꿈 */
export function setPill(
_sl: SheetLogic,
_node: string,
_cell: string,
_dir: "in" | "out",
_name: string,
_extra?: Pick<SlPill, "unit" | "outside">,
): SheetLogic {
return notReady();
}
/** 알약 빼기 — 이어진 선도 끊음 */
export function removePill(
_sl: SheetLogic,
_node: string,
_dir: "in" | "out",
_name: string,
): SheetLogic {
return notReady();
}