- 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>
69 lines
2.4 KiB
Python
69 lines
2.4 KiB
Python
"""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
|