aboutsummaryrefslogtreecommitdiffhomepage
path: root/scripts/park-editor.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/park-editor.mjs')
-rw-r--r--scripts/park-editor.mjs106
1 files changed, 90 insertions, 16 deletions
diff --git a/scripts/park-editor.mjs b/scripts/park-editor.mjs
index 7a6c2fa..a872008 100644
--- a/scripts/park-editor.mjs
+++ b/scripts/park-editor.mjs
@@ -1,9 +1,10 @@
-// 公園データの簡易エディタ(ローカル専用)。
+// 公園・公共施設データの簡易エディタ(ローカル専用)。
//
// 使い方:
-// node scripts/park-editor.mjs
+// npm run park-editor
// → 表示された URL(既定 http://localhost:8787/)をブラウザで開く
-// → 表のセルを直接編集し、「保存」を押すと src/data/kodaira-parks.json を更新
+// → タブで「市内公園 / 周辺の公園 / 市内の公共施設 / 周辺の公共施設」を切り替え
+// → 表のセルを直接編集し、「保存」を押すと該当するJSONを更新
// → 反映確認後、git にコミットする
//
// 注意: ローカル(127.0.0.1)にのみ公開します。追加パッケージは不要です。
@@ -13,36 +14,109 @@ import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
const root = join(dirname(fileURLToPath(import.meta.url)), "..");
-const DATA = join(root, "src/data/kodaira-parks.json");
const HTML = join(root, "scripts/park-editor.html");
const PORT = Number(process.env.PORT || 8787);
+const DATASETS = {
+ parks: {
+ label: "市内公園",
+ path: join(root, "src/data/kodaira-parks.json"),
+ pretty: false,
+ },
+ nearbyParks: {
+ label: "周辺の公園",
+ path: join(root, "src/data/kodaira-nearby-parks.json"),
+ pretty: false,
+ },
+ facilities: {
+ label: "市内の公共施設",
+ path: join(root, "src/data/kodaira-facilities.json"),
+ pretty: true,
+ },
+ nearbyFacilities: {
+ label: "周辺の公共施設",
+ path: join(root, "src/data/kodaira-nearby-facilities.json"),
+ pretty: true,
+ },
+};
+
function send(res, code, type, body) {
res.writeHead(code, { "content-type": type });
res.end(body);
}
+function datasetFromUrl(url) {
+ const match = /^\/api\/data\/([A-Za-z]+)$/.exec(url);
+ if (!match) return null;
+ return DATASETS[match[1]] ? { id: match[1], dataset: DATASETS[match[1]] } : null;
+}
+
const server = createServer(async (req, res) => {
try {
const url = (req.url || "").split("?")[0];
if (req.method === "GET" && (url === "/" || url === "/index.html")) {
send(res, 200, "text/html; charset=utf-8", await readFile(HTML, "utf-8"));
- } else if (req.method === "GET" && url === "/api/parks") {
- send(res, 200, "application/json; charset=utf-8", await readFile(DATA, "utf-8"));
- } else if (req.method === "POST" && url === "/api/parks") {
+ return;
+ }
+
+ if (req.method === "GET" && url === "/api/datasets") {
+ send(
+ res,
+ 200,
+ "application/json; charset=utf-8",
+ JSON.stringify(
+ Object.entries(DATASETS).map(([id, dataset]) => ({ id, label: dataset.label })),
+ ),
+ );
+ return;
+ }
+
+ const target = datasetFromUrl(url);
+ if (!target) {
+ send(res, 404, "text/plain; charset=utf-8", "not found");
+ return;
+ }
+
+ if (req.method === "GET") {
+ send(
+ res,
+ 200,
+ "application/json; charset=utf-8",
+ await readFile(target.dataset.path, "utf-8"),
+ );
+ return;
+ }
+
+ if (req.method === "POST") {
let body = "";
for await (const chunk of req) body += chunk;
- const parks = JSON.parse(body);
- if (!Array.isArray(parks) || parks.length === 0) {
+ const data = JSON.parse(body);
+
+ if (target.id === "nearbyParks") {
+ if (!data || data.type !== "FeatureCollection" || !Array.isArray(data.features)) {
+ throw new Error("周辺の公園は FeatureCollection ではありません");
+ }
+ } else if (!Array.isArray(data) || data.length === 0) {
throw new Error("データが配列ではありません");
}
- // 元ファイルと同じコンパクトな1行JSONで保存する(日本語はそのまま)。
- await writeFile(DATA, JSON.stringify(parks), "utf-8");
- console.log(`保存しました: ${parks.length} 件 → ${DATA}`);
- send(res, 200, "application/json; charset=utf-8", JSON.stringify({ ok: true, count: parks.length }));
- } else {
- send(res, 404, "text/plain; charset=utf-8", "not found");
+
+ const text = target.dataset.pretty
+ ? `${JSON.stringify(data, null, 2)}\n`
+ : `${JSON.stringify(data)}\n`;
+ await writeFile(target.dataset.path, text, "utf-8");
+
+ const count = target.id === "nearbyParks" ? data.features.length : data.length;
+ console.log(`保存しました: ${target.dataset.label} ${count}件 → ${target.dataset.path}`);
+ send(
+ res,
+ 200,
+ "application/json; charset=utf-8",
+ JSON.stringify({ ok: true, count }),
+ );
+ return;
}
+
+ send(res, 405, "text/plain; charset=utf-8", "method not allowed");
} catch (e) {
console.error(e);
send(res, 500, "text/plain; charset=utf-8", String(e));
@@ -50,5 +124,5 @@ const server = createServer(async (req, res) => {
});
server.listen(PORT, "127.0.0.1", () => {
- console.log(`公園データ編集: http://localhost:${PORT}/ (Ctrl+C で終了)`);
+ console.log(`公園・施設データ編集: http://localhost:${PORT}/ (Ctrl+C で終了)`);
});