/* ============================================================================= * A00_Common/design/logic/design_calc_node_trial.ts * 계산 자리 「서버」 시험 길(PLAN 511-A) — 조작 중 브라우저가 부르는 함수를 서버 Node 가 **같은 TS 로** 부름. * 등록부 `node:` 실행기 밖(파이썬 `TRIAL_IDS` 와 같은 표) · 입력 = `inputs.args[id]`(그 함수 인자 그대로 · JSON). * masshaul.series E1 유토곡선 그리기(`computeMassHaulSeries`) * stations.carry_keyed R9 측점 열쇠 넘김(`carryKeyedStates` · 읽기 = 칸 이름 → 값 표) * route.handle R2 · route.station_fit R4 · stations.swap R8 · profile.tools P7 · cross.fit C7 · footprint.plan D4 * Map · Set 은 목록으로(JSON) — 브라우저 대조도 같은 꼴(`design_calc_server.ts` `plain`). * ========================================================================== */ import { computeMassHaulSeries } from "@util/common_util_mass_haul"; import { footprintStage } from "../../../B05_Profile/logic/B05_Profile_Footprint_Stage"; import { fitAfter } from "../../../B05_Profile/logic/B05_Profile_RouteEdit_StationFit"; import { straightenBetween } from "../../../B05_Profile/logic/B05_Profile_UI_Profile_Straighten"; import { dragHandleTo } from "../../../B05_Profile/logic/B05_Profile_UI_RouteEdit_Curve"; import { carryKeyedStates, type KeyedState, type Raw, } from "../../../B06_Section/logic/B06_Section_Route_Carry"; import { swapCrossSections } from "../../../B06_Section/logic/B06_Section_Station_Swap"; import { toeOffsets } from "../../../B06_Section/logic/B06_Section_UI_Cross_Fit"; import type { StageContext } from "./design_pipeline_types"; export interface TrialInputs { args?: Record; } type Call = (...args: never[]) => unknown; /** Map · Set → 목록 — JSON 으로 오가는 꼴. */ export function plain(value: unknown): unknown { return JSON.parse( JSON.stringify(value, (_key, item: unknown) => item instanceof Map ? [...item.entries()] : item instanceof Set ? [...item] : item, ), ); } const TRIAL: Record = { "masshaul.series": computeMassHaulSeries as Call, "stations.carry_keyed": ((states: Record, from, to) => carryKeyedStates((name: KeyedState) => states[name] ?? {}, from, to)) as Call, "route.handle": dragHandleTo as Call, "route.station_fit": fitAfter as Call, // 편집 한 걸음 뒤 맞춤(fitCurveStations 를 부름) "stations.swap": swapCrossSections as Call, "profile.tools": straightenBetween as Call, "cross.fit": toeOffsets as Call, // 발자국 단계 — 앞 결과 없이 전 구간(브라우저 범위 밖 재사용과 같은 값) "footprint.plan": ((out: StageContext<"footprint">["out"]) => footprintStage({ out, range: null, prev: null } as StageContext<"footprint">)) as Call, }; export const TRIAL_IDS = Object.keys(TRIAL); /** id → 셈(입구 `RUNNERS` 에 얹음 · `available` 에는 안 넣음). */ export function trialRunners(inputs: TrialInputs): Record unknown> { return Object.fromEntries( TRIAL_IDS.map((id) => [id, () => plain(TRIAL[id](...((inputs.args?.[id] ?? []) as never[])))]), ); }