Files
rustycms/scripts/normalize-image-iframe-gallery-slugs.mjs

126 lines
4.2 KiB
JavaScript

#!/usr/bin/env node
/**
* Normalisiert image_gallery, image, iframe: _slug und Dateiname = prefix + slugify(name).
* - image_gallery: image_gallery-{name}
* - image: image-{name}
* - iframe: iframe-{name}
* Aktualisiert alle Referenzen in content/de (inkl. row1Content in pages/posts).
* Hinweis: image_gallery.images referenziert img (Assets), nicht die image-Komponente.
*/
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const CONTENT_DE = path.join(__dirname, "..", "content", "de");
function slugify(value) {
if (value == null || value === "") return "";
return String(value)
.replace(/_/g, "-")
.replace(/\s+/g, "-")
.replace(/[^a-zA-Z0-9-]+/g, "-")
.replace(/-+/g, "-")
.replace(/^-|-$/g, "")
.toLowerCase() || "untitled";
}
function stripPrefix(name, prefixes) {
let s = name || "";
for (const p of prefixes) {
if (s.toLowerCase().startsWith(p.toLowerCase())) {
s = s.slice(p.length).replace(/^-+/, "");
break;
}
}
return s || name;
}
function parseJson5(str) {
try {
return JSON.parse(str);
} catch {
return null;
}
}
function processCollection(collectionDir, prefix, namePrefixes = []) {
if (!fs.existsSync(collectionDir)) return new Map();
const files = fs.readdirSync(collectionDir).filter((f) => f.endsWith(".json5")).sort();
const oldToNew = new Map();
const used = new Set();
for (const file of files) {
const raw = fs.readFileSync(path.join(collectionDir, file), "utf8");
const data = parseJson5(raw);
const oldSlug = data?._slug || file.replace(/\.json5$/, "");
const name = data?.name ?? oldSlug;
let rest = slugify(stripPrefix(name, namePrefixes));
let newSlug = prefix + rest;
let n = 0;
while (used.has(newSlug)) {
n++;
newSlug = prefix + rest + (n === 1 ? "-1" : "-" + n);
}
used.add(newSlug);
oldToNew.set(oldSlug, newSlug);
}
for (const file of files) {
const filePath = path.join(collectionDir, file);
const data = parseJson5(fs.readFileSync(filePath, "utf8"));
const oldSlug = data?._slug || file.replace(/\.json5$/, "");
const newSlug = oldToNew.get(oldSlug);
if (!newSlug) continue;
data._slug = newSlug;
const newPath = path.join(collectionDir, newSlug + ".json5");
fs.writeFileSync(newPath, JSON.stringify(data, null, 2) + "\n", "utf8");
if (path.basename(newPath) !== file) fs.unlinkSync(filePath);
}
return oldToNew;
}
// Reihenfolge: image_gallery, image, iframe (keine Abhängigkeit untereinander; image_gallery referenziert nur img)
const imageGalleryDir = path.join(CONTENT_DE, "image_gallery");
const imageDir = path.join(CONTENT_DE, "image");
const iframeDir = path.join(CONTENT_DE, "iframe");
const mapGallery = processCollection(imageGalleryDir, "image_gallery-", ["component-image-gallery-", "component-image-gallery"]);
const mapImage = processCollection(imageDir, "image-", ["component-image-"]);
const mapIframe = processCollection(iframeDir, "iframe-", ["component-iframe-"]);
const allMaps = [mapGallery, mapImage, mapIframe];
console.log("image_gallery:", Object.fromEntries(mapGallery));
console.log("image:", Object.fromEntries(mapImage));
console.log("iframe:", Object.fromEntries(mapIframe));
function walkDir(dir, fn) {
const entries = fs.readdirSync(dir, { withFileTypes: true });
for (const e of entries) {
const full = path.join(dir, e.name);
if (e.isDirectory()) walkDir(full, fn);
else if (e.name.endsWith(".json5")) fn(full);
}
}
walkDir(CONTENT_DE, (filePath) => {
let content = fs.readFileSync(filePath, "utf8");
let changed = false;
for (const oldToNew of allMaps) {
for (const [oldSlug, newSlug] of oldToNew) {
if (oldSlug === newSlug) continue;
const escaped = oldSlug.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const newContent = content.replace(new RegExp('"' + escaped + '"', "g"), '"' + newSlug + '"');
if (newContent !== content) {
content = newContent;
changed = true;
}
}
}
if (changed) fs.writeFileSync(filePath, content, "utf8");
});
console.log("Fertig. image_gallery-, image-, iframe-Slugs normalisiert und Referenzen aktualisiert.");