{"version":3,"file":"common.cjs","names":["Papa"],"sources":["../src/common.ts"],"sourcesContent":["// HTML工数集計の共通型定義とユーティリティ関数\n// Node.js版とブラウザ版で共通利用\nimport Papa from \"papaparse\";\n\nexport interface WorktimeRow {\n\torder: string;\n\tprocess: string;\n\tdate: string; // yyyy-mm-dd\n\thours: number;\n\torderName: string;\n}\n\n// 年月取得の共通関数\nexport function getYearMonth(\n\tdoc: Document,\n\tgetValue: (el: Element | null) => string,\n): { year: string; month: string } {\n\treturn {\n\t\tyear: getValue(doc.getElementById(\"vD_SYORI_Y4\")),\n\t\tmonth: getValue(doc.getElementById(\"vD_SYORI_MM\")),\n\t};\n}\n\n// --- 共通ロジック: ヘッダ・インデックス・行データ抽出 ---\nexport function getHeaders(row: Element): string[] {\n\treturn Array.from((row as Element)?.querySelectorAll?.(\"th,td\") || []).map(\n\t\t(th) => (th as Element).textContent?.trim() || \"\",\n\t);\n}\n\n/**\n * ヘッダー配列から特定のカラム名に対応するインデックスを取得する\n * @param headers - ヘッダー名の文字列配列\n * @returns 各カラム(製造オーダ、工程、日付、製造オーダ名、工数詳細または工数)のインデックスを持つオブジェクト\n */\nexport function getHeaderIndexes(headers: string[]) {\n\treturn {\n\t\torder: headers.findIndex((h) => h.includes(\"製造オーダ\")),\n\t\tprocess: headers.findIndex((h) => h.includes(\"工程\")),\n\t\tdate: headers.findIndex((h) => h.includes(\"日付\")),\n\t\torderName: headers.findIndex((h) => h.includes(\"製造オーダ名\")),\n\t\ttime:\n\t\t\theaders.findIndex((h) => h.includes(\"工数詳細\")) !== -1\n\t\t\t\t? headers.findIndex((h) => h.includes(\"工数詳細\"))\n\t\t\t\t: headers.findIndex((h) => h.includes(\"工数\")),\n\t};\n}\n\n/**\n * セルの配列とヘッダーインデックス、年、月、現在の日付から作業時間情報を抽出する\n * @param cells - テーブルの各セル要素の配列\n * @param indexes - ヘッダー名から取得したインデックスのオブジェクト\n * @param year - 年(YYYY形式の文字列)\n * @param month - 月(MM形式の文字列)\n * @param currentDate - 現在の日付(YYYY-MM-DD形式の文字列)\n * @returns 抽出された作業時間情報(WorktimeRow型)または抽出できない場合はnull\n */\nexport function extractWorktime(\n\tcells: Element[],\n\tindexes: ReturnType<typeof getHeaderIndexes>,\n\tyear: string,\n\tmonth: string,\n\tcurrentDate: string,\n): WorktimeRow | null {\n\tconst dateRaw = cells[indexes.date]?.textContent?.trim() || \"\";\n\tlet date = currentDate;\n\tif (dateRaw) {\n\t\tconst day = dateRaw.split(\"(\")[0]?.padStart(2, \"0\") || \"\";\n\t\tdate = `${year}-${month}-${day}`;\n\t}\n\tif (!date) return null;\n\tconst timeStr = cells[indexes.time]?.textContent?.trim() || \"\";\n\tconst hours = convertTimeToHour(timeStr);\n\treturn {\n\t\torder: cells[indexes.order]?.textContent?.trim() || \"\",\n\t\tprocess: cells[indexes.process]?.textContent?.trim() || \"\",\n\t\tdate,\n\t\thours,\n\t\torderName: cells[indexes.orderName]?.textContent?.trim() || \"\",\n\t};\n}\n\n/**\n * 工数詳細列の時間文字列を時間に変換する\n *\n * @param timeStr - \"Xh Ym\"という形式の時間文字列。Xは時間の数、Yは分の数です。\n * @returns 時間を表す数値。\n *\n * @example\n * ```ts\n * convertTimeToHour(\"2h 30m\") // => 2.5\n * ```\n */\nexport function convertTimeToHour(timeStr: string): number {\n\tlet totalMinutes = 0;\n\tfor (const part of timeStr.split(\" \")) {\n\t\tif (part.endsWith(\"h\")) totalMinutes += Number.parseInt(part, 10) * 60;\n\t\telse if (part.endsWith(\"m\")) totalMinutes += Number.parseInt(part, 10);\n\t}\n\treturn totalMinutes / 60;\n}\n\n/**\n * 開始日から終了日までの日付配列を生成する\n *\n * @param start - 開始日 (yyyy-mm-dd形式)\n * @param end - 終了日 (yyyy-mm-dd形式)\n * @returns 開始日から終了日までの連続した日付文字列の配列 (yyyy-mm-dd形式)\n *\n * @example\n * ```ts\n * getDateArray(\"2024-01-01\", \"2024-01-03\")\n * // => [\"2024-01-01\", \"2024-01-02\", \"2024-01-03\"]\n * ```\n */\nexport function getDateArray(start: string, end: string): string[] {\n\tconst arr: string[] = [];\n\t// biome-ignore lint/style/useConst: d is mutated via setDate\n\tlet d = new Date(start);\n\tconst endD = new Date(end);\n\twhile (d <= endD) {\n\t\tconst y = d.getFullYear();\n\t\tconst m = String(d.getMonth() + 1).padStart(2, \"0\");\n\t\tconst day = String(d.getDate()).padStart(2, \"0\");\n\t\tarr.push(`${y}-${m}-${day}`);\n\t\td.setDate(d.getDate() + 1);\n\t}\n\treturn arr;\n}\n\n/**\n * 時間値を文字列にフォーマットする\n *\n * 小数点以下が .0 または .5 の場合は1桁で表示し、それ以外は2桁で表示します。\n *\n * @param val - フォーマットする時間値\n * @returns フォーマットされた時間文字列\n *\n * @example\n * ```ts\n * formatHour(2.0)  // => \"2.0\"\n * formatHour(2.5)  // => \"2.5\"\n * formatHour(2.33) // => \"2.33\"\n * ```\n */\nexport function formatHour(val: number): string {\n\t// 小数点以下が .0 または .5 なら1桁、それ以外は2桁\n\tif (Number.isInteger(val * 2)) {\n\t\treturn val.toFixed(1);\n\t}\n\treturn val.toFixed(2);\n}\n\n/**\n * グループ化されたデータの型定義\n */\ntype WorktimeGroup = {\n\torder: string;\n\tprocess: string;\n\t[date: string]: string | number;\n};\n\n/**\n * WorktimeRowの配列を製造オーダと工程でグループ化する\n *\n * 同じ製造オーダと工程の組み合わせについて、日付ごとの工数をマップに集約します。\n *\n * @param rows - グループ化するWorktimeRowの配列\n * @returns 製造オーダと工程をキーとしたグループのMap\n *\n * @example\n * ```ts\n * const rows = [\n *   { order: \"A\", process: \"P1\", date: \"2024-01-01\", hours: 2.0, orderName: \"\" },\n *   { order: \"A\", process: \"P1\", date: \"2024-01-02\", hours: 3.0, orderName: \"\" },\n * ];\n * const groups = groupByOrderAndProcess(rows);\n * // Map { \"A\\tP1\" => { order: \"A\", process: \"P1\", \"2024-01-01\": 2.0, \"2024-01-02\": 3.0 } }\n * ```\n */\nexport function groupByOrderAndProcess(rows: WorktimeRow[]): Map<string, WorktimeGroup> {\n\tconst groupMap = new Map<string, WorktimeGroup>();\n\tfor (const row of rows) {\n\t\tconst key = `${row.order}\\t${row.process}`;\n\t\tlet group = groupMap.get(key);\n\t\tif (!group) {\n\t\t\tgroup = { order: row.order, process: row.process };\n\t\t\tgroupMap.set(key, group);\n\t\t}\n\t\tgroup[row.date] = row.hours;\n\t}\n\treturn groupMap;\n}\n\n/**\n * グループ化されたデータをフォーマットして2次元配列に変換する\n *\n * 各グループについて、製造オーダ、工程、および各日付の工数をフォーマットして配列化します。\n * 日付に対応する工数が存在しない場合は \"0.0\" で埋めます。\n *\n * @param groupMap - グループ化されたデータのMap\n * @param dates - 出力する日付の配列 (yyyy-mm-dd形式)\n * @returns フォーマットされたデータ行の2次元配列\n *\n * @example\n * ```ts\n * const groups = new Map([\n *   [\"A\\tP1\", { order: \"A\", process: \"P1\", \"2024-01-01\": 2.0 }]\n * ]);\n * const dates = [\"2024-01-01\", \"2024-01-02\"];\n * const data = formatDataRows(groups, dates);\n * // [[\"A\", \"P1\", \"2.0\", \"0.0\"]]\n * ```\n */\nexport function formatDataRows(\n\tgroupMap: Map<string, WorktimeGroup>,\n\tdates: string[],\n): (string | number)[][] {\n\tconst data: (string | number)[][] = [];\n\t// 製造オーダと工程でソート\n\tconst sortedGroups = Array.from(groupMap.values()).sort(\n\t\t(a, b) => a.order.localeCompare(b.order) || a.process.localeCompare(b.process),\n\t);\n\tfor (const g of sortedGroups) {\n\t\tconst arr: (string | number)[] = [g.order, g.process];\n\t\tfor (const d of dates) {\n\t\t\tconst v = g[d] ?? 0.0;\n\t\t\tif (typeof v === \"number\") {\n\t\t\t\tarr.push(formatHour(v));\n\t\t\t} else {\n\t\t\t\tarr.push(v);\n\t\t\t}\n\t\t}\n\t\tdata.push(arr);\n\t}\n\treturn data;\n}\n\n/**\n * WorktimeRow[] を横持ちCSV形式の2次元配列(string|number)に変換する\n *\n * 入力されたWorktimeRowの配列を、日付を列とした横持ち形式の2次元配列に変換します。\n * ヘッダー行には「製造オーダ」「工程」と日付範囲が含まれ、データ行には各製造オーダ・工程\n * ごとの日付別工数が含まれます。日付範囲は入力データの最小日付から最大日付までを自動的に\n * 生成します。\n *\n * @param rows - 変換するWorktimeRowの配列\n * @returns ヘッダー行とデータ行を含む2次元配列。データが空の場合は空配列を返します。\n *\n * @example\n * ```ts\n * const rows = [\n *   { order: \"A\", process: \"P1\", date: \"2024-01-01\", hours: 2.0, orderName: \"\" },\n *   { order: \"A\", process: \"P1\", date: \"2024-01-02\", hours: 3.0, orderName: \"\" },\n * ];\n * const result = toWideArray(rows);\n * // [\n * //   [\"製造オーダ\", \"工程\", \"2024-01-01\", \"2024-01-02\"],\n * //   [\"A\", \"P1\", \"2.0\", \"3.0\"]\n * // ]\n * ```\n */\nexport function toWideArray(rows: WorktimeRow[]): (string | number)[][] {\n\tif (!rows.length) return [];\n\n\t// 日付範囲を取得\n\tconst dateList = rows.map((r) => r.date).sort();\n\tconst minDate = dateList[0];\n\tconst maxDate = dateList[dateList.length - 1];\n\tif (!minDate || !maxDate) return [];\n\n\t// 日付配列を生成\n\tconst dates = getDateArray(minDate, maxDate);\n\n\t// ヘッダー行を生成\n\tconst headers = [\"製造オーダ\", \"工程\", ...dates];\n\n\t// データをグループ化\n\tconst groupMap = groupByOrderAndProcess(rows);\n\n\t// データ行をフォーマット\n\tconst data = formatDataRows(groupMap, dates);\n\n\treturn [headers, ...data];\n}\n\n/**\n * 2次元配列をCSV形式の文字列に変換する\n *\n * @param outRows - CSV データを表す2次元配列。各内部配列は1行を表し、要素は文字列または数値。\n * @param withBom - 先頭に UTF-8 BOM (\\ufeff) を付与するか。Excel 用。デフォルトは false。\n * @returns CSV形式の文字列(ヘッダーなし)\n *\n * @remarks\n * PapaParse の `unparse` メソッドを使用して配列をCSV形式に変換します。\n * header オプションは false に設定されているため、ヘッダー行は生成されません。\n * BOM 付与は Excel での文字化け防止用です。\n *\n * @example\n * ```ts\n * toCSVString(data, true) // BOM付きCSV\n * toCSVString(data) // BOMなしCSV(デフォルト)\n * ```\n */\nexport function toCSVString(outRows: (string | number)[][], withBom = false): string {\n\tconst csv = Papa.unparse(outRows, { header: false, newline: \"\\r\\n\" });\n\treturn withBom ? `\\ufeff${csv}` : csv;\n}\n"],"mappings":"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"}