- 꼴: 변수표(기호 · 첨자 · 이름 · 단위 · 연결 = 숫자 · 선택 · 입력 · 요소 · 표 · 단가산출 · 식) + 식 줄 + 금액 줄 + 끝수 칸 — resources/master_data/_수식문서_틀.md - 풀이 · 글로 되돌림 · 기호 · 이름 바꿈 전파 · 정적 검사 = master_doc.py ↔ common_util_formula_doc.ts - 셈 = master_doc_calc.py ↔ common_util_formula_doc_calc.ts — 기호는 필요할 때 셈 · 정의 필요 · 순환 · 0 나눔 · 식 틀림 · 빈 문서 = 표지 + 금액 없음 · 값 없음 = 그 줄만 비움 · 묶음 소계 · 합계 · 줄 자리 · 끝전 큰나머지 · 계 끝수 · 조정 · 번지 · 단계 · 합밖 - M01 연결 풀이(표 찾기 · 요소 · 단가산출 문서) = master_doc_link.py ↔ common_util_formula_doc_table.ts(표 찾기) · 옛 엔진 셈 안 부름 - 옛 로직 변환 = master_doc_convert.py(802-2 빌더가 부름) - 시험 test_802_1_formula_doc 48(꼴 · 셈 · 지움 견딤 300 넘는 지운 문서 예외 0 · 표지 · 거울 파이썬 ↔ TS 60 문서) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
74 lines
2.9 KiB
JavaScript
74 lines
2.9 KiB
JavaScript
/* 802-1 수식 문서 거울 헬퍼 — common_util_formula_doc*.ts 를 그 자리에서 트랜스파일해 Node 로 돌림.
|
|
* stdin = {문서들: {키: 문서}, 대상: [키], 기록: {열쇠: {값 | 빈 | 끊김}}, 글: [식 글], 표: [{표, 조건, 칸}]}
|
|
* stdout = {답: {키: calcDoc 답}, 글: [textOf 또는 {틀림}], 표: [tableValue 값 또는 {빈 | 끊김}]}
|
|
* 기록 열쇠 = 갈래 + "|" + 값 글(파이썬 `_canon` 과 같은 꼴). */
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
|
|
|
const cache = new Map();
|
|
function load(at) {
|
|
if (cache.has(at)) return cache.get(at);
|
|
const js = ts.transpileModule(fs.readFileSync(at, "utf8"), {
|
|
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
|
|
}).outputText;
|
|
const box = { exports: {} };
|
|
cache.set(at, box.exports);
|
|
const need = (p) =>
|
|
p.startsWith(".") ? load(path.resolve(path.dirname(at), `${p}.ts`)) : require(p);
|
|
new Function("exports", "module", "require", js)(box.exports, box, need);
|
|
return box.exports;
|
|
}
|
|
const root = path.join(__dirname, "..", "..", "common_util");
|
|
const doc = load(path.join(root, "common_util_formula_doc.ts"));
|
|
const calc = load(path.join(root, "common_util_formula_doc_calc.ts"));
|
|
const table = load(path.join(root, "common_util_formula_doc_table.ts"));
|
|
|
|
function canon(v) {
|
|
if (typeof v === "number") return calc.plainText(v);
|
|
if (Array.isArray(v)) return v.map(canon);
|
|
if (v && typeof v === "object") {
|
|
const out = {};
|
|
for (const k of Object.keys(v).sort()) out[k] = canon(v[k]);
|
|
return out;
|
|
}
|
|
return v;
|
|
}
|
|
const keyOf = (kind, p) => `${kind}|${JSON.stringify(canon(p))}`;
|
|
|
|
const input = JSON.parse(fs.readFileSync(0, "utf8"));
|
|
const record = input.기록 || {};
|
|
function answer(kind, p) {
|
|
const k = keyOf(kind, p);
|
|
if (!(k in record)) throw new calc.Broken(`기록 없음 ${k}`);
|
|
const got = record[k];
|
|
if ("빈" in got) throw new calc.Gap(got.빈);
|
|
if ("끊김" in got) throw new calc.Broken(got.끊김);
|
|
return got.값;
|
|
}
|
|
const links = {
|
|
element: (p) => answer("요소", p),
|
|
table: (p) => answer("표", p),
|
|
doc: (key) => (input.문서들 || {})[key] || null,
|
|
};
|
|
const out = { 답: {}, 글: [], 표: [] };
|
|
for (const key of input.대상 || []) out.답[key] = calc.calcDoc(input.문서들[key], links);
|
|
for (const text of input.글 || []) {
|
|
try {
|
|
out.글.push(doc.textOf(doc.parse(text)));
|
|
} catch (e) {
|
|
if (!(e instanceof doc.DocError)) throw e;
|
|
out.글.push({ 틀림: true });
|
|
}
|
|
}
|
|
for (const one of input.표 || []) {
|
|
try {
|
|
out.표.push({ 값: table.tableValue(one.표, { 조건: one.조건, 칸: one.칸 }) });
|
|
} catch (e) {
|
|
if (e instanceof calc.Gap) out.표.push({ 빈: true });
|
|
else if (e instanceof calc.Broken) out.표.push({ 끊김: true });
|
|
else throw e;
|
|
}
|
|
}
|
|
process.stdout.write(JSON.stringify(out));
|