- design_calc_registry.ts — 순수 자료 · 1.1 표 # 마다 id 하나(43) · 입력 · 출력 · 실행 자리 · 단계 · 실행기 · 짝 · 거울 - design_calc_node.ts — id → 함수 표(구조물 면적 · 관 길이 · 누가토량 · 유토 배분 · 터파기 · 3D) · build:design-calc - 나머지 id 실행기 = 지금 파이썬 이름 · 472-4 동안 표시 - test_472_3_calc_registry — 실행기 있음 · STAGE_DEPS 같음 · 서버 쪽 코드 브라우저 밖 · Node 입구 도달 경계(알려진 끌림 목록) · server-calc · corridor 묶음과 같은 값 - 기존 묶음 · 파이썬 · design_pipeline.ts 그대로 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
52 lines
2.0 KiB
JavaScript
52 lines
2.0 KiB
JavaScript
/* 472-3 헬퍼 — TS import 도달 집합(472-0 g472/graph.mjs 꼴 · 읽기만).
|
|
* node helper_472_3_graph.mjs <저장소 뿌리> <입구.ts> [<입구.ts> …]
|
|
* 입구마다 도달 파일(뿌리 상대 · `/`)을 JSON 한 벌로 표준출력 — 정적 import · export from · 동적
|
|
* import() · new URL(…, import.meta.url)(워커) · `import type` · `export type` 은 뺌(지워짐). */
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
|
|
const [root, ...entries] = process.argv.slice(2);
|
|
const alias = { "@ui/": "ui_template/", "@config/": "config/", "@util/": "common_util/" };
|
|
const rel = (p) => path.relative(root, p).split(path.sep).join("/");
|
|
const exists = (p) => {
|
|
for (const c of [p, `${p}.ts`, `${p}/index.ts`])
|
|
if (fs.existsSync(c) && fs.statSync(c).isFile()) return c;
|
|
return null;
|
|
};
|
|
function resolve(from, spec) {
|
|
let base;
|
|
if (spec.startsWith(".")) base = path.resolve(path.dirname(from), spec);
|
|
else {
|
|
const a = Object.keys(alias).find((k) => spec.startsWith(k));
|
|
if (!a) return null;
|
|
base = path.resolve(root, alias[a] + spec.slice(a.length));
|
|
}
|
|
return exists(base.replace(/\.js$/, ""));
|
|
}
|
|
const re =
|
|
/(?:import|export)\s+(?:type\s+)?(?:[^;"'`]*?\sfrom\s+)?["']([^"']+)["']|import\(\s*["']([^"']+)["']\s*\)|new URL\(\s*["']([^"']+)["']\s*,\s*import\.meta\.url/g;
|
|
function deps(file) {
|
|
if (!/\.(ts|mts)$/.test(file)) return [];
|
|
const src = fs.readFileSync(file, "utf8");
|
|
const out = [];
|
|
for (const m of src.matchAll(re)) {
|
|
if (/^(?:import|export)\s+type\s/.test(m[0])) continue;
|
|
const target = resolve(file, m[1] || m[2] || m[3]);
|
|
if (target) out.push(target);
|
|
}
|
|
return out;
|
|
}
|
|
const result = {};
|
|
for (const entry of entries) {
|
|
const seen = new Set();
|
|
const stack = [path.resolve(root, entry)];
|
|
while (stack.length) {
|
|
const file = stack.pop();
|
|
if (seen.has(file)) continue;
|
|
seen.add(file);
|
|
stack.push(...deps(file));
|
|
}
|
|
result[entry] = [...seen].map(rel).sort();
|
|
}
|
|
process.stdout.write(JSON.stringify(result));
|