diff --git a/redirects.ts b/redirects.ts index 8c311736..14762816 100644 --- a/redirects.ts +++ b/redirects.ts @@ -194,13 +194,36 @@ export function createRedirects(existingPath: string, basePath: string = ''): st // Extract the path after /release-notes/ const subpath = existingPath.replace('/release-notes/', ''); + // Handle old version naming (4.tucker -> v4-tucker, etc.) + let oldSubpath = subpath; + const versionMap: Record = { + 'v1-alby': '1.alby', + 'v2-penny': '2.penny', + 'v3-monkey': '3.monkey', + 'v4-tucker': '4.tucker', + }; + + // Check if the path starts with a new version name and convert to old format + for (const [newName, oldName] of Object.entries(versionMap)) { + if (subpath.startsWith(`${newName}/`) || subpath === newName) { + oldSubpath = subpath.replace(newName, oldName); + break; + } + } + // Add redirects from current version docs (4.6 is served at /docs/) redirects.push(`/docs/technical-details/release-notes/${subpath}`); + if (oldSubpath !== subpath) { + redirects.push(`/docs/technical-details/release-notes/${oldSubpath}`); + } // Also redirect from all versioned docs paths const versions = ['4.1', '4.2', '4.3', '4.4', '4.5', '4.6']; for (const version of versions) { redirects.push(`/docs/${version}/technical-details/release-notes/${subpath}`); + if (oldSubpath !== subpath) { + redirects.push(`/docs/${version}/technical-details/release-notes/${oldSubpath}`); + } } } diff --git a/scripts/postbuild.js b/scripts/postbuild.js index bdf67acd..c1c35ef0 100644 --- a/scripts/postbuild.js +++ b/scripts/postbuild.js @@ -54,6 +54,65 @@ async function generateIndexHtmlFiles(outDir) { } } +// Copy redirect index.html files to .html ONLY for old release notes paths +// This ensures redirects work with simple HTTP servers like `npm run serve` +// Example: docs/technical-details/release-notes/4.tucker/4.4.0/index.html +// -> docs/technical-details/release-notes/4.tucker/4.4.0.html +async function generateReleaseNotesRedirectHtmlFiles(outDir) { + console.log('Post-build: Creating .html redirect files for old release notes paths...'); + + const redirectBase = path.join(outDir, 'docs', 'technical-details', 'release-notes'); + + try { + await fs.stat(redirectBase); + } catch { + console.log('Post-build: No release notes redirects found, skipping'); + return; + } + + // Walk through all directories recursively + async function* walkDirs(dir) { + const dirents = await fs.readdir(dir, { withFileTypes: true }); + for (const dirent of dirents) { + if (dirent.isDirectory()) { + const res = path.resolve(dir, dirent.name); + yield res; + yield* walkDirs(res); + } + } + } + + const processedFiles = []; + + for await (const dirPath of walkDirs(redirectBase)) { + // Check if this directory has an index.html redirect file + const indexPath = path.join(dirPath, 'index.html'); + try { + const content = await fs.readFile(indexPath, 'utf8'); + // Check if it's a redirect file (contains meta refresh) + if (content.includes('meta http-equiv="refresh"')) { + // Create a sibling .html file with the same content + const dirName = path.basename(dirPath); + const siblingHtmlPath = path.join(path.dirname(dirPath), `${dirName}.html`); + await fs.copyFile(indexPath, siblingHtmlPath); + processedFiles.push(`${dirName}/index.html → ${dirName}.html`); + } + } catch { + // No index.html or other error, skip + } + } + + if (processedFiles.length > 0) { + console.log(`Post-build: Created ${processedFiles.length} .html redirect files`); + // Uncomment to see details: + // processedFiles.forEach(f => console.log(` - ${f}`)); + } else { + console.log('Post-build: No .html redirect files needed'); + } +} + // Run the post-processing const buildDir = path.join(__dirname, '..', 'build'); -generateIndexHtmlFiles(buildDir).catch(console.error); +generateIndexHtmlFiles(buildDir) + .then(() => generateReleaseNotesRedirectHtmlFiles(buildDir)) + .catch(console.error);