feat(m02-df): 표준 표 판 · standardsList — 두 표 보기 · 칸 고치기 · 저장 · 처음 값으로
- M02_DF_Standards.ts — renderStandards(host, on) · standardsList()(단위 고르기 · 끝수 제안 · 동기) · loadStandards · 서버 GET/PUT/DELETE /api/m02/df/standards - 시험 test_m02_df_standards.py 에 standardsList 목록(단위 반올림 · 금액 지위 → 자리 · 버림) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BU9gbNE3aWFUvE61pS2WGt
This commit is contained in:
@@ -78,3 +78,68 @@ def test_금액_다섯_줄() -> None:
|
||||
]
|
||||
assert all(r["단위"] == "원" and r["비고"] == "미만버림" for r in rows)
|
||||
assert all(_cells(r["원문 줄"])[0] == r["종목"] for r in rows)
|
||||
|
||||
|
||||
# ── standardsList(단위 고르기 · 끝수 제안이 씀) — Node 로 `M02_DF_Standards.ts` 를 바로 돌림 ──────────
|
||||
HOOKS = r"""
|
||||
import { readFileSync } from "node:fs";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { stripTypeScriptTypes } from "node:module";
|
||||
export async function load(url, ctx, next) {
|
||||
if (!url.endsWith(".ts")) return next(url, ctx);
|
||||
let src = readFileSync(fileURLToPath(url), "utf8");
|
||||
src = src.replace(/import\s+"[^"]+\.css";/g, "");
|
||||
src = src.replace(/import\s+(\w+)\s+from\s+"\.\/_standard\/([^"]+)\.json";/g, "const $1 = globalThis.__std[\"$2\"];");
|
||||
src = src.replace(/import\s*\{([^}]*)\}\s*from\s*"([^"]+)";/g, (m, names) => {
|
||||
const list = names.split(",").map((x) => x.trim()).filter((x) => x && !x.startsWith("type "));
|
||||
return list.length ? `const { ${list.join(", ")} } = globalThis.__stub;` : "";
|
||||
});
|
||||
return { format: "module", source: stripTypeScriptTypes(src, { mode: "transform" }), shortCircuit: true };
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def _node(body: str) -> object:
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
assert shutil.which("node")
|
||||
script = (
|
||||
"import { register } from 'node:module';\n"
|
||||
f"register('data:text/javascript,' + encodeURIComponent({json.dumps(HOOKS)}));\n"
|
||||
"globalThis.__stub = new Proxy({}, { get: (_, k) => k === 'currentLanguageIndex' ? 0 : k === 'API_BASE_URL' ? '/api' : () => undefined });\n" # noqa: E501
|
||||
f"globalThis.__std = {json.dumps({'단위표준': UNIT, '금액단위표준': MONEY}, ensure_ascii=False)};\n"
|
||||
f"const S = await import({json.dumps((STD.parent / 'M02_DF_Standards.ts').as_uri())});\n"
|
||||
"const out = (x) => process.stdout.write(JSON.stringify(x));\n" + body
|
||||
)
|
||||
result = subprocess.run(
|
||||
["node", "--no-warnings", "--input-type=module", "-e", script],
|
||||
capture_output=True, text=True, encoding="utf-8", timeout=60, cwd=ROOT,
|
||||
) # fmt: skip
|
||||
assert result.returncode == 0, result.stderr[-2000:]
|
||||
return json.loads(result.stdout)
|
||||
|
||||
|
||||
def test_standardsList_목록() -> None:
|
||||
got = _node("out(S.standardsList());")
|
||||
units = [
|
||||
(r["종목"], g, u, p)
|
||||
for r in UNIT["줄"]
|
||||
for g, u, p in [
|
||||
("규격", r["규격 단위"], r["규격 소수자리"]),
|
||||
("단위수량", r["단위수량 단위"], r["단위수량 소수자리"]),
|
||||
]
|
||||
if u and u != "없음"
|
||||
]
|
||||
assert [
|
||||
(x["종목"], x["갈래"], x["단위"], x["소수자리"]) for x in got if x["갈래"] != "금액"
|
||||
] == [(n, g, u, p or 0) for n, g, u, p in units]
|
||||
assert all(x["방법"] == "반올림" for x in got if x["갈래"] != "금액")
|
||||
money = [x for x in got if x["갈래"] == "금액"]
|
||||
assert [(x["지위"], x["소수자리"], x["방법"]) for x in money] == [
|
||||
(1000, -3, "버림"),
|
||||
(1, 0, "버림"),
|
||||
(1, 0, "버림"),
|
||||
(1, 0, "버림"),
|
||||
(0.1, 1, "버림"),
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user