196 lines
7.4 KiB
JavaScript
196 lines
7.4 KiB
JavaScript
/**
|
||
* extract-site-config.js
|
||
* ------------------------------------------------------------
|
||
* 取得済みのサイト構成 (configs/site-{SiteId}_latest.json) から、
|
||
* Scripts / Styles / ServerScripts / Processes / ガイドHTML を
|
||
* 個別ファイルとして configs/site-{SiteId}/ 配下に書き出します。
|
||
*
|
||
* 使い方:
|
||
* node extract-site-config.js
|
||
* node extract-site-config.js ./configs/site-214812_latest.json
|
||
*
|
||
* 出力:
|
||
* configs/site-{SiteId}/
|
||
* manifest.json ← 抽出内容の一覧(build-desired-config.jsでの再構成に使用)
|
||
* scripts/{Id}_{Title}.js
|
||
* styles/{Id}_{Title}.css
|
||
* serverscripts/{Id}_{Title}.js
|
||
* html/{GuideName}.html ← GridGuide等、ガイドHTML(値が空でないもののみ)
|
||
* processes.json ← プロセス設定(SiteSettings.Processes をそのまま保存)
|
||
*
|
||
* 注意:
|
||
* ガイドHTML(GridGuide等)はSiteSettingsではなく、サイトデータ直下の項目です。
|
||
* そのため反映時はサイト設定の部分更新(updatesitesettings)ではなく、
|
||
* サイト全体更新(updatesite / Mode:"full")が必要になります。
|
||
* Scripts/Styles/ServerScripts/Processesは部分更新(Mode:"partial")で反映できます。
|
||
* 詳しくは build-desired-config.js の実行結果メッセージを参照してください。
|
||
* ------------------------------------------------------------
|
||
*/
|
||
|
||
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 });
|
||
}
|
||
|
||
function extractList(items, outDir, ext, bodyKey = "Body") {
|
||
const manifestEntries = [];
|
||
if (!items || items.length === 0) return manifestEntries;
|
||
ensureDir(outDir);
|
||
for (const item of items) {
|
||
const fileName = `${item.Id}_${sanitize(item.Title || item.Name)}${ext}`;
|
||
fs.writeFileSync(path.join(outDir, fileName), item[bodyKey] || "", "utf-8");
|
||
const { [bodyKey]: _omit, ...meta } = item;
|
||
manifestEntries.push({ ...meta, File: fileName });
|
||
}
|
||
return manifestEntries;
|
||
}
|
||
|
||
// config.json の SiteId(数値 / カンマ区切り文字列 / 配列)を
|
||
// 個々のSiteId文字列の配列に正規化する(get-site-config.jsと同仕様)。
|
||
function parseSiteIds(rawSiteId) {
|
||
const list = Array.isArray(rawSiteId) ? rawSiteId : String(rawSiteId).split(",");
|
||
return list
|
||
.map((id) => String(id).trim())
|
||
.filter((id) => id.length > 0);
|
||
}
|
||
|
||
const GUIDE_FIELDS = [
|
||
"GridGuide",
|
||
"EditorGuide",
|
||
"CalendarGuide",
|
||
"CrosstabGuide",
|
||
"GanttGuide",
|
||
"BurnDownGuide",
|
||
"TimeSeriesGuide",
|
||
"AnalyGuide",
|
||
"KambanGuide",
|
||
"ImageLibGuide",
|
||
];
|
||
|
||
// get-site-config.js からも呼び出せるよう関数化。
|
||
// CLI実行時(直接 `node extract-site-config.js`)は末尾のブロックが引数解決を行う。
|
||
function extractSiteConfig(latestPath) {
|
||
const baseDir = __dirname;
|
||
|
||
if (!fs.existsSync(latestPath)) {
|
||
console.error(`[エラー] ファイルが見つかりません: ${latestPath}`);
|
||
console.error("先に node get-site-config.js を実行してください。");
|
||
process.exit(1);
|
||
}
|
||
|
||
const json = JSON.parse(fs.readFileSync(latestPath, "utf-8"));
|
||
const data = json?.Response?.Data;
|
||
if (!data) {
|
||
console.error("[エラー] Response.Data が見つかりません。getsiteのレスポンス形式を確認してください。");
|
||
process.exit(1);
|
||
}
|
||
|
||
const siteId = data.SiteId;
|
||
const settings = data.SiteSettings || {};
|
||
const dirName = `site-${siteId}_${sanitize(data.Title)}`;
|
||
const outRoot = path.join(baseDir, "configs", dirName);
|
||
ensureDir(outRoot);
|
||
|
||
const manifest = {
|
||
SiteId: siteId,
|
||
Title: data.Title,
|
||
ExtractedAt: new Date().toISOString(),
|
||
SourceFile: path.relative(baseDir, latestPath).replace(/\\/g, "/"),
|
||
};
|
||
|
||
manifest.Scripts = extractList(settings.Scripts, path.join(outRoot, "scripts"), ".js");
|
||
manifest.Styles = extractList(settings.Styles, path.join(outRoot, "styles"), ".css");
|
||
manifest.ServerScripts = extractList(settings.ServerScripts, path.join(outRoot, "serverscripts"), ".js");
|
||
|
||
// ガイドHTML(サイトデータ直下。SiteSettingsではない点に注意)
|
||
const htmlDir = path.join(outRoot, "html");
|
||
const htmlEntries = [];
|
||
for (const field of GUIDE_FIELDS) {
|
||
const value = data[field];
|
||
if (value) {
|
||
ensureDir(htmlDir);
|
||
const fileName = `${field}.html`;
|
||
fs.writeFileSync(path.join(htmlDir, fileName), value, "utf-8");
|
||
htmlEntries.push({ Field: field, File: fileName, TopLevel: true });
|
||
}
|
||
}
|
||
manifest.Html = htmlEntries;
|
||
|
||
// プロセス設定 … 個別分割せず1つの定義ファイルとして保存
|
||
fs.writeFileSync(
|
||
path.join(outRoot, "processes.json"),
|
||
JSON.stringify(settings.Processes || [], null, 2),
|
||
"utf-8"
|
||
);
|
||
manifest.ProcessesFile = "processes.json";
|
||
manifest.ProcessesCount = (settings.Processes || []).length;
|
||
|
||
fs.writeFileSync(path.join(outRoot, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
|
||
|
||
console.log(`[OK] 抽出完了: ${outRoot}`);
|
||
console.log(` Scripts : ${manifest.Scripts.length}件`);
|
||
console.log(` Styles : ${manifest.Styles.length}件`);
|
||
console.log(` ServerScripts : ${manifest.ServerScripts.length}件`);
|
||
console.log(` Html(ガイド) : ${manifest.Html.length}件`);
|
||
console.log(` Processes : ${manifest.ProcessesCount}件 → processes.json`);
|
||
console.log("\n次のステップ: 各ファイルを直接編集するか、Claudeに修正内容を指示してください。");
|
||
console.log(`修正後は次のコマンドで反映用JSONを作成できます: node build-desired-config.js ${dirName}`);
|
||
|
||
return manifest;
|
||
}
|
||
|
||
// CLIとして直接実行された場合のみ、引数からlatestPathを解決して実行する
|
||
if (require.main === module) {
|
||
const baseDir = __dirname;
|
||
const latestPathArg = process.argv[2];
|
||
|
||
if (latestPathArg) {
|
||
extractSiteConfig(latestPathArg);
|
||
} else {
|
||
const configPath = path.join(baseDir, "config.json");
|
||
if (!fs.existsSync(configPath)) {
|
||
console.error("[エラー] config.jsonが見つかりません。抽出対象のJSONパスを引数で指定してください。");
|
||
process.exit(1);
|
||
}
|
||
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
||
const siteIds = parseSiteIds(config.SiteId);
|
||
if (siteIds.length === 0) {
|
||
console.error("[エラー] config.json の SiteId から有効なサイトIDを取得できませんでした。");
|
||
process.exit(1);
|
||
}
|
||
|
||
const missing = [];
|
||
for (const siteId of siteIds) {
|
||
const latestPath = path.join(baseDir, "configs", `site-${siteId}_latest.json`);
|
||
if (!fs.existsSync(latestPath)) {
|
||
console.error(`[警告] ファイルが見つかりません(スキップ): ${latestPath}`);
|
||
missing.push(siteId);
|
||
continue;
|
||
}
|
||
if (siteIds.length > 1) {
|
||
console.log(`\n==== SiteId: ${siteId} ====`);
|
||
}
|
||
extractSiteConfig(latestPath);
|
||
}
|
||
|
||
if (missing.length > 0) {
|
||
console.error(`\n[エラー] 未取得のSiteIdがあります: ${missing.join(", ")}`);
|
||
console.error("先に node get-site-config.js を実行してください。");
|
||
process.exit(1);
|
||
}
|
||
}
|
||
}
|
||
|
||
module.exports = { extractSiteConfig };
|