mirror of
https://github.com/svemagie/blog-eleventy-indiekit.git
synced 2026-04-02 16:44:56 +02:00
- Fix fallback logic (empty object is truthy) - Try multiple paths for Docker and local dev - Add debug logging for file discovery Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
158 lines
4.5 KiB
JavaScript
158 lines
4.5 KiB
JavaScript
/**
|
|
* URL Aliases for Webmention Recovery
|
|
*
|
|
* Maps new URLs to their old URLs so webmentions from previous
|
|
* URL structures can be displayed on current pages.
|
|
*
|
|
* Sources:
|
|
* - redirects.map.rmendes (micro.blog: /YYYY/MM/DD/slug.html → /notes/...)
|
|
* - old-blog-redirects.map.rmendes (Known/WP: /YYYY/slug → /content/...)
|
|
*/
|
|
|
|
import { readFileSync, existsSync } from "fs";
|
|
import { resolve, dirname } from "path";
|
|
import { fileURLToPath } from "url";
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const siteUrl = process.env.SITE_URL || "https://example.com";
|
|
|
|
/**
|
|
* Parse a redirect map file into URL mappings
|
|
* Format: old_path new_path;
|
|
*/
|
|
function parseRedirectMap(filePath) {
|
|
const aliases = {};
|
|
|
|
if (!existsSync(filePath)) {
|
|
console.log(`[urlAliases] File not found: ${filePath}`);
|
|
return aliases;
|
|
}
|
|
|
|
try {
|
|
const content = readFileSync(filePath, "utf-8");
|
|
const lines = content.split("\n").filter((line) => {
|
|
const trimmed = line.trim();
|
|
return trimmed && !trimmed.startsWith("#");
|
|
});
|
|
|
|
for (const line of lines) {
|
|
// Format: /old/path /new/path;
|
|
const match = line.match(/^(\S+)\s+(\S+);?$/);
|
|
if (match) {
|
|
const [, oldPath, newPath] = match;
|
|
// Normalize paths (remove trailing slashes, ensure leading slash)
|
|
const normalizedNew = newPath.replace(/;$/, "").replace(/\/$/, "");
|
|
const normalizedOld = oldPath.replace(/\/$/, "");
|
|
|
|
// Map new URL → array of old URLs
|
|
if (!aliases[normalizedNew]) {
|
|
aliases[normalizedNew] = [];
|
|
}
|
|
aliases[normalizedNew].push(normalizedOld);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error(`[urlAliases] Error parsing ${filePath}:`, error.message);
|
|
}
|
|
|
|
return aliases;
|
|
}
|
|
|
|
/**
|
|
* Merge multiple alias maps
|
|
*/
|
|
function mergeAliases(...maps) {
|
|
const merged = {};
|
|
for (const map of maps) {
|
|
for (const [newUrl, oldUrls] of Object.entries(map)) {
|
|
if (!merged[newUrl]) {
|
|
merged[newUrl] = [];
|
|
}
|
|
merged[newUrl].push(...oldUrls);
|
|
}
|
|
}
|
|
return merged;
|
|
}
|
|
|
|
// Parse redirect maps from /app/pkg (Docker) or parent directory (local dev)
|
|
// In Docker: eleventy-site is at /app/pkg/eleventy-site, maps are at /app/pkg/
|
|
// In local dev: maps might be at ../
|
|
const pkgRoot = resolve(__dirname, "../..");
|
|
|
|
// Helper to find first existing file
|
|
function findFile(candidates) {
|
|
for (const path of candidates) {
|
|
if (existsSync(path)) {
|
|
console.log(`[urlAliases] Found: ${path}`);
|
|
return path;
|
|
}
|
|
}
|
|
console.log(`[urlAliases] No file found in: ${candidates.join(", ")}`);
|
|
return null;
|
|
}
|
|
|
|
// Try multiple possible locations for each map type
|
|
const microblogMapPath = findFile([
|
|
resolve(pkgRoot, "redirects.map"),
|
|
resolve(pkgRoot, "redirects.map.rmendes"),
|
|
resolve(__dirname, "../../redirects.map"),
|
|
]);
|
|
|
|
const knownMapPath = findFile([
|
|
resolve(pkgRoot, "old-blog-redirects.map"),
|
|
resolve(pkgRoot, "old-blog-redirects.map.rmendes"),
|
|
resolve(__dirname, "../../old-blog-redirects.map"),
|
|
]);
|
|
|
|
const microblogAliases = microblogMapPath ? parseRedirectMap(microblogMapPath) : {};
|
|
const knownAliases = knownMapPath ? parseRedirectMap(knownMapPath) : {};
|
|
|
|
const allAliases = mergeAliases(microblogAliases, knownAliases);
|
|
|
|
// Log summary
|
|
const totalMappings = Object.keys(allAliases).length;
|
|
const totalOldUrls = Object.values(allAliases).reduce((sum, urls) => sum + urls.length, 0);
|
|
console.log(`[urlAliases] Loaded ${totalMappings} URL mappings with ${totalOldUrls} old URLs`);
|
|
|
|
export default {
|
|
// The merged alias map: new URL → [old URLs]
|
|
aliases: allAliases,
|
|
|
|
// Site URL for building absolute URLs
|
|
siteUrl,
|
|
|
|
/**
|
|
* Get all URLs (old and new) that should be checked for webmentions
|
|
* @param {string} url - Current page URL (relative)
|
|
* @returns {string[]} - Array of absolute URLs to check
|
|
*/
|
|
getAllUrls(url) {
|
|
const normalizedUrl = url.replace(/\/$/, "");
|
|
const urls = [
|
|
`${siteUrl}${url}`,
|
|
`${siteUrl}${normalizedUrl}`,
|
|
];
|
|
|
|
// Add old URL variations
|
|
const oldUrls = allAliases[normalizedUrl] || [];
|
|
for (const oldUrl of oldUrls) {
|
|
urls.push(`${siteUrl}${oldUrl}`);
|
|
// Also try with trailing slash
|
|
urls.push(`${siteUrl}${oldUrl}/`);
|
|
}
|
|
|
|
// Deduplicate
|
|
return [...new Set(urls)];
|
|
},
|
|
|
|
/**
|
|
* Get just the old URLs for a given new URL
|
|
* @param {string} url - Current page URL (relative)
|
|
* @returns {string[]} - Array of old relative URLs
|
|
*/
|
|
getOldUrls(url) {
|
|
const normalizedUrl = url.replace(/\/$/, "");
|
|
return allAliases[normalizedUrl] || [];
|
|
},
|
|
};
|