- M01 단가산출 기초 · M02 단가산출 상세 보기 = 수식(줄 쌓기 · 기본) · 단가산출 상세 둘 - 줄 쌓기에 M02 사본 [단가 갱신] · [재생성](미리 셈 → 알림 → 저장 · 고침 있으면 막음) · 판 바뀜(409) 문서 그대로면 새 판으로 다시 저장 옮김 - 옛 수식 문서 화면 걷음(formula_doc_screen · defs · edit · lines · math · math_model · rows · sub · formula_doc.css) · 이미 안 부르던 796-2 수식 나무 화면(LogicLab_Equation · Defs · Var · css · M01_Logic_Equation_Model · sheet_formula_cell · ui_template_equation_defs · edit) 걷음 — 18 파일 4,860 줄 - formula_doc_render = 줄 쌓기가 쓰는 reach 만 · 옵션 가로 CSS 는 line_stack.css 로 - 남김 = 계산기 common_util_formula_doc* · 서버 길 · 옵션 · 사본 표지 · 합계 상자 · KaTeX · 시험 페이지 tools/line-stack-test - 시험: test_796_2 지움(걷은 화면 원본 검사뿐) · 799_1 · 800_2 걷은 화면 줄만 뺌 · 799_2 · 802_4b2 · 804_2 보기 · 화면 파일 대상 바꿈 · test_804_6 새로(걷은 파일 · 부르는 곳 없음 · 첫 탭 · 사본 할일) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
83 lines
2.8 KiB
TypeScript
83 lines
2.8 KiB
TypeScript
/* =============================================================================
|
|
* formula_doc_render.ts
|
|
* 수식 문서 닿는 기호(PLAN 802-3 · 804-6) — 줄 쌓기 산출근거(`line_stack_out.ts`)가 씀
|
|
* reach = 지금 탄 갈래로 닿는 기호(만약 안 탄 갈래 · 숨김 자리 인자 빼고)
|
|
* 옛 수식 문서 탭의 조판 그림(renderNode · 값 식 · 수 바꿈)은 804-6 에 걷음
|
|
* ========================================================================== */
|
|
|
|
import {
|
|
linkNames,
|
|
varId,
|
|
type FormulaDoc,
|
|
type Node,
|
|
} from "../common_util/common_util_formula_doc";
|
|
import {
|
|
offLine,
|
|
takenOf,
|
|
tryParse,
|
|
type Values,
|
|
} from "../common_util/common_util_formula_doc_view";
|
|
|
|
/** 탄 갈래로 부르는 이름(만약 안 탄 갈래 · 숨김 자리 인자 빼고) */
|
|
function namesTaken(n: Node, vals: Values, out: string[] = []): string[] {
|
|
const add = (x: string): void => {
|
|
if (!out.includes(x)) out.push(x);
|
|
};
|
|
switch (n[0]) {
|
|
case "var":
|
|
add(n[1]);
|
|
break;
|
|
case "bin":
|
|
namesTaken(n[2], vals, out);
|
|
namesTaken(n[3], vals, out);
|
|
break;
|
|
case "neg":
|
|
case "pct":
|
|
case "field":
|
|
namesTaken(n[1], vals, out);
|
|
break;
|
|
case "call": {
|
|
const pick = takenOf(n, vals);
|
|
const items = pick ? [n[2][0], n[2][pick]] : n[2];
|
|
items.forEach((x) => namesTaken(x, vals, out));
|
|
break;
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
const RESERVED_MONEY = new Set(["노무비", "재료비", "경비", "번지", "단계"]);
|
|
|
|
/** 정의 영역에 보일 기호 — 식 줄 · 금액 줄 · 결과에서 지금 탄 갈래로 닿는 것(보이는 차례) */
|
|
export function reach(doc: FormulaDoc, vals: Values, showOff = false): string[] {
|
|
const vars = new Map((doc.변수 ?? []).map((v) => [varId(v), v]));
|
|
const lines = new Map((doc.식 ?? []).map((l) => [String(l.기호 ?? ""), l.식]));
|
|
const money = new Set((doc.금액 ?? []).map((l) => String(l.기호 ?? "")).filter(Boolean));
|
|
const out: string[] = [];
|
|
const visit = (name: string): void => {
|
|
if (!name || out.includes(name) || RESERVED_MONEY.has(name) || money.has(name)) return;
|
|
out.push(name);
|
|
if (lines.has(name)) {
|
|
const n = tryParse(lines.get(name));
|
|
if (n) namesTaken(n, vals).forEach(visit);
|
|
}
|
|
const v = vars.get(name);
|
|
if (v?.연결 && v.연결.갈래 !== "식") linkNames(v.연결).forEach(visit);
|
|
};
|
|
const from = (text: unknown): void => {
|
|
const n = tryParse(text);
|
|
if (n) namesTaken(n, vals).forEach(visit);
|
|
};
|
|
for (const l of doc.식 ?? []) {
|
|
visit(String(l.기호 ?? ""));
|
|
from(l.식);
|
|
}
|
|
for (const l of doc.금액 ?? []) {
|
|
if (!showOff && offLine(l, vals, lines)) continue;
|
|
from(l.수량);
|
|
from(l.단가);
|
|
}
|
|
if (doc.결과) visit(String(doc.결과));
|
|
return out;
|
|
}
|