- announceDesignStore = 관 · 구조물만(추가 측점은 _Api_PlusStations 훅이 이미 알림 · 페이지 설정은 5-C 훅) - 계산 묶음 먹이기 — 되돌리는 동안 구독은 안 받음(되살림 훅 한 길) · 묶음 입력과 같은 값 다시 알림은 안 넣음 (옛: 추가 측점 되돌리기에 묶음 두 번) - 시험 test_472_5_shop_owner 알림 수(옛 코드 실패 확인) · helper_429 가짜 묶음이 받은 값을 입력으로(까닭: 실제 묶음과 같게) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
125 lines
4.2 KiB
JavaScript
125 lines
4.2 KiB
JavaScript
/* 472-5 헬퍼 — node helper_472_5_shop.mjs <묶음.mjs> · 표준출력 JSON.
|
|
* ① 되돌리기 · 다시하기가 가게 듣는 쪽(관 · 구조물 사본)을 부르는가 ② 배수 편집기가 남이 고친 관 초안을 받는가. */
|
|
import { pathToFileURL } from "node:url";
|
|
|
|
const storage = () => {
|
|
const m = new Map();
|
|
return {
|
|
getItem: (k) => (m.has(k) ? m.get(k) : null),
|
|
setItem: (k, v) => m.set(k, String(v)),
|
|
removeItem: (k) => m.delete(k),
|
|
key: (i) => [...m.keys()][i] ?? null,
|
|
get length() {
|
|
return m.size;
|
|
},
|
|
clear: () => m.clear(),
|
|
};
|
|
};
|
|
const any = new Proxy(function () {}, {
|
|
get: (_t, k) => (k === Symbol.toPrimitive ? () => 0 : any),
|
|
apply: () => any,
|
|
construct: () => any,
|
|
});
|
|
globalThis.window = { sessionStorage: storage(), localStorage: storage() }; // 손길 듣기 없음 = 열 때 규칙 꺼짐
|
|
globalThis.sessionStorage = window.sessionStorage;
|
|
globalThis.localStorage = window.localStorage;
|
|
globalThis.document = any;
|
|
|
|
const m = await import(pathToFileURL(process.argv[2]).href);
|
|
const P = "p472five";
|
|
localStorage.setItem("frd_current_project_id", P);
|
|
m.pinDraftProject(P);
|
|
const store = m.useDesignStore(P, null);
|
|
const A = [{ structure_id: "a", type_id: "berm", placement: "point", chainage_m: 20, options: {} }];
|
|
const AB = [
|
|
...A,
|
|
{ structure_id: "b", type_id: "berm", placement: "point", chainage_m: 40, options: {} },
|
|
];
|
|
const pipes1 = [
|
|
{ id: "k1", chainage_m: 100, source: "user", facility: "pipe", options: { diameter_mm: 800 } },
|
|
];
|
|
const pipes2 = [
|
|
{ id: "k1", chainage_m: 100, source: "user", facility: "pipe", options: { diameter_mm: 1000 } },
|
|
];
|
|
store.set("structures", A);
|
|
store.set("pipes", pipes1);
|
|
m.writePlusDraft(P, [60]);
|
|
const history = m.createProfileHistory(() => undefined, 100);
|
|
store.set("structures", AB);
|
|
store.set("pipes", pipes2);
|
|
m.writePlusDraft(P, [60, 80]);
|
|
history.record();
|
|
const heard = { structures: [], pipes: [], plusStations: [] };
|
|
store.subscribe("structures", (v) => heard.structures.push(v));
|
|
store.subscribe("pipes", (v) => heard.pipes.push(v));
|
|
store.subscribe("plusStations", (v) => heard.plusStations.push(v));
|
|
// 계산 묶음 먹이기 — 되돌리기 한 번에 출처마다 한 번만(되살림 훅 한 길 · 472-5 겹침 정리)
|
|
const fed = [];
|
|
const input = { pipes: pipes2, structures: AB, plusStations: [60, 80] };
|
|
const keyOf = { pipe: "pipes", structure: "structures", plus: "plusStations" };
|
|
m.feedFacilities({
|
|
projectId: P,
|
|
store,
|
|
ready: () => true,
|
|
gone: () => false,
|
|
saved: () => null,
|
|
input: (key) => input[key],
|
|
routed: () => false,
|
|
feed: (source, value) => {
|
|
fed.push(source);
|
|
input[keyOf[source]] = value;
|
|
},
|
|
resync: async () => undefined,
|
|
});
|
|
const tick = () => new Promise((done) => setTimeout(done, 5));
|
|
history.undo();
|
|
await tick();
|
|
const afterUndo = {
|
|
structures: heard.structures.at(-1) ?? null,
|
|
pipes: heard.pipes.at(-1) ?? null,
|
|
};
|
|
const counts = {
|
|
structures: heard.structures.length,
|
|
pipes: heard.pipes.length,
|
|
plusStations: heard.plusStations.length,
|
|
fed: [...fed].sort(),
|
|
};
|
|
history.redo();
|
|
await tick();
|
|
const afterRedo = {
|
|
structures: heard.structures.at(-1) ?? null,
|
|
pipes: heard.pipes.at(-1) ?? null,
|
|
};
|
|
|
|
// ② 배수 편집기 — 같은 몸통 = 메아리(안 받음) · 옵션만 바뀜 = 받음 · 고른 관 유지
|
|
const editor = m.createPipeEditor(() => undefined);
|
|
const facilities = m.createFacilityStore();
|
|
editor.setPipes([
|
|
{ chainage_m: 100, reason: "user", id: "k1" },
|
|
{ chainage_m: 140, reason: "user", id: "k2" },
|
|
]);
|
|
facilities.replaceFromResponse(pipes1);
|
|
editor.select(0);
|
|
const body = () =>
|
|
facilities.attach(
|
|
editor.pipes().map((p) => ({ chainage_m: p.chainage_m, source: p.reason, id: p.id })),
|
|
);
|
|
const echo = m.adoptEditorPipes(editor, facilities, body(), body());
|
|
const next = [
|
|
{ id: "k2", chainage_m: 140, source: "user", facility: "pipe" },
|
|
{ id: "k1", chainage_m: 100, source: "user", facility: "pipe", options: { diameter_mm: 1200 } },
|
|
];
|
|
const adopted = m.adoptEditorPipes(editor, facilities, body(), next);
|
|
const picked = editor.pipes()[editor.selected() ?? -1]?.id ?? null;
|
|
console.log(
|
|
JSON.stringify({
|
|
afterUndo,
|
|
afterRedo,
|
|
counts,
|
|
echo,
|
|
adopted,
|
|
picked,
|
|
options: facilities.get(100)?.options ?? null,
|
|
}),
|
|
);
|