/** * site-paths.js * ------------------------------------------------------------ * configs/ 配下のフォルダ構成を一箇所で管理する共有ヘルパー。 * * 構成: * configs/ * master/ … ユーザー/組織/グループのマスターデータ(get-master-data.js) * site-{SiteId}_{サイト名}/ * sitesettings/ … getsiteの生JSON(site-{SiteId}_latest.json / _{timestamp}.json) * scripts/ styles/ serverscripts/ html/ processes.json / manifest.json * … extract-site-config.js による分割済みファイル(従来通り) * docs/ … 仕様書(.md)や改善要望プラン等、sitesettings以外の関連ドキュメント * modify/{request}/ … 修正依頼ごとに新規作成。変更前後のconfigファイルや差分・結果を保管 * ------------------------------------------------------------ */ const fs = require("fs"); const path = require("path"); function sanitize(name) { return ( String(name || "untitled") .replace(/[\\/:*?"<>|]/g, "_") .trim() .slice(0, 60) || "untitled" ); } function ensureDir(dir) { if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); return dir; } // configs/ 配下から "site-{siteId}_*"(前方一致)または "site-{siteId}"(完全一致)の // フォルダを探す。見つからなければ null。 function findSiteDir(configsDir, siteId) { if (!fs.existsSync(configsDir)) return null; const bare = `site-${siteId}`; const prefix = `site-${siteId}_`; const candidates = fs.readdirSync(configsDir).filter((name) => { const full = path.join(configsDir, name); return fs.statSync(full).isDirectory() && (name === bare || name.startsWith(prefix)); }); const suffixed = candidates.filter((n) => n !== bare); if (suffixed.length >= 1) return path.join(configsDir, suffixed[0]); if (candidates.includes(bare)) return path.join(configsDir, bare); return null; } // 既存フォルダがあればそれを使い、無ければ site-{siteId}_{sanitize(title)} を新規作成する function ensureSiteDir(configsDir, siteId, title) { const existing = findSiteDir(configsDir, siteId); if (existing) return existing; const dir = path.join(configsDir, `site-${siteId}_${sanitize(title)}`); return ensureDir(dir); } function sitesettingsDir(siteDir) { return ensureDir(path.join(siteDir, "sitesettings")); } function docsDir(siteDir) { return ensureDir(path.join(siteDir, "docs")); } // 修正依頼用の新規フォルダを作成する(labelを省略した場合はタイムスタンプを使う) function newModifyDir(siteDir, label) { const name = label || new Date().toISOString().replace(/[:.]/g, "-"); return ensureDir(path.join(siteDir, "modify", name)); } // 既存のmodifyフォルダの中で最も新しいもの(フォルダ名の降順ソート)を返す。無ければnull。 function latestModifyDir(siteDir) { const modifyRoot = path.join(siteDir, "modify"); if (!fs.existsSync(modifyRoot)) return null; const dirs = fs .readdirSync(modifyRoot) .filter((n) => fs.statSync(path.join(modifyRoot, n)).isDirectory()) .sort(); if (dirs.length === 0) return null; return path.join(modifyRoot, dirs[dirs.length - 1]); } // サイトの最新getsiteダンプ(site-{siteId}_latest.json)のパスを返す。 // フォルダ自体が無い場合は null。 function latestJsonPath(configsDir, siteId) { const siteDir = findSiteDir(configsDir, siteId); if (!siteDir) return null; return path.join(siteDir, "sitesettings", `site-${siteId}_latest.json`); } module.exports = { sanitize, ensureDir, findSiteDir, ensureSiteDir, sitesettingsDir, docsDir, newModifyDir, latestModifyDir, latestJsonPath, };