refactor(B07): 횡단 덧그림 서버 묶음이 B06 화면 허브를 끄지 않게 함 (PLAN 574-1 · 요구 418)
- Overlay 가 설계선 · 포장 그리기를 허브(_UI_Cross_Design) 대신 _Design_Line · _Design_Surface 에서 직접 가져옴 - 허브가 상세 창 · CAD · API · 부품 상자를 끌던 사슬 걷힘 — 묶음 482 → 240 KB - 구조물 그림 여섯은 이미 logic 기하만 씀 · SVG 그리기는 B07 이 SVG → CAD 로 옮기므로 그대로 둠 · 가짜 DOM 계속 필요 - 지킴 시험 test_574 — 묶음 입구에서 닿는 TS 에 화면 코드 없음 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -19,10 +19,9 @@ import { appendFordOverlay } from "../B06_Section/B06_Section_UI_Cross_Ford";
|
||||
import { appendFordPavementOverlay } from "../B06_Section/B06_Section_UI_Cross_Ford_Pavement";
|
||||
import { appendUnderdrainOverlay } from "../B06_Section/B06_Section_UI_Cross_Underdrain";
|
||||
import { groundLine } from "../B06_Section/logic/B06_Section_Cross_Wall_Hatch_Geom";
|
||||
import {
|
||||
appendCrossDesignOverlay,
|
||||
appendPavementOverlay,
|
||||
} from "../B06_Section/B06_Section_UI_Cross_Design";
|
||||
// 허브(`_UI_Cross_Design`)가 아닌 그리기 파일에서 직접 — 허브는 상세 창 · CAD · API 를 끈다(574-1)
|
||||
import { appendCrossDesignOverlay } from "../B06_Section/B06_Section_UI_Cross_Design_Line";
|
||||
import { appendPavementOverlay } from "../B06_Section/B06_Section_UI_Cross_Design_Surface";
|
||||
import { appendRevetmentOverlay } from "../B06_Section/B06_Section_UI_Cross_Revetment";
|
||||
import { clipPointsToPolygon, clipSegment, pointInPolygon } from "../A00_Common/b_polygon_clip";
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
"""B07 횡단 덧그림 서버 묶음(`b07-extent`)이 화면 코드를 끌지 않음 (574-1).
|
||||
|
||||
묶음 입구에서 값 import 를 따라가 닿는 TS 파일에 확인 창 · CAD · 상세 창 · API ·
|
||||
부품 상자 · B06 허브(`_UI_Cross_Design`)가 없어야 함. `import type` 은 지워지므로 뺌.
|
||||
"""
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
ENTRY = ROOT / "B07_DesignDetail" / "B07_DesignDetail_Cross_Extent_Node.ts"
|
||||
ALIAS = {"@util/": ROOT / "common_util", "@ui/": ROOT / "ui_template"}
|
||||
_IMPORT = re.compile(
|
||||
r"^\s*(?:import|export)\s+(type\s+)?(?:([^;]*?)\s+from\s+)?[\"']([^\"']+)[\"']",
|
||||
re.M | re.S,
|
||||
)
|
||||
FORBIDDEN = re.compile(
|
||||
r"ui_template|_Cad|Cross_Detail|_Api_|B06_Section_UI_Cross_Design\.ts$|three"
|
||||
)
|
||||
|
||||
|
||||
def _type_only(names: str | None) -> bool:
|
||||
inner = (names or "").strip()
|
||||
if not inner.startswith("{"):
|
||||
return False
|
||||
parts = [p.strip() for p in inner.strip("{} \n").split(",") if p.strip()]
|
||||
return bool(parts) and all(p.startswith("type ") for p in parts)
|
||||
|
||||
|
||||
def _resolve(origin: Path, spec: str) -> Path | None:
|
||||
for prefix, base in ALIAS.items():
|
||||
if spec.startswith(prefix):
|
||||
target = base / spec[len(prefix) :]
|
||||
break
|
||||
else:
|
||||
if not spec.startswith("."):
|
||||
return None # node:fs · 라이브러리
|
||||
target = origin.parent / spec
|
||||
for suffix in (".ts", ""):
|
||||
path = Path(str(target) + suffix).resolve()
|
||||
if path.is_file():
|
||||
return path
|
||||
return None
|
||||
|
||||
|
||||
def _reachable() -> set[Path]:
|
||||
seen, queue = {ENTRY.resolve()}, [ENTRY.resolve()]
|
||||
while queue:
|
||||
current = queue.pop()
|
||||
if current.suffix != ".ts":
|
||||
continue
|
||||
for match in _IMPORT.finditer(current.read_text(encoding="utf-8")):
|
||||
type_kw, names, spec = match.groups()
|
||||
if type_kw or _type_only(names):
|
||||
continue
|
||||
found = _resolve(current, spec)
|
||||
if found and found not in seen:
|
||||
seen.add(found)
|
||||
queue.append(found)
|
||||
return seen
|
||||
|
||||
|
||||
def test_extent_bundle_pulls_no_screen_code():
|
||||
reached = _reachable()
|
||||
names = {p.relative_to(ROOT).as_posix() for p in reached}
|
||||
assert "B07_DesignDetail/B07_DesignDetail_Cross_Overlay.ts" in names # 걷기가 실제로 돎
|
||||
bad = sorted(n for n in names if FORBIDDEN.search(n))
|
||||
assert not bad, bad
|
||||
Reference in New Issue
Block a user