714 lines
30 KiB
JavaScript
714 lines
30 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* Migriert Contentful-Export (contentful-export.json) nach rustycms content/de/.
|
||
* Nur deutsche Locale (en kann später ergänzt werden).
|
||
*
|
||
* Aufruf: node scripts/contentful-to-rustycms.mjs [Pfad-zum-Export] [--html-only] [--only=quote|iframe|image|image_gallery]
|
||
* Default Export-Pfad: ../www.windwiderstand.de/contentful-export.json
|
||
* --html-only: nur HTML migrieren
|
||
* --only=X: nur Typ X migrieren (mehrfach möglich), X = html|quote|iframe|image|image_gallery|youtube_video
|
||
*/
|
||
|
||
import fs from "fs";
|
||
import path from "path";
|
||
import { fileURLToPath } from "url";
|
||
|
||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||
const ROOT = path.resolve(__dirname, "..");
|
||
const CONTENT_DE = path.join(ROOT, "content", "de");
|
||
const argv = process.argv.slice(2);
|
||
const ONLY = new Set();
|
||
if (argv.includes("--html-only")) ONLY.add("html");
|
||
argv.forEach((a) => {
|
||
const m = a.match(/^--only=(.+)$/);
|
||
if (m) ONLY.add(m[1]);
|
||
});
|
||
const EXPORT_PATH = argv.filter((a) => a !== "--html-only" && !a.startsWith("--only="))[0] || path.join(ROOT, "..", "www.windwiderstand.de", "contentful-export.json");
|
||
|
||
// ─── Slug-Normalisierung ─────────────────────────────────────────────────
|
||
function slugify(value) {
|
||
if (value == null || value === "") return "";
|
||
let s = String(value)
|
||
.replace(/^\//, "")
|
||
.replace(/\//g, "-")
|
||
.replace(/[^a-zA-Z0-9_-]+/g, "-")
|
||
.replace(/-+/g, "-")
|
||
.replace(/^-|-$/g, "");
|
||
return s || "untitled";
|
||
}
|
||
|
||
function safeSlug(entry, type) {
|
||
const f = entry?.fields || {};
|
||
if (type === "page" && f.slug != null) return f.slug === "/" ? "home" : slugify(f.slug);
|
||
if (f.id != null) return slugify(f.id);
|
||
if (type === "link" && f.slug != null) return slugify(f.slug);
|
||
if (entry?.sys?.id) return slugify(entry.sys.id);
|
||
return "untitled";
|
||
}
|
||
|
||
// ─── Rekursive Sammlung: alle Entries und Assets ──────────────────────────
|
||
function collectNodes(obj, entries, assets) {
|
||
if (!obj || typeof obj !== "object") return;
|
||
if (Array.isArray(obj)) {
|
||
obj.forEach((item) => collectNodes(item, entries, assets));
|
||
return;
|
||
}
|
||
const sys = obj.sys;
|
||
const fields = obj.fields;
|
||
if (sys?.type === "Asset" && fields?.file) {
|
||
const id = sys.id;
|
||
if (!assets.has(id)) assets.set(id, { sys, fields });
|
||
return;
|
||
}
|
||
const contentTypeId = sys?.contentType?.sys?.id || sys?.contentType?.id;
|
||
if (sys?.type === "Entry" && contentTypeId) {
|
||
const id = sys.id;
|
||
if (!entries.has(id)) {
|
||
entries.set(id, { sys: { ...sys, contentType: { id: contentTypeId } }, fields: fields || {} });
|
||
if (fields && typeof fields === "object") {
|
||
Object.values(fields).forEach((v) => collectNodes(v, entries, assets));
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
Object.values(obj).forEach((v) => collectNodes(v, entries, assets));
|
||
}
|
||
|
||
// ─── JSON5-ähnlich ausgeben (gültiges JSON, 2 Leerzeichen) ────────────────
|
||
function writeJson5(filePath, obj) {
|
||
const dir = path.dirname(filePath);
|
||
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
||
const str = JSON.stringify(obj, null, 2);
|
||
fs.writeFileSync(filePath, str + "\n", "utf8");
|
||
}
|
||
|
||
// ─── Main ───────────────────────────────────────────────────────────────
|
||
function main() {
|
||
if (!fs.existsSync(EXPORT_PATH)) {
|
||
console.error("Export-Datei nicht gefunden:", EXPORT_PATH);
|
||
process.exit(1);
|
||
}
|
||
console.log("Lese Export:", EXPORT_PATH);
|
||
const data = JSON.parse(fs.readFileSync(EXPORT_PATH, "utf8"));
|
||
const byType = data.byType || {};
|
||
const entries = new Map();
|
||
const assets = new Map();
|
||
Object.values(byType).forEach((group) => {
|
||
if (group?.items) group.items.forEach((item) => collectNodes(item, entries, assets));
|
||
});
|
||
console.log("Einträge:", entries.size, "Assets:", assets.size);
|
||
|
||
const idToSlug = new Map();
|
||
const SUPPORTED_ROW_COMPONENTS = new Set([
|
||
"markdown", "html", "componentLinkList", "fullwidthBanner", "componentPostOverview", "componentSearchableText",
|
||
"quoteComponent", "iframe", "image", "imageGallery", "youtubeVideo",
|
||
]);
|
||
|
||
function getSlug(entryOrId, contentType) {
|
||
const entry = typeof entryOrId === "string" ? entries.get(entryOrId) : entryOrId;
|
||
if (!entry) return null;
|
||
const id = entry.sys?.id;
|
||
const type = contentType || entry.sys?.contentType?.id || entry.sys?.contentType?.sys?.id;
|
||
if (idToSlug.has(id)) return idToSlug.get(id);
|
||
// Assets: bereits in idToSlug aus Schritt 1
|
||
if (entry.sys?.type === "Asset") return idToSlug.get(id) || slugify(entry.fields?.title || id);
|
||
const slug = safeSlug(entry, type);
|
||
let finalSlug = slug;
|
||
let n = 0;
|
||
const used = new Set(idToSlug.values());
|
||
while (used.has(finalSlug)) {
|
||
n++;
|
||
finalSlug = slug + "-" + n;
|
||
}
|
||
idToSlug.set(id, finalSlug);
|
||
return finalSlug;
|
||
}
|
||
|
||
function refToSlug(ref) {
|
||
if (ref == null) return null;
|
||
if (typeof ref === "string") return idToSlug.get(ref) || ref;
|
||
if (ref.sys?.type === "Entry") return getSlug(ref, ref.sys?.contentType?.id);
|
||
if (ref.sys?.type === "Asset") return getSlug(ref, "img");
|
||
return null;
|
||
}
|
||
|
||
const run = (key) => !ONLY.size || ONLY.has(key);
|
||
|
||
// Bei --only=image/image_gallery: nur Asset-Slugs in idToSlug eintragen (für refToSlug), ohne img-Dateien zu schreiben
|
||
if (ONLY.size && (ONLY.has("image") || ONLY.has("image_gallery"))) {
|
||
assets.forEach((asset, id) => {
|
||
const slug = slugify(asset.fields?.title || id);
|
||
const uniq = Array.from(idToSlug.values()).includes(slug) ? slug + "-" + id.slice(0, 6) : slug;
|
||
idToSlug.set(id, uniq);
|
||
});
|
||
}
|
||
|
||
if (run("img")) {
|
||
// ─── 1) Assets → img ───────────────────────────────────────────────────
|
||
assets.forEach((asset, id) => {
|
||
const slug = slugify(asset.fields?.title || id);
|
||
const uniq = Array.from(idToSlug.values()).includes(slug) ? slug + "-" + id.slice(0, 6) : slug;
|
||
idToSlug.set(id, uniq);
|
||
const file = asset.fields?.file || {};
|
||
let url = file.url || "";
|
||
if (url && !url.startsWith("http")) url = "https:" + url;
|
||
const out = {
|
||
_slug: uniq,
|
||
title: asset.fields?.title ?? "",
|
||
description: asset.fields?.description ?? "",
|
||
file: {
|
||
url,
|
||
fileName: file.fileName,
|
||
contentType: file.contentType,
|
||
details: file.details,
|
||
},
|
||
};
|
||
writeJson5(path.join(CONTENT_DE, "img", uniq + ".json5"), out);
|
||
});
|
||
console.log("img:", assets.size);
|
||
}
|
||
|
||
if (run("tag")) {
|
||
// ─── 2) Tag ────────────────────────────────────────────────────────────
|
||
(byType.tag?.items || []).forEach((entry) => {
|
||
const slug = getSlug(entry, "tag");
|
||
const f = entry.fields || {};
|
||
writeJson5(path.join(CONTENT_DE, "tag", slug + ".json5"), {
|
||
_slug: slug,
|
||
name: f.name ?? slug,
|
||
});
|
||
});
|
||
console.log("tag:", (byType.tag?.items || []).length);
|
||
}
|
||
|
||
if (run("link")) {
|
||
// ─── 3) Link ───────────────────────────────────────────────────────────
|
||
(byType.link?.items || []).forEach((entry) => {
|
||
const slug = getSlug(entry, "link");
|
||
const f = entry.fields || {};
|
||
writeJson5(path.join(CONTENT_DE, "link", slug + ".json5"), {
|
||
_slug: slug,
|
||
name: f.linkName ?? slug,
|
||
internal: slug,
|
||
linkName: f.linkName ?? "",
|
||
url: f.url ?? "",
|
||
newTab: f.newTab ?? false,
|
||
external: f.externalLink ?? false,
|
||
description: f.description ?? "",
|
||
alt: f.alt ?? "",
|
||
showText: f.showText !== false,
|
||
author: f.author ?? "–",
|
||
date: f.date ?? "",
|
||
source: f.source ?? "–",
|
||
});
|
||
});
|
||
console.log("link:", (byType.link?.items || []).length);
|
||
}
|
||
|
||
if (run("markdown")) {
|
||
// ─── 4) Markdown ────────────────────────────────────────────────────────
|
||
function extractMarkdown(entry) {
|
||
const slug = getSlug(entry, "markdown");
|
||
const f = entry.fields || {};
|
||
const layout = f.layout?.fields || {};
|
||
writeJson5(path.join(CONTENT_DE, "markdown", slug + ".json5"), {
|
||
_slug: slug,
|
||
name: f.id ?? slug,
|
||
content: f.content ?? "",
|
||
layout: {
|
||
mobile: layout.mobile ?? "12",
|
||
tablet: layout.tablet,
|
||
desktop: layout.desktop,
|
||
spaceBottom: layout.spaceBottom ?? 0,
|
||
},
|
||
alignment: f.alignment ?? "left",
|
||
});
|
||
return slug;
|
||
}
|
||
function ensureMarkdown(entry) {
|
||
if (!entry || entry.sys?.contentType?.id !== "markdown") return null;
|
||
if (!idToSlug.has(entry.sys.id)) extractMarkdown(entry);
|
||
return idToSlug.get(entry.sys.id);
|
||
}
|
||
(byType.markdown?.items || []).forEach(extractMarkdown);
|
||
entries.forEach((entry) => {
|
||
if (entry.sys?.contentType?.id === "markdown" && !idToSlug.has(entry.sys.id)) extractMarkdown(entry);
|
||
});
|
||
console.log("markdown:", Array.from(entries.values()).filter((e) => e.sys?.contentType?.id === "markdown").length);
|
||
}
|
||
|
||
// ─── 4b) HTML (html) ────────────────────────────────────────────────────
|
||
if (run("html")) {
|
||
function extractHtml(entry) {
|
||
const slug = getSlug(entry, "html");
|
||
const f = entry.fields || {};
|
||
const layout = f.layout?.fields || f.layout || {};
|
||
writeJson5(path.join(CONTENT_DE, "html", slug + ".json5"), {
|
||
_slug: slug,
|
||
name: f.id ?? slug,
|
||
html: f.html ?? "",
|
||
layout: {
|
||
mobile: layout.mobile ?? "12",
|
||
tablet: layout.tablet,
|
||
desktop: layout.desktop,
|
||
spaceBottom: layout.spaceBottom ?? 0,
|
||
},
|
||
});
|
||
return slug;
|
||
}
|
||
(byType.html?.items || []).forEach(extractHtml);
|
||
entries.forEach((entry) => {
|
||
if (entry.sys?.contentType?.id === "html" && !idToSlug.has(entry.sys.id)) extractHtml(entry);
|
||
});
|
||
console.log("html:", Array.from(entries.values()).filter((e) => e.sys?.contentType?.id === "html").length);
|
||
}
|
||
|
||
// ─── 4c) Quote (quoteComponent) ─────────────────────────────────────────
|
||
if (run("quote")) {
|
||
(byType.quoteComponent?.items || []).forEach((entry) => {
|
||
const slug = getSlug(entry, "quoteComponent");
|
||
const f = entry.fields || {};
|
||
const layout = f.layout?.fields || f.layout || {};
|
||
writeJson5(path.join(CONTENT_DE, "quote", slug + ".json5"), {
|
||
_slug: slug,
|
||
quote: f.quote ?? "",
|
||
author: f.author ?? "",
|
||
variant: f.variant ?? "left",
|
||
layout: {
|
||
mobile: layout.mobile ?? "12",
|
||
tablet: layout.tablet,
|
||
desktop: layout.desktop,
|
||
spaceBottom: layout.spaceBottom ?? 0,
|
||
},
|
||
});
|
||
});
|
||
entries.forEach((e) => {
|
||
if (e.sys?.contentType?.id === "quoteComponent" && !idToSlug.has(e.sys.id)) {
|
||
const slug = getSlug(e, "quoteComponent");
|
||
const f = e.fields || {};
|
||
const layout = f.layout?.fields || f.layout || {};
|
||
writeJson5(path.join(CONTENT_DE, "quote", slug + ".json5"), {
|
||
_slug: slug,
|
||
quote: f.quote ?? "",
|
||
author: f.author ?? "",
|
||
variant: f.variant ?? "left",
|
||
layout: { mobile: layout.mobile ?? "12", tablet: layout.tablet, desktop: layout.desktop, spaceBottom: layout.spaceBottom ?? 0 },
|
||
});
|
||
}
|
||
});
|
||
console.log("quote:", Array.from(entries.values()).filter((e) => e.sys?.contentType?.id === "quoteComponent").length);
|
||
}
|
||
|
||
// ─── 4d) Iframe ────────────────────────────────────────────────────────
|
||
if (run("iframe")) {
|
||
(byType.iframe?.items || []).forEach((entry) => {
|
||
const slug = getSlug(entry, "iframe");
|
||
const f = entry.fields || {};
|
||
const layout = f.layout?.fields || f.layout || {};
|
||
writeJson5(path.join(CONTENT_DE, "iframe", slug + ".json5"), {
|
||
_slug: slug,
|
||
name: f.name ?? slug,
|
||
content: f.content ?? "",
|
||
iframe: f.iframe ?? "",
|
||
overlayImage: refToSlug(f.overlayImage) ?? undefined,
|
||
layout: {
|
||
mobile: layout.mobile ?? "12",
|
||
tablet: layout.tablet,
|
||
desktop: layout.desktop,
|
||
spaceBottom: layout.spaceBottom ?? 0,
|
||
},
|
||
});
|
||
});
|
||
entries.forEach((e) => {
|
||
if (e.sys?.contentType?.id === "iframe" && !idToSlug.has(e.sys.id)) {
|
||
const slug = getSlug(e, "iframe");
|
||
const f = e.fields || {};
|
||
const layout = f.layout?.fields || f.layout || {};
|
||
writeJson5(path.join(CONTENT_DE, "iframe", slug + ".json5"), {
|
||
_slug: slug,
|
||
name: f.name ?? slug,
|
||
content: f.content ?? "",
|
||
iframe: f.iframe ?? "",
|
||
overlayImage: refToSlug(f.overlayImage) ?? undefined,
|
||
layout: { mobile: layout.mobile ?? "12", tablet: layout.tablet, desktop: layout.desktop, spaceBottom: layout.spaceBottom ?? 0 },
|
||
});
|
||
}
|
||
});
|
||
console.log("iframe:", Array.from(entries.values()).filter((e) => e.sys?.contentType?.id === "iframe").length);
|
||
}
|
||
|
||
// ─── 4e) Image ───────────────────────────────────────────────────────────
|
||
if (run("image")) {
|
||
(byType.image?.items || []).forEach((entry) => {
|
||
const slug = getSlug(entry, "image");
|
||
const f = entry.fields || {};
|
||
const layout = f.layout?.fields || f.layout || {};
|
||
writeJson5(path.join(CONTENT_DE, "image", slug + ".json5"), {
|
||
_slug: slug,
|
||
name: f.name ?? slug,
|
||
image: refToSlug(f.image) ?? "",
|
||
caption: f.caption ?? "",
|
||
layout: {
|
||
mobile: layout.mobile ?? "12",
|
||
tablet: layout.tablet,
|
||
desktop: layout.desktop,
|
||
spaceBottom: layout.spaceBottom ?? 0,
|
||
},
|
||
...(f.maxWidth != null && { maxWidth: f.maxWidth }),
|
||
...(f.aspectRatio != null && { aspectRatio: f.aspectRatio }),
|
||
});
|
||
});
|
||
entries.forEach((e) => {
|
||
if (e.sys?.contentType?.id === "image" && !idToSlug.has(e.sys.id)) {
|
||
const slug = getSlug(e, "image");
|
||
const f = e.fields || {};
|
||
const layout = f.layout?.fields || f.layout || {};
|
||
writeJson5(path.join(CONTENT_DE, "image", slug + ".json5"), {
|
||
_slug: slug,
|
||
name: f.name ?? slug,
|
||
image: refToSlug(f.image) ?? "",
|
||
caption: f.caption ?? "",
|
||
layout: { mobile: layout.mobile ?? "12", tablet: layout.tablet, desktop: layout.desktop, spaceBottom: layout.spaceBottom ?? 0 },
|
||
...(f.maxWidth != null && { maxWidth: f.maxWidth }),
|
||
...(f.aspectRatio != null && { aspectRatio: f.aspectRatio }),
|
||
});
|
||
}
|
||
});
|
||
console.log("image:", Array.from(entries.values()).filter((e) => e.sys?.contentType?.id === "image").length);
|
||
}
|
||
|
||
// ─── 4f) ImageGallery ───────────────────────────────────────────────────
|
||
if (run("image_gallery")) {
|
||
(byType.imageGallery?.items || []).forEach((entry) => {
|
||
const slug = getSlug(entry, "imageGallery");
|
||
const f = entry.fields || {};
|
||
const layout = f.layout?.fields || f.layout || {};
|
||
const imageSlugs = (f.images || []).map(refToSlug).filter(Boolean);
|
||
writeJson5(path.join(CONTENT_DE, "image_gallery", slug + ".json5"), {
|
||
_slug: slug,
|
||
name: f.name ?? slug,
|
||
images: imageSlugs,
|
||
layout: {
|
||
mobile: layout.mobile ?? "12",
|
||
tablet: layout.tablet,
|
||
desktop: layout.desktop,
|
||
spaceBottom: layout.spaceBottom ?? 0,
|
||
},
|
||
...(f.description != null && f.description !== "" && { description: f.description }),
|
||
});
|
||
});
|
||
entries.forEach((e) => {
|
||
if ((e.sys?.contentType?.id === "imageGallery" || e.sys?.contentType?.id === "imgGallery") && !idToSlug.has(e.sys.id)) {
|
||
const slug = getSlug(e, "imageGallery");
|
||
const f = e.fields || {};
|
||
const layout = f.layout?.fields || f.layout || {};
|
||
const imageSlugs = (f.images || []).map(refToSlug).filter(Boolean);
|
||
writeJson5(path.join(CONTENT_DE, "image_gallery", slug + ".json5"), {
|
||
_slug: slug,
|
||
name: f.name ?? slug,
|
||
images: imageSlugs,
|
||
layout: { mobile: layout.mobile ?? "12", tablet: layout.tablet, desktop: layout.desktop, spaceBottom: layout.spaceBottom ?? 0 },
|
||
...(f.description != null && f.description !== "" && { description: f.description }),
|
||
});
|
||
}
|
||
});
|
||
console.log("image_gallery:", Array.from(entries.values()).filter((e) => e.sys?.contentType?.id === "imageGallery" || e.sys?.contentType?.id === "imgGallery").length);
|
||
}
|
||
|
||
// ─── 4g) YoutubeVideo ───────────────────────────────────────────────────
|
||
if (run("youtube_video")) {
|
||
(byType.youtubeVideo?.items || []).forEach((entry) => {
|
||
const slug = getSlug(entry, "youtubeVideo");
|
||
const f = entry.fields || {};
|
||
const layout = f.layout?.fields || f.layout || {};
|
||
writeJson5(path.join(CONTENT_DE, "youtube_video", slug + ".json5"), {
|
||
_slug: slug,
|
||
id: f.id ?? slug,
|
||
youtubeId: f.youtubeId ?? "",
|
||
...(f.params != null && f.params !== "" && { params: f.params }),
|
||
...(f.title != null && f.title !== "" && { title: f.title }),
|
||
...(f.description != null && f.description !== "" && { description: f.description }),
|
||
layout: {
|
||
mobile: layout.mobile ?? "12",
|
||
tablet: layout.tablet,
|
||
desktop: layout.desktop,
|
||
spaceBottom: layout.spaceBottom ?? 0,
|
||
},
|
||
});
|
||
});
|
||
entries.forEach((e) => {
|
||
if (e.sys?.contentType?.id === "youtubeVideo" && !idToSlug.has(e.sys.id)) {
|
||
const slug = getSlug(e, "youtubeVideo");
|
||
const f = e.fields || {};
|
||
const layout = f.layout?.fields || f.layout || {};
|
||
writeJson5(path.join(CONTENT_DE, "youtube_video", slug + ".json5"), {
|
||
_slug: slug,
|
||
id: f.id ?? slug,
|
||
youtubeId: f.youtubeId ?? "",
|
||
...(f.params != null && f.params !== "" && { params: f.params }),
|
||
...(f.title != null && f.title !== "" && { title: f.title }),
|
||
...(f.description != null && f.description !== "" && { description: f.description }),
|
||
layout: { mobile: layout.mobile ?? "12", tablet: layout.tablet, desktop: layout.desktop, spaceBottom: layout.spaceBottom ?? 0 },
|
||
});
|
||
}
|
||
});
|
||
console.log("youtube_video:", Array.from(entries.values()).filter((e) => e.sys?.contentType?.id === "youtubeVideo").length);
|
||
}
|
||
|
||
if (ONLY.size) {
|
||
console.log("Fertig. Nur migriert:", [...ONLY].sort().join(", "));
|
||
return;
|
||
}
|
||
|
||
// ─── 5) Link-List (componentLinkList) ───────────────────────────────────
|
||
function writeLinkList(entry) {
|
||
const slug = getSlug(entry, "componentLinkList");
|
||
const f = entry.fields || {};
|
||
const linkSlugs = (f.links || []).map((l) => refToSlug(l)).filter(Boolean);
|
||
writeJson5(path.join(CONTENT_DE, "link_list", slug + ".json5"), {
|
||
_slug: slug,
|
||
headline: f.headline ?? "",
|
||
links: linkSlugs,
|
||
});
|
||
}
|
||
(byType.componentLinkList?.items || []).forEach(writeLinkList);
|
||
entries.forEach((e) => {
|
||
if (e.sys?.contentType?.id === "componentLinkList" && !idToSlug.has(e.sys.id)) writeLinkList(e);
|
||
});
|
||
console.log("link_list:", Array.from(entries.values()).filter((e) => e.sys?.contentType?.id === "componentLinkList").length);
|
||
|
||
// ─── 6) FullwidthBanner ────────────────────────────────────────────────
|
||
function extractFullwidthBanner(entry) {
|
||
const slug = getSlug(entry, "fullwidthBanner");
|
||
const f = entry.fields || {};
|
||
const img = f.img;
|
||
let image = [];
|
||
if (img?.fields?.file?.url) {
|
||
let u = img.fields.file.url;
|
||
if (!u.startsWith("http")) u = "https:" + u;
|
||
image = [u];
|
||
}
|
||
writeJson5(path.join(CONTENT_DE, "fullwidth_banner", slug + ".json5"), {
|
||
_slug: slug,
|
||
name: f.id ?? slug,
|
||
variant: f.variant ?? "light",
|
||
headline: f.headline ?? "",
|
||
subheadline: f.subheadline ?? "",
|
||
text: f.text ?? "",
|
||
image,
|
||
});
|
||
return slug;
|
||
}
|
||
(byType.fullwidthBanner?.items || []).forEach(extractFullwidthBanner);
|
||
entries.forEach((e) => {
|
||
if (e.sys?.contentType?.id === "fullwidthBanner" && !idToSlug.has(e.sys.id)) extractFullwidthBanner(e);
|
||
});
|
||
console.log("fullwidth_banner:", Array.from(entries.values()).filter((e) => e.sys?.contentType?.id === "fullwidthBanner").length);
|
||
|
||
// ─── 7) PostOverview (componentPostOverview) ────────────────────────────
|
||
(byType.componentPostOverview?.items || []).forEach((entry) => {
|
||
const slug = getSlug(entry, "componentPostOverview");
|
||
const f = entry.fields || {};
|
||
const tagSlugs = (f.filterByTag || []).map(refToSlug).filter(Boolean);
|
||
writeJson5(path.join(CONTENT_DE, "post_overview", slug + ".json5"), {
|
||
_slug: slug,
|
||
id: f.id ?? slug,
|
||
headline: f.headline ?? "",
|
||
allPosts: f.allPosts ?? true,
|
||
filterByTag: tagSlugs,
|
||
});
|
||
});
|
||
entries.forEach((e) => {
|
||
if (e.sys?.contentType?.id === "componentPostOverview" && !idToSlug.has(e.sys.id)) {
|
||
const slug = getSlug(e, "componentPostOverview");
|
||
const f = e.fields || {};
|
||
const tagSlugs = (f.filterByTag || []).map(refToSlug).filter(Boolean);
|
||
writeJson5(path.join(CONTENT_DE, "post_overview", slug + ".json5"), {
|
||
_slug: slug,
|
||
id: f.id ?? slug,
|
||
headline: f.headline ?? "",
|
||
allPosts: f.allPosts ?? true,
|
||
filterByTag: tagSlugs,
|
||
});
|
||
}
|
||
});
|
||
console.log("post_overview:", Array.from(entries.values()).filter((e) => e.sys?.contentType?.id === "componentPostOverview").length);
|
||
|
||
// ─── 8) TextFragment + SearchableText (optional, falls verwendet) ────────
|
||
(byType.textFragment?.items || []).forEach((entry) => {
|
||
const slug = getSlug(entry, "textFragment");
|
||
const f = entry.fields || {};
|
||
const tagSlugs = (f.tags || []).map(refToSlug).filter(Boolean);
|
||
writeJson5(path.join(CONTENT_DE, "text_fragment", slug + ".json5"), {
|
||
_slug: slug,
|
||
id: f.id ?? slug,
|
||
title: f.title ?? "",
|
||
text: f.text ?? "",
|
||
tags: tagSlugs,
|
||
});
|
||
});
|
||
(byType.componentSearchableText?.items || []).forEach((entry) => {
|
||
const slug = getSlug(entry, "componentSearchableText");
|
||
const f = entry.fields || {};
|
||
const fragSlugs = (f.textFragments || []).map(refToSlug).filter(Boolean);
|
||
const tagSlugs = (f.tagWhitelist || []).map(refToSlug).filter(Boolean);
|
||
writeJson5(path.join(CONTENT_DE, "searchable_text", slug + ".json5"), {
|
||
_slug: slug,
|
||
id: f.id ?? slug,
|
||
textFragments: fragSlugs,
|
||
tagWhitelist: tagSlugs,
|
||
title: f.title,
|
||
description: f.description,
|
||
});
|
||
});
|
||
|
||
// ─── 9) Post ───────────────────────────────────────────────────────────
|
||
(byType.post?.items || []).forEach((entry) => {
|
||
const slug = getSlug(entry, "post");
|
||
const f = entry.fields || {};
|
||
const row1Content = (f.row1Content || []).map(refToSlug).filter(Boolean);
|
||
const obj = {
|
||
_slug: slug,
|
||
slug: f.slug ?? "/" + slug,
|
||
linkName: f.linkName ?? "",
|
||
headline: f.headline ?? "",
|
||
subheadline: f.subheadline ?? "",
|
||
excerpt: f.excerpt ?? "",
|
||
...(entry.sys?.createdAt && { created: entry.sys.createdAt }),
|
||
postImage: refToSlug(f.postImage) || null,
|
||
postTag: (f.postTag || []).map(refToSlug).filter(Boolean),
|
||
important: f.important ?? false,
|
||
content: f.content ?? "",
|
||
showCommentSection: f.showCommentSection !== false,
|
||
row1JustifyContent: f.row1JustifyContent ?? "start",
|
||
row1AlignItems: f.row1AlignItems ?? "start",
|
||
seoTitle: f.seoTitle ?? "",
|
||
seoDescription: f.seoDescription ?? "",
|
||
seoMetaRobots: f.seoMetaRobots ?? "index, follow",
|
||
};
|
||
if (obj.postImage == null) delete obj.postImage;
|
||
if (row1Content.length) obj.row1Content = row1Content;
|
||
writeJson5(path.join(CONTENT_DE, "post", slug + ".json5"), obj);
|
||
});
|
||
console.log("post:", (byType.post?.items || []).length);
|
||
|
||
// ─── 10) Page (alle Page-Einträge aus entries, damit auch nur in Nav referenzierte) ───
|
||
const pageEntries = Array.from(entries.values()).filter((e) => (e.sys?.contentType?.id || e.sys?.contentType?.sys?.id) === "page");
|
||
pageEntries.forEach((entry) => {
|
||
const slug = getSlug(entry, "page");
|
||
const f = entry.fields || {};
|
||
const row1Content = (f.row1Content || [])
|
||
.filter((ref) => ref?.sys?.contentType && SUPPORTED_ROW_COMPONENTS.has(ref.sys.contentType.sys?.id || ref.sys.contentType.id))
|
||
.map(refToSlug)
|
||
.filter(Boolean);
|
||
const name = slug === "home" || f.slug === "/" ? "home" : slug;
|
||
const pageSlug = f.slug ?? (name === "home" ? "/" : "/" + name);
|
||
writeJson5(path.join(CONTENT_DE, "page", slug + ".json5"), {
|
||
_slug: slug,
|
||
slug: pageSlug,
|
||
name,
|
||
linkName: f.linkName ?? "",
|
||
headline: f.headline ?? "",
|
||
subheadline: f.subheadline ?? "",
|
||
seoTitle: f.seoTitle ?? "",
|
||
seoDescription: f.seoDescription ?? "",
|
||
seoMetaRobots: f.seoMetaRobots ?? "index, follow",
|
||
row1JustifyContent: f.row1JustifyContent ?? "start",
|
||
row1AlignItems: f.row1AlignItems ?? "start",
|
||
row1Content,
|
||
...(refToSlug(f.topFullwidthBanner) ? { topFullwidthBanner: refToSlug(f.topFullwidthBanner) } : {}),
|
||
});
|
||
});
|
||
console.log("page:", pageEntries.length);
|
||
|
||
// ─── 11) Footer ────────────────────────────────────────────────────────
|
||
(byType.footer?.items || []).forEach((entry) => {
|
||
const slug = getSlug(entry, "footer");
|
||
const f = entry.fields || {};
|
||
const row1Content = (f.row1Content || []).map(refToSlug).filter(Boolean);
|
||
writeJson5(path.join(CONTENT_DE, "footer", slug + ".json5"), {
|
||
_slug: slug,
|
||
id: f.id ?? slug,
|
||
row1JustifyContent: f.row1JustifyContent ?? "start",
|
||
row1AlignItems: f.row1AlignItems ?? "start",
|
||
row1Content,
|
||
});
|
||
});
|
||
|
||
// ─── 12) Navigation ─────────────────────────────────────────────────────
|
||
(byType.navigation?.items || []).forEach((entry) => {
|
||
const slug = getSlug(entry, "navigation");
|
||
const f = entry.fields || {};
|
||
const links = (f.links || []).map((p) => refToSlug(p)).filter(Boolean);
|
||
const internal = f.id ?? (slug === "navigation-header" ? "navigation-header" : slug);
|
||
writeJson5(path.join(CONTENT_DE, "navigation", (f.id || slug) + ".json5"), {
|
||
_slug: f.id || slug,
|
||
name: f.id ?? slug,
|
||
internal,
|
||
links,
|
||
});
|
||
});
|
||
|
||
// ─── 13) PageConfig ─────────────────────────────────────────────────────
|
||
const pageConfigItems = byType.pageConfig?.items || [];
|
||
const defaultFooterText = "© Bürgerinitiative Vachdorf. Alle Rechte vorbehalten.";
|
||
pageConfigItems.forEach((entry) => {
|
||
const slug = "default";
|
||
const f = entry.fields || {};
|
||
const logoRef = f.logo;
|
||
const logoSlug = logoRef ? (logoRef.sys?.type === "Asset" ? idToSlug.get(logoRef.sys?.id) : null) : null;
|
||
writeJson5(path.join(CONTENT_DE, "page_config", slug + ".json5"), {
|
||
_slug: slug,
|
||
logo: logoSlug ?? "logo",
|
||
footerText1: defaultFooterText,
|
||
seoTitle: f.seoTitle ?? "Bürgerinitiative Vachdorf / $1",
|
||
seoDescription: f.seoDescription ?? "$1 - Bürgerinitiative Vachdorf",
|
||
website: f.website ?? "https://www.windwiderstand.de",
|
||
});
|
||
});
|
||
if (pageConfigItems.length === 0) {
|
||
writeJson5(path.join(CONTENT_DE, "page_config", "default.json5"), {
|
||
_slug: "default",
|
||
logo: "logo",
|
||
footerText1: defaultFooterText,
|
||
seoTitle: "Bürgerinitiative Vachdorf / $1",
|
||
seoDescription: "$1 - Bürgerinitiative Vachdorf",
|
||
website: "https://www.windwiderstand.de",
|
||
});
|
||
}
|
||
|
||
// ─── 14) Campaign ───────────────────────────────────────────────────────
|
||
(byType.campaign?.items || []).forEach((entry) => {
|
||
const slug = getSlug(entry, "campaign");
|
||
const f = entry.fields || {};
|
||
writeJson5(path.join(CONTENT_DE, "campaign", slug + ".json5"), {
|
||
_slug: slug,
|
||
campaignName: f.campaingName ?? f.campaignName ?? slug,
|
||
urlPattern: f.urlPatter ?? f.urlPattern ?? "/",
|
||
selector: f.selector ?? "body",
|
||
insertHtml: f.insertHtml ?? "beforeend",
|
||
timeUntil: f.timeUntil ?? "",
|
||
html: f.html ?? "",
|
||
javascript: f.javascript ?? "",
|
||
css: f.css ?? "",
|
||
});
|
||
});
|
||
|
||
// ─── 15) Campaigns ─────────────────────────────────────────────────────
|
||
(byType.campaigns?.items || []).forEach((entry) => {
|
||
const slug = getSlug(entry, "campaigns");
|
||
const f = entry.fields || {};
|
||
const campaignSlugs = (f.campaings || f.campaigns || []).map(refToSlug).filter(Boolean);
|
||
writeJson5(path.join(CONTENT_DE, "campaigns", (f.id || slug) + ".json5"), {
|
||
_slug: f.id || slug,
|
||
id: f.id ?? slug,
|
||
campaigns: campaignSlugs,
|
||
enable: f.enable !== false,
|
||
});
|
||
});
|
||
|
||
console.log("Fertig. Content in", CONTENT_DE);
|
||
}
|
||
|
||
main();
|