GitHub(nextgroup2706/ken_nogi)は今後使わず自社Gitea運用に切替え。 NodeSrvは旧リポジトリの履歴を破棄しファイルのみ統合(Dokploy用サービスアカウントは 別途mygit-admin/NodeSrv.gitに履歴あり)。notepmエクスポート(12GB)とPleasanter インストーラzip(208MB)はサイズが大きいため.gitignoreで除外。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
160 lines
7.3 KiB
JavaScript
160 lines
7.3 KiB
JavaScript
/**
|
||
* site-paths.js
|
||
* ------------------------------------------------------------
|
||
* configs/ 配下のフォルダ構成を一箇所で管理する共有ヘルパー。
|
||
* ClaudePleasanter直下に置く共通実装。全プロジェクトの .claude/js/ 配下
|
||
* (またはプロジェクト直下)にある薄いラッパーから require される。
|
||
*
|
||
* baseDir(プロジェクトルート)は各スクリプトの main() が
|
||
* process.env.PLEASANTER_PROJECT_ROOT(ラッパーが設定)から受け取る。
|
||
* このファイル自体はbaseDir解決を行わず、呼び出し側から渡されたconfigsDirを
|
||
* そのまま使う(layout非依存の純粋なパス組み立てヘルパー)。
|
||
*
|
||
* レイアウトは2種類:
|
||
* hierarchical(既定): configs/site-{SiteId}_{サイト名}/sitesettings/ に生JSONを保存
|
||
* flat : configs/ 直下に site-{SiteId}_latest.json をフラットに保存
|
||
* (抽出済みファイル configs/site-{SiteId}_{サイト名}/scripts/ 等は
|
||
* レイアウトによらず共通)
|
||
* layoutは各プロジェクトのラッパーが PLEASANTER_LAYOUT 環境変数("flat"|未設定=hierarchical)
|
||
* で明示指定する。既存configsフォルダの実際の保存構造を変えないための切り替えであり、
|
||
* 自動判定はしない。
|
||
*
|
||
* 構成(hierarchicalの場合):
|
||
* 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。(抽出済みファイルの置き場所はlayoutによらず共通)
|
||
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)のパスを返す(hierarchicalレイアウト用)。
|
||
// フォルダ自体が無い場合は null。
|
||
function latestJsonPath(configsDir, siteId) {
|
||
const siteDir = findSiteDir(configsDir, siteId);
|
||
if (!siteDir) return null;
|
||
return path.join(siteDir, "sitesettings", `site-${siteId}_latest.json`);
|
||
}
|
||
|
||
// 生JSON(getsiteダンプ)の置き場所は、プロジェクトごとに3パターンある
|
||
// (既存configsフォルダの実際の保存構造を変えないための切り替え。自動判定はしない):
|
||
// hierarchical(既定): configs/site-{siteId}_{title}/sitesettings/
|
||
// flat : configs/ 直下にフラット保存(サイト名フォルダを作らない)
|
||
// separate : baseDir/siteSettingJsons/ 直下にフラット保存(configs/とは別のトップレベルフォルダ)
|
||
// 抽出済みファイル(scripts/styles/等)の置き場所 configs/site-{siteId}_{title}/ 自体は
|
||
// どのlayoutでも共通(extract-site-config.js等はconfigsDirをそのまま使えばよい)。
|
||
|
||
// 生JSON保存先ディレクトリを解決する(保存前。フォルダが無ければ作成する)。
|
||
// baseDir: プロジェクトルート。configsDir: baseDir/configs/{env}(呼び出し元でenvを織り込み済み)。
|
||
// env: "production"|"development"。hierarchical/flatはconfigsDir側で分離済みのため未使用、
|
||
// separateのみ baseDir/siteSettingJsons/{env}/ として直接envを使う(configsDirを経由しないため)。
|
||
function rawJsonSaveDir(baseDir, configsDir, siteId, title, layout, env) {
|
||
if (layout === "flat") {
|
||
return ensureDir(configsDir);
|
||
}
|
||
if (layout === "separate") {
|
||
return ensureDir(path.join(baseDir, "siteSettingJsons", env));
|
||
}
|
||
const siteDir = ensureSiteDir(configsDir, siteId, title);
|
||
return sitesettingsDir(siteDir);
|
||
}
|
||
|
||
// 既存サイトの生JSON latestファイルパスを layout に応じて解決する(参照用、無ければnull)。
|
||
function findLatestJsonPath(baseDir, configsDir, siteId, layout, env) {
|
||
if (layout === "flat") {
|
||
const p = path.join(configsDir, `site-${siteId}_latest.json`);
|
||
return fs.existsSync(p) ? p : null;
|
||
}
|
||
if (layout === "separate") {
|
||
const p = path.join(baseDir, "siteSettingJsons", env, `site-${siteId}_latest.json`);
|
||
return fs.existsSync(p) ? p : null;
|
||
}
|
||
return latestJsonPath(configsDir, siteId);
|
||
}
|
||
|
||
module.exports = {
|
||
sanitize,
|
||
ensureDir,
|
||
findSiteDir,
|
||
ensureSiteDir,
|
||
sitesettingsDir,
|
||
docsDir,
|
||
newModifyDir,
|
||
latestModifyDir,
|
||
latestJsonPath,
|
||
rawJsonSaveDir,
|
||
findLatestJsonPath,
|
||
};
|