test(508-1d 빨강 가림 2/2): 모양 다른 헬퍼 일곱 공용 불러오기로 · 공용 불러오기 옵션 둘(target · rewrite)

- 공용 불러오기: target(트랜스파일 대상) · rewrite(트랜스파일 글 손봄 · import.meta) 옵션
- 280_2(import.meta.env.DEV) · 345_4(import.meta.url) = rewrite · 298_3 = target ES2022
- 322_0 = fileStub(경로 가짜 맵 · .css) · 347 = 파일별 진짜 import 목록 · 427_1 · 459 = load(뿌리 기준)
- 풀이 함수 본문 그대로 · 헬퍼 출력 전 · 후 같음

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-21 18:01:55 +09:00
co-authored by Claude Opus 5.5
parent 0dc6769d6b
commit 38e6b65f37
8 changed files with 73 additions and 132 deletions
+8 -13
View File
@@ -2,9 +2,8 @@
* 트랜스파일해 가짜 DOM 위에서 ① 주소마다 줄 차례 ② [<] [>] = 이웃 단계 단추 누름(꺼진 단계 = 알림만)을
* 돌려 JSON 한 벌로 냄. 확장자 `.cjs` 까닭은 `helper_design_view_parity.cjs` 머리와 같음.
*/
const fs = require("fs");
const path = require("path");
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
const { makeLoader } = require("./helper_ts_stub_loader.cjs");
const ROOT = path.join(__dirname, "..", "..");
@@ -148,20 +147,16 @@ const STUBS = {
};
globalThis.__DEV = false;
function loadTs(file) {
const src = fs.readFileSync(file, "utf8").replace(/import\.meta\.env\.DEV/g, "globalThis.__DEV");
const js = ts.transpileModule(src, {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
}).outputText;
const box = { exports: {} };
const localRequire = (request) => {
const { loadTs } = makeLoader({
root: ROOT,
cache: false,
rewrite: (js) => js.replace(/import\.meta\.env\.DEV/g, "globalThis.__DEV"),
requireFor: () => (request) => {
if (request.endsWith(".css")) return {};
if (STUBS[request]) return STUBS[request];
throw new Error(`대역 없음: ${request}`);
};
new Function("exports", "module", "require", js)(box.exports, box, localRequire);
return box.exports;
}
},
});
help = loadTs(path.join(ROOT, "ui_template", "ui_template_help.ts"));
const layout = loadTs(path.join(ROOT, "ui_template", "ui_template_workflow_layout.ts"));
+9 -25
View File
@@ -2,22 +2,13 @@
* `design_leave` 를 그 자리에서 트랜스파일 · 페이지를 다섯 번 다시 세운 뒤 창 듣개 수 · 옛 노드 풀림.
* `node --expose-gc` 로 부름 · 결과 JSON 을 stdout 으로.
*/
const fs = require("fs");
const path = require("path");
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
const { makeLoader, memoryStorage } = require("./helper_ts_stub_loader.cjs");
const ROOT = path.join(__dirname, "..", "..");
const session = new Map();
const storage = {
getItem: (key) => (session.has(key) ? session.get(key) : null),
setItem: (key, value) => session.set(key, String(value)),
removeItem: (key) => session.delete(key),
key: (index) => [...session.keys()][index] ?? null,
get length() {
return session.size;
},
};
const storage = memoryStorage();
const win = new EventTarget();
const doc = new EventTarget();
const counts = { window: 0, document: 0 };
@@ -54,24 +45,17 @@ const STUBS = {
"../router": { currentRoute: () => "/b05-profile", setLeaveGuard: (fn) => (guard = fn) },
};
const loaded = new Map();
function loadTs(file) {
if (loaded.has(file)) return loaded.get(file);
const js = ts.transpileModule(fs.readFileSync(file, "utf8"), {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022 },
}).outputText;
const box = { exports: {} };
loaded.set(file, box.exports);
const localRequire = (request) => {
const { loadTs } = makeLoader({
root: ROOT,
target: ts.ScriptTarget.ES2022,
requireFor: (full) => (request) => {
if (request in STUBS) return STUBS[request];
if (request.startsWith("@ui/"))
return loadTs(path.join(ROOT, "ui_template", `${request.slice(4)}.ts`));
if (request.startsWith(".")) return loadTs(path.join(path.dirname(file), `${request}.ts`));
if (request.startsWith(".")) return loadTs(path.join(path.dirname(full), `${request}.ts`));
return require(request);
};
new Function("exports", "module", "require", js)(box.exports, box, localRequire);
return box.exports;
}
},
});
const drag = loadTs(path.join(ROOT, "ui_template", "ui_template_overlay_drag.ts"));
const leave = loadTs(path.join(ROOT, "A00_Common", "design", "design_leave.ts"));
+8 -26
View File
@@ -7,7 +7,7 @@
const fs = require("fs");
const path = require("path");
const ROOT = path.join(__dirname, "..", "..");
const ts = require(path.join(ROOT, "config", "node_modules", "typescript"));
const { makeLoader } = require("./helper_ts_stub_loader.cjs");
const input = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
const clone = (v) => JSON.parse(JSON.stringify(v));
@@ -137,27 +137,11 @@ const resolveFile = (base) =>
[base, `${base}.ts`, base.replace(/\.js$/, ".ts"), path.join(base, "index.ts")].find(
(p) => fs.existsSync(p) && fs.statSync(p).isFile(),
) ?? `${base}.ts`;
const cache = new Map();
function loadTs(target) {
const full = path.resolve(target);
if (STUBS.has(full)) return STUBS.get(full);
if (cache.has(full)) return cache.get(full);
if (full.endsWith(".css")) return {}; // 화면 꼴(vite 몫)
if (full.endsWith(".json")) {
const data = JSON.parse(fs.readFileSync(full, "utf8"));
cache.set(full, data);
return data;
}
const js = ts.transpileModule(fs.readFileSync(full, "utf8"), {
compilerOptions: {
module: ts.ModuleKind.CommonJS,
target: ts.ScriptTarget.ES2020,
esModuleInterop: true,
},
}).outputText;
const box = { exports: {} };
cache.set(full, box.exports);
const need = (spec) => {
const { loadTs } = makeLoader({
root: ROOT,
interop: true,
fileStub: (full) => STUBS.get(full) ?? (full.endsWith(".css") ? {} : undefined), // .css = 화면 꼴(vite 몫)
requireFor: (full) => (spec) => {
if (spec === "three") return require(path.join(ROOT, "config", "node_modules", "three"));
const alias = { "@util/": "common_util", "@ui/": "ui_template", "@config/": "config" };
for (const [prefix, dir] of Object.entries(alias))
@@ -165,10 +149,8 @@ function loadTs(target) {
return loadTs(resolveFile(path.join(ROOT, dir, spec.slice(prefix.length))));
if (spec.startsWith(".")) return loadTs(resolveFile(path.join(path.dirname(full), spec)));
return require(spec);
};
new Function("exports", "module", "require", js)(box.exports, box, need);
return box.exports;
}
},
});
/* ── 견본 횡단 ───────────────────────────────────────────────────────────── */
const plainAt = (at) => ({ ...clone(input.plain_section), chainage_m: at, kind: "regular" });
@@ -5,20 +5,12 @@
const fs = require("fs");
const path = require("path");
const ROOT = path.join(__dirname, "..", "..");
const ts = require(path.join(ROOT, "config", "node_modules", "typescript"));
const { makeLoader } = require("./helper_ts_stub_loader.cjs");
const cache = new Map();
function loadTs(file) {
const full = path.resolve(file);
if (cache.has(full)) return cache.get(full);
const js = ts
.transpileModule(fs.readFileSync(full, "utf8"), {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
})
.outputText.replace(/import\.meta\.url/g, '"file:///x.js"');
const box = { exports: {} };
cache.set(full, box.exports);
const localRequire = (request) => {
const { loadTs } = makeLoader({
root: ROOT,
rewrite: (js) => js.replace(/import\.meta\.url/g, '"file:///x.js"'),
requireFor: (full) => (request) => {
if (request.startsWith("@ui/") || request.startsWith("@config/"))
return new Proxy({}, { get: () => () => undefined });
const target = request.startsWith("@util/")
@@ -26,10 +18,8 @@ function loadTs(file) {
: path.join(path.dirname(full), request);
if (request.endsWith(".json")) return JSON.parse(fs.readFileSync(target, "utf8"));
return loadTs(fs.existsSync(`${target}.ts`) ? `${target}.ts` : path.join(target, "index.ts"));
};
new Function("exports", "module", "require", js)(box.exports, box, localRequire);
return box.exports;
}
},
});
const B05 = (name) => path.join(ROOT, "B05_Profile", `${name}.ts`);
const { buildCorridor } = loadTs(B05("B05_Profile_UI_Corridor_Build"));
@@ -1,30 +1,25 @@
/* 347 덧 관 고정 id — `reconcilePipes`(되돌리기 · 구조물 폼으로 관 목록이 바뀔 때)가 id 를 따라 옮기는지.
* `B05_Profile_UI_Drainage_Parts.ts` 를 그 자리에서 트랜스파일 · 그 밖 import 는 빈 껍데기(틀 = helper_281_1).
*/
const fs = require("fs");
const path = require("path");
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
const { makeLoader } = require("./helper_ts_stub_loader.cjs");
const ROOT = path.join(__dirname, "..", "..");
const stub = new Proxy(function () {}, { get: () => stub, apply: () => stub });
function loadTs(file, real) {
const js = ts.transpileModule(fs.readFileSync(file, "utf8"), {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
}).outputText;
const box = { exports: {} };
const localRequire = (request) =>
real.some((name) => request.endsWith(name))
? loadTs(path.join(path.dirname(file), `${request}.ts`), ["common_util_pipe_match"]) // 472-6
: stub;
new Function("exports", "module", "require", js)(box.exports, box, localRequire);
return box.exports;
}
const TOP = path.join(ROOT, "B05_Profile", "B05_Profile_UI_Drainage_Parts.ts");
// 진짜로 부를 import — 맨 위 = 고름 · 그 밑 = 관 짝 맞춤(472-6) · 그 밖 = 빈 껍데기
const realOf = (full) => (full === TOP ? ["design_selection"] : ["common_util_pipe_match"]);
const { loadTs } = makeLoader({
root: ROOT,
cache: false,
requireFor: (full) => (request) =>
realOf(full).some((name) => request.endsWith(name))
? loadTs(path.join(path.dirname(full), `${request}.ts`))
: stub,
});
const { adoptDraftPipes, reconcilePipes } = loadTs(
path.join(ROOT, "B05_Profile", "B05_Profile_UI_Drainage_Parts.ts"),
["design_selection"],
);
const { adoptDraftPipes, reconcilePipes } = loadTs(TOP);
const before = [
{ chainage_m: 100, reason: "stream", id: "a1" },
{ chainage_m: 200, reason: "user", id: "b2" },
+10 -13
View File
@@ -4,24 +4,21 @@
*/
const fs = require("fs");
const path = require("path");
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
const { makeLoader } = require("./helper_ts_stub_loader.cjs");
const CATALOG = require("./helper_322_catalog_module.cjs");
const ROOT = path.join(__dirname, "..", "..");
function loadTs(file) {
const js = ts.transpileModule(fs.readFileSync(path.join(ROOT, file), "utf8"), {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
}).outputText;
const box = { exports: {} };
const localRequire = (request) => {
const { loadTs: loadFull, load } = makeLoader({
root: ROOT,
cache: false,
requireFor: (full) => (request) => {
if (CATALOG.isCatalogRequest(request)) return CATALOG;
if (request.startsWith(".")) return loadTs(path.join(path.dirname(file), `${request}.ts`));
throw new Error(`stub 없음: ${request} (${file})`);
};
new Function("exports", "module", "require", js)(box.exports, box, localRequire);
return box.exports;
}
if (request.startsWith(".")) return loadFull(path.join(path.dirname(full), `${request}.ts`));
throw new Error(`stub 없음: ${request} (${path.relative(ROOT, full)})`);
},
});
const loadTs = (file) => load(file); // 뿌리 기준 상대 경로
const cases = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
const station = loadTs("common_util/common_util_structure_station.ts");
+9 -17
View File
@@ -4,30 +4,22 @@
*/
const fs = require("fs");
const path = require("path");
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
const { makeLoader } = require("./helper_ts_stub_loader.cjs");
const CATALOG = require("./helper_322_catalog_module.cjs");
const ROOT = path.join(__dirname, "..", "..");
const cache = new Map();
function loadTs(file) {
const full = path.join(ROOT, file);
if (cache.has(full)) return cache.get(full);
const js = ts.transpileModule(fs.readFileSync(full, "utf8"), {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
}).outputText;
const box = { exports: {} };
cache.set(full, box.exports);
const localRequire = (request) => {
const { loadTs: loadFull, load } = makeLoader({
root: ROOT,
requireFor: (full) => (request) => {
if (CATALOG.isCatalogRequest(request)) return CATALOG;
if (request.endsWith(".json"))
return JSON.parse(fs.readFileSync(path.join(path.dirname(full), request), "utf8"));
if (request.startsWith(".")) return loadTs(path.join(path.dirname(file), `${request}.ts`));
throw new Error(`stub 없음: ${request} (${file})`);
};
new Function("exports", "module", "require", js)(box.exports, box, localRequire);
return box.exports;
}
if (request.startsWith(".")) return loadFull(path.join(path.dirname(full), `${request}.ts`));
throw new Error(`stub 없음: ${request} (${path.relative(ROOT, full)})`);
},
});
const loadTs = (file) => load(file); // 뿌리 기준 상대 경로
const grade = loadTs("B05_Profile/logic/B05_Profile_Pipeline_Grade.ts");
const carry = loadTs("B05_Profile/logic/B05_Profile_Grade_Carry.ts");
+9 -3
View File
@@ -32,7 +32,9 @@ function memoryStorage() {
* requireFor(full, file) 풀이 함수를 헬퍼가 직접 지음(기본 풀이 대신) · 인자 없으면 진짜 require
* interop esModuleInterop 로 트랜스파일
* cache:false 같은 파일을 부를 때마다 새로 읽음(기본은 한 번만)
* fileStub(full) 파일 경로로 통째 대신할 값(없으면 undefined) */
* fileStub(full) 파일 경로로 통째 대신할 값(없으면 undefined)
* target 트랜스파일 대상(기본 ES2020)
* rewrite(js) 트랜스파일한 글 손봄(`import.meta` 처럼 CommonJS 가 못 읽는 것) */
function makeLoader({
root,
stubs = {},
@@ -41,6 +43,8 @@ function makeLoader({
interop = false,
cache: useCache = true,
fileStub,
target = ts.ScriptTarget.ES2020,
rewrite = (js) => js,
}) {
const cache = new Map();
function defaultRequire(full) {
@@ -68,9 +72,11 @@ function makeLoader({
if (useCache) cache.set(full, data);
return data;
}
const compilerOptions = { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 };
const compilerOptions = { module: ts.ModuleKind.CommonJS, target };
if (interop) compilerOptions.esModuleInterop = true;
const js = ts.transpileModule(fs.readFileSync(full, "utf8"), { compilerOptions }).outputText;
const js = rewrite(
ts.transpileModule(fs.readFileSync(full, "utf8"), { compilerOptions }).outputText,
);
const box = { exports: {} };
if (useCache) cache.set(full, box.exports);
const localRequire = requireFor ? requireFor(full, file) : defaultRequire(full);