- 종단 편집: 모듈 사본 EditState 걷음 — 지금 값 = 가게 alignmentDraft(세션) ?? 새 칸 alignmentSaved(노선별 서버 저장분 · 메모리) · ↶ ↷ = 다시 읽기만(resync · 같은 값이면 다시 셈 없음) · [저장] 뒤 ↶ 가 저장 전 서버 값으로 안 돌아감 · 노선 없는 창구는 그 안 메모리 - 페이지 설정: 가게 칸 pageSettings(세션 pagesettings) · ↶ ↷ 훅이 가게로 다시 알림 → 폼(B05) · 기울기 한도 · 시작 측점(종단도 한 벌)이 들음(N6) - 최소고 강제: 결과 통 사본 칸 profile-enforce-min-cover 지움 — 편집 가드가 페이지 설정(초안 ?? 저장 노선)을 바로 읽음(N7) - 시험: test_472_5_value_owner(옛 코드 빨강 3) · 헬퍼 271 · 442_2 가게 창구 따라감 · 최소고 가드 글 검사 줄 - 위키 design_page 값 · 조작 · 세션 열쇠 · 규칙 줄 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
120 lines
5.2 KiB
JavaScript
120 lines
5.2 KiB
JavaScript
/* 472-5 5-C 헬퍼 — 종단 편집 · 페이지 설정 값 주인 = 설계 가게 칸 하나. 진짜 `b_page_state` · `design_store` ·
|
|
* `_Profile_Edit` · `_Api_PageSettings` 를 Node 로(세션 = 메모리 · 되돌리기 = 세션 칸 되쓰기 + 훅 부름 흉내).
|
|
* node helper_472_5_value_owner.cjs (짝 = `test_472_5_value_owner.py`)
|
|
*/
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const ROOT = path.join(__dirname, "..", "..");
|
|
const ts = require(path.join(ROOT, "config", "node_modules", "typescript"));
|
|
|
|
function memoryStorage() {
|
|
const map = new Map();
|
|
return {
|
|
getItem: (k) => (map.has(k) ? map.get(k) : null),
|
|
setItem: (k, v) => map.set(k, String(v)),
|
|
removeItem: (k) => map.delete(k),
|
|
key: (i) => [...map.keys()][i] ?? null,
|
|
get length() {
|
|
return map.size;
|
|
},
|
|
};
|
|
}
|
|
globalThis.window = { sessionStorage: memoryStorage(), localStorage: memoryStorage() };
|
|
|
|
const REAL = new Set(
|
|
[
|
|
"A00_Common/b_page_state.ts",
|
|
"A00_Common/design/design_store.ts",
|
|
"B05_Profile/B05_Profile_UI_Profile_Edit.ts",
|
|
"B05_Profile/B05_Profile_Api_PageSettings.ts",
|
|
"B05_Profile/logic/B05_Profile_UI_Profile_Alignment.ts",
|
|
].map((rel) => path.join(ROOT, rel)),
|
|
);
|
|
const historyHooks = [];
|
|
const STUBS = {
|
|
B05_Profile_UI_Profile_History: { onPageHistory: (entry) => historyHooks.push(entry) },
|
|
B05_Profile_Api_Fetch: {
|
|
readRouteLatestCache: (p) => state().readState("latest", p),
|
|
writeRouteLatestCache: (p, value) => state().writeState("latest", value, p),
|
|
savePageSettings: async () => ({}),
|
|
},
|
|
};
|
|
const anything = () =>
|
|
new Proxy({}, { get: (_target, key) => (key === "__esModule" ? false : () => undefined) });
|
|
const cache = new Map();
|
|
function load(file) {
|
|
if (cache.has(file)) return cache.get(file);
|
|
const box = { exports: {} };
|
|
cache.set(file, box.exports);
|
|
const js = ts.transpileModule(fs.readFileSync(file, "utf8"), {
|
|
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
|
|
}).outputText;
|
|
const req = (request) => {
|
|
const stub = STUBS[path.basename(request)];
|
|
if (stub) return stub;
|
|
if (request === "@ui/ui_template_locale") return { ui_locales: {}, currentLanguageIndex: 0 };
|
|
if (!request.startsWith(".")) return anything();
|
|
const target = path.resolve(path.dirname(file), request);
|
|
const full = fs.existsSync(`${target}.ts`) ? `${target}.ts` : target;
|
|
return REAL.has(full) ? load(full) : anything();
|
|
};
|
|
new Function("exports", "module", "require", js)(box.exports, box, req);
|
|
return box.exports;
|
|
}
|
|
const state = () => load(path.join(ROOT, "A00_Common", "b_page_state.ts"));
|
|
|
|
const P = "P4725";
|
|
const ROUTE = 7;
|
|
const store = load(path.join(ROOT, "A00_Common", "design", "design_store.ts"));
|
|
store.pinDraftProject(P);
|
|
const edit = load(path.join(ROOT, "B05_Profile", "B05_Profile_UI_Profile_Edit.ts"));
|
|
const settings = load(path.join(ROOT, "B05_Profile", "B05_Profile_Api_PageSettings.ts"));
|
|
const out = {};
|
|
|
|
// ① 두 보기 = 창구 둘 · 같은 노선 — ↶ 가 세션 칸을 되쓰면 둘 다 그 값(모듈 사본이 옛 값을 쥐지 않음)
|
|
const saved = { station_offsets: {}, curve_radii: { "40.000": 30 } };
|
|
const a = edit.createProfileEditStore(ROUTE, saved, () => undefined);
|
|
const b = edit.createProfileEditStore(ROUTE, saved, () => undefined);
|
|
const x = { station_offsets: { "20.000": 0.5 }, curve_radii: { "40.000": 30 } };
|
|
const y = { station_offsets: { "20.000": 0.2 }, curve_radii: { "40.000": 30 } };
|
|
a.replace(x);
|
|
state().writeState("alignment-draft", y, P, ROUTE); // 되돌리기 = 세션 되쓰기
|
|
out.undo = {
|
|
a: a.edits(),
|
|
b: b.edits(),
|
|
aDirty: a.dirty(),
|
|
resync: a.resync?.() ?? "없음",
|
|
again: a.resync?.() ?? "없음",
|
|
};
|
|
// ② [저장] 뒤 ↶ 로 초안 칸이 비면 = 저장한 값(저장 전 서버 값으로 안 돌아감)
|
|
a.replace(x);
|
|
a.markSaved();
|
|
state().writeState("alignment-draft", null, P, ROUTE);
|
|
out.afterSave = { edits: b.edits(), dirty: b.dirty(), canRestore: b.canRestoreSaved() };
|
|
|
|
// ③ 페이지 설정 — ↶ 훅이 가게로 다시 알림(폼 · 기울기 한도 · 시작 측점이 들음 · N6)
|
|
const heard = [];
|
|
store.useDesignStore(P, null).subscribe("pageSettings", (value) => heard.push(value));
|
|
const draft = {
|
|
design_speed_kph: 30,
|
|
terrain_type: "normal",
|
|
max_grade_pct: 12,
|
|
min_vertical_radius_m: null,
|
|
min_tangent_length_m: null,
|
|
enforce_pipe_clearance: true,
|
|
station_display: { station: 0, cumulative: 0 },
|
|
};
|
|
settings.writePageSettings(P, draft);
|
|
state().writeState("pagesettings", null, P); // 되돌리기 = 세션 되쓰기
|
|
historyHooks.forEach((entry) => entry.restore?.("undo"));
|
|
out.settingsHeard = [...heard];
|
|
|
|
// ④ 최소고 강제 = 페이지 설정 한 칸(초안 ?? 저장 노선) · 사본 세션 칸 없음(N7)
|
|
state().writeState("latest", { project_id: P, route_params: { enforce_pipe_clearance: true } }, P);
|
|
out.enforceSaved = settings.enforceMinCoverOf?.(P) ?? "없음"; // 옛 코드 = 창구 없음
|
|
settings.writePageSettings(P, { ...draft, enforce_pipe_clearance: false });
|
|
out.enforceDraft = settings.enforceMinCoverOf?.(P) ?? "없음";
|
|
// 등록부에 없으면 열쇠가 안 섬(null) — 옛 코드는 결과 통 열쇠가 섬
|
|
out.copyKey = state().stateKey("profile-enforce-min-cover", P) ?? "none";
|
|
console.log(JSON.stringify(out));
|