diff --git a/src/lib/format.ts b/src/lib/format.ts index 4e82c6f..a10eee1 100644 --- a/src/lib/format.ts +++ b/src/lib/format.ts @@ -2,14 +2,20 @@ export function pad2(n: number): string { return n.toString().padStart(2, "0"); } +// 年(数値)・月・日(各2桁ゼロ埋め文字列)を取り出す。日付スタンプ生成の共通部分。 +function dateParts(now: Date): { year: number; month: string; day: string } { + return { year: now.getFullYear(), month: pad2(now.getMonth() + 1), day: pad2(now.getDate()) }; +} + export function todayStamp(): string { - const now = new Date(); - return `${now.getFullYear()}-${pad2(now.getMonth() + 1)}-${pad2(now.getDate())}`; + const { year, month, day } = dateParts(new Date()); + return `${year}-${month}-${day}`; } export function fileStamp(): string { const now = new Date(); - return `${now.getFullYear()}${pad2(now.getMonth() + 1)}${pad2(now.getDate())}-${pad2(now.getHours())}${pad2(now.getMinutes())}`; + const { year, month, day } = dateParts(now); + return `${year}${month}${day}-${pad2(now.getHours())}${pad2(now.getMinutes())}`; } export function randomOf(arr: readonly T[]): T | undefined { diff --git a/src/lib/model.ts b/src/lib/model.ts index 1f4fce9..f18a35c 100644 --- a/src/lib/model.ts +++ b/src/lib/model.ts @@ -194,13 +194,18 @@ function hexColor(v: unknown, fallback: string): string { return typeof v === "string" && HEX_COLOR.test(v) ? v : fallback; } +// 既存の id を採用し、無ければ新規発番する(正規化対象すべてで共通の id 決定ロジック)。 +function idOf(r: Record): string { + return str(r.id) || newId(); +} + function normalizeStep(raw: unknown): Step { const r = rec(raw); if (r.type === "if") { const branches = rec(r.branches); const labels = rec(r.labels); return { - id: str(r.id) || newId(), + id: idOf(r), type: "if", text: str(r.text), done: bool(r.done), @@ -213,13 +218,13 @@ function normalizeStep(raw: unknown): Step { }, }; } - return { id: str(r.id) || newId(), type: "step", text: str(r.text), done: bool(r.done) }; + return { id: idOf(r), type: "step", text: str(r.text), done: bool(r.done) }; } // ステッカー・シェイプ・写真に共通する配置情報(id と座標・回転)を正規化する。 function normalizePlacement(r: Record): Placement { return { - id: str(r.id) || newId(), + id: idOf(r), x: clampNum(r.x, 0, 0, MAX_POSITION), y: clampNum(r.y, 0, 0, MAX_POSITION), rot: num(r.rot), @@ -262,7 +267,7 @@ function normalizeArrow(raw: unknown): Arrow | null { const from = str(r.from); const to = str(r.to); if (!from || !to) return null; - const id = str(r.id) || newId(); + const id = idOf(r); const mx = num(r.mx); const my = num(r.my); const length = num(r.length); @@ -283,7 +288,7 @@ export function normalizePage(raw: unknown): Page { const shapes = list(r.shapes).map(normalizeShape); const shapeIds = new Set(shapes.map((s) => s.id)); return { - id: str(r.id) || newId(), + id: idOf(r), type: oneOf(r.type, ["flowchart", "notebook"], "flowchart"), title: str(r.title), frame: oneOf(r.frame, FRAMES, "aurora"), @@ -325,7 +330,7 @@ export function normalizeNotebook(raw: unknown): Notebook | null { } return { - id: str(r.id) || newId(), + id: idOf(r), name: str(r.name), type, color: hexColor(r.color, "#C9B6E4"),