From a55680ed41b9f411b2c2d439e7a94c81040968c2 Mon Sep 17 00:00:00 2001 From: Marc Mintel Date: Sun, 22 Feb 2026 11:22:35 +0100 Subject: [PATCH] fix(mdx): support recursive product file searching for OG images and routing --- lib/mdx.ts | 162 +++++++++++++++++++++++++++++------------------------ 1 file changed, 89 insertions(+), 73 deletions(-) diff --git a/lib/mdx.ts b/lib/mdx.ts index 6e5b4d91..7ea420eb 100644 --- a/lib/mdx.ts +++ b/lib/mdx.ts @@ -26,42 +26,43 @@ export async function getProductMetadata( const fileSlug = await mapSlugToFileSlug(slug, locale); const productsDir = path.join(process.cwd(), 'data', 'products', locale); - // Try exact slug first - let filePath = path.join(productsDir, `${fileSlug}.mdx`); + if (!fs.existsSync(productsDir)) return null; - if (!fs.existsSync(filePath)) { - // Try with -2 suffix (common in the dumped files) - filePath = path.join(productsDir, `${fileSlug}-2.mdx`); - } - - if (!fs.existsSync(filePath)) { - // Fallback to English if locale is not 'en' - if (locale !== 'en') { - const enProductsDir = path.join(process.cwd(), 'data', 'products', 'en'); - let enFilePath = path.join(enProductsDir, `${fileSlug}.mdx`); - if (!fs.existsSync(enFilePath)) { - enFilePath = path.join(enProductsDir, `${fileSlug}-2.mdx`); - } - - if (fs.existsSync(enFilePath)) { - const fileContent = fs.readFileSync(enFilePath, 'utf8'); - const { data } = matter(fileContent); - return { - slug: fileSlug, - frontmatter: { - ...data, - isFallback: true, - } as ProductFrontmatter & { isFallback?: boolean }, - }; + // Recursive search for the file + const findFile = (dir: string): string | null => { + const files = fs.readdirSync(dir); + for (const file of files) { + const fullPath = path.join(dir, file); + const stat = fs.statSync(fullPath); + if (stat.isDirectory()) { + const found = findFile(fullPath); + if (found) return found; + } else if (file === `${fileSlug}.mdx` || file === `${fileSlug}-2.mdx`) { + return fullPath; } } - } else { + return null; + }; + + let filePath = findFile(productsDir); + + if (!filePath && locale !== 'en') { + // Fallback to English + const enProductsDir = path.join(process.cwd(), 'data', 'products', 'en'); + if (fs.existsSync(enProductsDir)) { + filePath = findFile(enProductsDir); + } + } + + if (filePath && fs.existsSync(filePath)) { const fileContent = fs.readFileSync(filePath, 'utf8'); const { data } = matter(fileContent); - return { slug: fileSlug, - frontmatter: data as ProductFrontmatter, + frontmatter: { + ...data, + isFallback: filePath.includes('/en/'), + } as any, }; } @@ -73,68 +74,83 @@ export async function getProductBySlug(slug: string, locale: string): Promise { + const files = fs.readdirSync(dir); + for (const file of files) { + const fullPath = path.join(dir, file); + const stat = fs.statSync(fullPath); + if (stat.isDirectory()) { + const found = findFile(fullPath); + if (found) return found; + } else if (file === `${fileSlug}.mdx` || file === `${fileSlug}-2.mdx`) { + return fullPath; } } - } else { + return null; + }; + + let filePath = findFile(productsDir); + let isFallback = false; + + if (!filePath && locale !== 'en') { + // Fallback to English + const enProductsDir = path.join(process.cwd(), 'data', 'products', 'en'); + if (fs.existsSync(enProductsDir)) { + filePath = findFile(enProductsDir); + if (filePath) isFallback = true; + } + } + + if (filePath && fs.existsSync(filePath)) { const fileContent = fs.readFileSync(filePath, 'utf8'); const { data, content } = matter(fileContent); - - product = { + const product = { slug: fileSlug, - frontmatter: data as ProductFrontmatter, + frontmatter: { + ...data, + isFallback, + } as any, content, }; - } - // Filter out products without images - if ( - product && - (!product.frontmatter.images || + // Filter out products without images + if ( + !product.frontmatter.images || product.frontmatter.images.length === 0 || - !product.frontmatter.images[0]) - ) { - return null; + !product.frontmatter.images[0] + ) { + return null; + } + + return product; } - return product; + return null; } export async function getAllProductSlugs(locale: string): Promise { const productsDir = path.join(process.cwd(), 'data', 'products', locale); if (!fs.existsSync(productsDir)) return []; - const files = fs.readdirSync(productsDir); - return files.filter((file) => file.endsWith('.mdx')).map((file) => file.replace(/\.mdx$/, '')); + const slugs: string[] = []; + const walk = (dir: string) => { + const files = fs.readdirSync(dir); + for (const file of files) { + const fullPath = path.join(dir, file); + const stat = fs.statSync(fullPath); + if (stat.isDirectory()) { + walk(fullPath); + } else if (file.endsWith('.mdx')) { + slugs.push(file.replace(/\.mdx$/, '')); + } + } + }; + + walk(productsDir); + return slugs; } export async function getAllProducts(locale: string): Promise {