From 8ba3cc0d2f75699f2664ededc95e0ace46fbb089 Mon Sep 17 00:00:00 2001 From: Edinaldo Junior Date: Thu, 14 Aug 2025 18:07:41 -0300 Subject: [PATCH 1/9] feat: copy feature v2 --- components/copy-page.tsx | 45 ++++++---- package.json | 7 +- scripts/process-mdx-to-md.js | 163 +++++++++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+), 19 deletions(-) create mode 100644 scripts/process-mdx-to-md.js diff --git a/components/copy-page.tsx b/components/copy-page.tsx index a2a613ed..8c0ef383 100644 --- a/components/copy-page.tsx +++ b/components/copy-page.tsx @@ -12,6 +12,7 @@ const CopyPage: React.FC = () => { const [isOpen, setIsOpen] = useState(false); const [isCopied, setIsCopied] = useState(false); const dropdownRef = useRef(null); + const router = useRouter(); // Close dropdown when clicking outside useEffect(() => { @@ -27,14 +28,21 @@ const CopyPage: React.FC = () => { const copyPageAsMarkdown = async () => { try { - // Get the current page content - const pageContent = document.querySelector('main')?.innerText || ''; - const pageTitle = document.title; + const currentPath = router.asPath; - // Create markdown content - const markdownContent = `# ${pageTitle}\n\n${pageContent}`; + // Remove query params and hash from path + const cleanPath = currentPath.split('?')[0].split('#')[0]; - await navigator.clipboard.writeText(markdownContent); + // Convert path to static file URL + const mdUrl = cleanPath === '/' ? '/pages/index.md' : `/pages${cleanPath}.md`; + const response = await fetch(mdUrl); + + if (!response.ok) { + throw new Error('Failed to fetch MDX content'); + } + + const mdContent = await response.text(); + await navigator.clipboard.writeText(mdContent); // Show success feedback setIsCopied(true); @@ -48,21 +56,26 @@ const CopyPage: React.FC = () => { }; const viewAsMarkdown = () => { - const pageContent = document.querySelector('main')?.innerText || ''; - const pageTitle = document.title; - const markdownContent = `# ${pageTitle}\n\n${pageContent}`; + const currentPath = router.asPath; - // Open in new window/tab - const blob = new Blob([markdownContent], { type: 'text/markdown' }); - const url = URL.createObjectURL(blob); - window.open(url, '_blank'); - URL.revokeObjectURL(url); + // Remove query params and hash from path + const cleanPath = currentPath.split('?')[0].split('#')[0]; + + // Open the .md file directly (no blob needed!) + const mdUrl = cleanPath === '/' ? '/pages/index.md' : `/pages${cleanPath}.md`; + window.open(mdUrl, '_blank'); setIsOpen(false); }; const openInAI = (platform: 'chatgpt' | 'claude') => { - const currentUrl = window.location.href; - const prompt = `I'm building with GenLayer - can you read this docs page ${currentUrl} so I can ask you questions about it?`; + const currentPath = router.asPath; + const cleanPath = currentPath.split('?')[0].split('#')[0]; + + // Use the .md file URL instead of the docs page URL + const mdUrl = cleanPath === '/' ? '/pages/index.md' : `/pages${cleanPath}.md`; + const fullMdUrl = `${window.location.origin}${mdUrl}`; + + const prompt = `I'm building with GenLayer - can you read this markdown file ${fullMdUrl} so I can ask you questions about it?`; const encodedPrompt = encodeURIComponent(prompt); const urls = { diff --git a/package.json b/package.json index 75b3c576..b19d92fe 100644 --- a/package.json +++ b/package.json @@ -3,14 +3,15 @@ "version": "0.0.1", "description": "GenLayer documentation", "scripts": { - "dev": "npm run node-generate-changelog && npm run node-update-setup-guide && npm run node-update-config && npm run node-generate-api-docs && node scripts/generate-full-docs.js && next dev", - "build": "npm run node-generate-changelog && npm run node-update-setup-guide && npm run node-update-config && npm run node-generate-api-docs && node scripts/generate-full-docs.js && next build", + "dev": "npm run node-generate-changelog && npm run node-update-setup-guide && npm run node-update-config && npm run node-generate-api-docs && node scripts/generate-full-docs.js && npm run sync-mdx && next dev", + "build": "npm run node-generate-changelog && npm run node-update-setup-guide && npm run node-update-config && npm run node-generate-api-docs && node scripts/generate-full-docs.js && npm run sync-mdx && next build", "start": "next start", "generate-sitemap": "node scripts/generate-sitemap-xml.js", "node-generate-changelog": "node scripts/generate-changelog.js", "node-generate-api-docs": "node scripts/generate-api-docs.js", "node-update-setup-guide": "node scripts/update-setup-guide-versions.js", - "node-update-config": "node scripts/update-config-in-setup-guide.js" + "node-update-config": "node scripts/update-config-in-setup-guide.js", + "sync-mdx": "node scripts/process-mdx-to-md.js" }, "repository": { "type": "git", diff --git a/scripts/process-mdx-to-md.js b/scripts/process-mdx-to-md.js new file mode 100644 index 00000000..fcfdc238 --- /dev/null +++ b/scripts/process-mdx-to-md.js @@ -0,0 +1,163 @@ +const fs = require('fs'); +const path = require('path'); + +function processMdxToMarkdown(content) { + const baseUrl = 'https://docs.genlayer.com'; + + // Helper function to convert relative URLs to absolute + function makeAbsoluteUrl(url) { + if (url.startsWith('http://') || url.startsWith('https://')) { + return url; // Already absolute + } + if (url.startsWith('/')) { + return baseUrl + url; // Relative to root + } + return url; // Keep as-is for anchors (#) or other formats + } + + let processed = content; + + // Remove import statements + processed = processed.replace(/^import\s+.*$/gm, ''); + + // Convert CustomCard components to markdown links + processed = processed.replace( + /]*\s+title="([^"]*)"[^>]*\s+description="([^"]*)"[^>]*\s+href="([^"]*)"[^>]*\/>/g, + (match, title, description, href) => { + const absoluteUrl = makeAbsoluteUrl(href); + return `- **[${title}](${absoluteUrl})**: ${description}`; + } + ); + + // Convert Card components to markdown links + processed = processed.replace( + /]*\s+title="([^"]*)"[^>]*\s+href="([^"]*)"[^>]*\/>/g, + (match, title, href) => { + const absoluteUrl = makeAbsoluteUrl(href); + return `- **[${title}](${absoluteUrl})**`; + } + ); + + // Convert simple JSX links to markdown + processed = processed.replace( + /]*>([^<]*)<\/a>/g, + (match, href, text) => { + const absoluteUrl = makeAbsoluteUrl(href); + return `[${text}](${absoluteUrl})`; + } + ); + + // Convert Callout components to markdown blockquotes + processed = processed.replace( + /]*type="([^"]*)"[^>]*>([\s\S]*?)<\/Callout>/g, + (match, type, content) => { + const cleanContent = content.trim(); + const prefix = type === 'warning' ? '⚠️ ' : type === 'info' ? 'ℹ️ ' : ''; + return `> ${prefix}${cleanContent}`; + } + ); + + // Convert simple HTML divs to text (remove div tags but keep content) + processed = processed.replace(/]*>([\s\S]*?)<\/div>/g, '$1'); + + // Convert
tags to line breaks + processed = processed.replace(//g, '\n'); + + // Convert Image components to markdown images (with alt) + processed = processed.replace( + /]*\s+src="([^"]*)"[^>]*\s+alt="([^"]*)"[^>]*\/?>/g, + (match, src, alt) => { + const absoluteUrl = makeAbsoluteUrl(src); + return `![${alt}](${absoluteUrl})`; + } + ); + + // Convert Image components to markdown images (without alt) + processed = processed.replace( + /]*\s+src="([^"]*)"[^>]*\/?>/g, + (match, src) => { + const absoluteUrl = makeAbsoluteUrl(src); + return `![Image](${absoluteUrl})`; + } + ); + + // Convert regular tags to markdown images + processed = processed.replace( + /]*\s+src="([^"]*)"[^>]*\s+alt="([^"]*)"[^>]*\/?>/g, + (match, src, alt) => { + const absoluteUrl = makeAbsoluteUrl(src); + return `![${alt}](${absoluteUrl})`; + } + ); + + // Convert regular markdown images to absolute URLs + processed = processed.replace( + /!\[([^\]]*)\]\(([^)]*)\)/g, + (match, alt, src) => { + const absoluteUrl = makeAbsoluteUrl(src); + return `![${alt}](${absoluteUrl})`; + } + ); + + // Convert regular markdown links to absolute URLs + processed = processed.replace( + /\[([^\]]*)\]\(([^)]*)\)/g, + (match, text, href) => { + const absoluteUrl = makeAbsoluteUrl(href); + return `[${text}](${absoluteUrl})`; + } + ); + + // Remove empty lines created by import removal and clean up + processed = processed + .split('\n') + .filter((line, index, array) => { + // Remove empty lines at the start + if (index === 0 && line.trim() === '') return false; + // Remove multiple consecutive empty lines + if (line.trim() === '' && array[index - 1] && array[index - 1].trim() === '') return false; + return true; + }) + .join('\n') + .trim(); + + return processed; +} + +function processAllMdxFiles() { + const pagesDir = path.join(process.cwd(), 'pages'); + const publicPagesDir = path.join(process.cwd(), 'public', 'pages'); + + // Create public/pages directory if it doesn't exist + if (!fs.existsSync(publicPagesDir)) { + fs.mkdirSync(publicPagesDir, { recursive: true }); + } + + function processDirectory(sourceDir, targetDir) { + const items = fs.readdirSync(sourceDir); + + items.forEach(item => { + const sourcePath = path.join(sourceDir, item); + const stat = fs.statSync(sourcePath); + + if (stat.isDirectory()) { + const newTargetDir = path.join(targetDir, item); + if (!fs.existsSync(newTargetDir)) { + fs.mkdirSync(newTargetDir, { recursive: true }); + } + processDirectory(sourcePath, newTargetDir); + } else if (item.endsWith('.mdx')) { + const content = fs.readFileSync(sourcePath, 'utf8'); + const processedContent = processMdxToMarkdown(content); + + const targetPath = path.join(targetDir, item.replace('.mdx', '.md')); + fs.writeFileSync(targetPath, processedContent); + } + }); + } + + processDirectory(pagesDir, publicPagesDir); + console.log('✅ Processed all MDX files to clean Markdown'); +} + +processAllMdxFiles(); From 8f248bea3635b48d50ddf1dc2bcc6ea48e0c1d1e Mon Sep 17 00:00:00 2001 From: Edinaldo Junior Date: Thu, 14 Aug 2025 18:14:54 -0300 Subject: [PATCH 2/9] chore: gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index eaa0af3b..645e7bae 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ node_modules pnpm-lock.yaml public/full-documentation.txt +public/pages .specstory/ # SpecStory explanation file .specstory/.what-is-this.md From ff642f8c226168d0c10b6ea7d680f22e44ee85d6 Mon Sep 17 00:00:00 2001 From: Edinaldo Junior Date: Thu, 14 Aug 2025 23:49:58 -0300 Subject: [PATCH 3/9] fix: prevent security issue on safari --- components/copy-page.tsx | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/components/copy-page.tsx b/components/copy-page.tsx index 8c0ef383..5fc5eef5 100644 --- a/components/copy-page.tsx +++ b/components/copy-page.tsx @@ -11,6 +11,7 @@ import AnthropicIcon from './icons/anthropic'; const CopyPage: React.FC = () => { const [isOpen, setIsOpen] = useState(false); const [isCopied, setIsCopied] = useState(false); + const [prefetchedContent, setPrefetchedContent] = useState(null); const dropdownRef = useRef(null); const router = useRouter(); @@ -26,23 +27,30 @@ const CopyPage: React.FC = () => { return () => document.removeEventListener('mousedown', handleClickOutside); }, []); + // Prefetch markdown content when component mounts + useEffect(() => { + const prefetchContent = async () => { + try { + const currentPath = router.asPath; + const cleanPath = currentPath.split('?')[0].split('#')[0]; + const mdUrl = cleanPath === '/' ? '/pages/index.md' : `/pages${cleanPath}.md`; + + const response = await fetch(mdUrl); + if (response.ok) { + const content = await response.text(); + setPrefetchedContent(content); + } + } catch (error) { + console.log('Prefetch failed, will use fallback:', error); + } + }; + + prefetchContent(); + }, [router.asPath]); // Re-prefetch when route changes + const copyPageAsMarkdown = async () => { try { - const currentPath = router.asPath; - - // Remove query params and hash from path - const cleanPath = currentPath.split('?')[0].split('#')[0]; - - // Convert path to static file URL - const mdUrl = cleanPath === '/' ? '/pages/index.md' : `/pages${cleanPath}.md`; - const response = await fetch(mdUrl); - - if (!response.ok) { - throw new Error('Failed to fetch MDX content'); - } - - const mdContent = await response.text(); - await navigator.clipboard.writeText(mdContent); + await navigator.clipboard.writeText(prefetchedContent || ''); // Show success feedback setIsCopied(true); From 558ca4a84bf4484ee765cf4512be5aff514d6230 Mon Sep 17 00:00:00 2001 From: Edinaldo Junior Date: Thu, 14 Aug 2025 23:53:17 -0300 Subject: [PATCH 4/9] chore: comments --- components/copy-page.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/copy-page.tsx b/components/copy-page.tsx index 5fc5eef5..e7a0eef9 100644 --- a/components/copy-page.tsx +++ b/components/copy-page.tsx @@ -28,6 +28,7 @@ const CopyPage: React.FC = () => { }, []); // Prefetch markdown content when component mounts + // this is needed to avoid a security issue on safari where you cant fetch and paste in the clipboard useEffect(() => { const prefetchContent = async () => { try { @@ -46,7 +47,7 @@ const CopyPage: React.FC = () => { }; prefetchContent(); - }, [router.asPath]); // Re-prefetch when route changes + }, [router.asPath]); const copyPageAsMarkdown = async () => { try { @@ -66,10 +67,8 @@ const CopyPage: React.FC = () => { const viewAsMarkdown = () => { const currentPath = router.asPath; - // Remove query params and hash from path const cleanPath = currentPath.split('?')[0].split('#')[0]; - // Open the .md file directly (no blob needed!) const mdUrl = cleanPath === '/' ? '/pages/index.md' : `/pages${cleanPath}.md`; window.open(mdUrl, '_blank'); setIsOpen(false); @@ -79,7 +78,6 @@ const CopyPage: React.FC = () => { const currentPath = router.asPath; const cleanPath = currentPath.split('?')[0].split('#')[0]; - // Use the .md file URL instead of the docs page URL const mdUrl = cleanPath === '/' ? '/pages/index.md' : `/pages${cleanPath}.md`; const fullMdUrl = `${window.location.origin}${mdUrl}`; From 2551fd89cedf6aab8765d2f6f38ab7ec5b5cb61a Mon Sep 17 00:00:00 2001 From: Edinaldo Junior Date: Thu, 14 Aug 2025 23:53:41 -0300 Subject: [PATCH 5/9] chore: comments --- components/copy-page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/copy-page.tsx b/components/copy-page.tsx index e7a0eef9..e9b148d7 100644 --- a/components/copy-page.tsx +++ b/components/copy-page.tsx @@ -28,7 +28,7 @@ const CopyPage: React.FC = () => { }, []); // Prefetch markdown content when component mounts - // this is needed to avoid a security issue on safari where you cant fetch and paste in the clipboard + // this is needed to avoid a security issue on safari where you can't fetch and paste in the clipboard useEffect(() => { const prefetchContent = async () => { try { From 6e71beb20a3bf5d873d6272b20a22803bb1c40a0 Mon Sep 17 00:00:00 2001 From: Edinaldo Junior Date: Fri, 15 Aug 2025 00:56:38 -0300 Subject: [PATCH 6/9] fix: custom card better refex --- scripts/process-mdx-to-md.js | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/scripts/process-mdx-to-md.js b/scripts/process-mdx-to-md.js index fcfdc238..ba630dc6 100644 --- a/scripts/process-mdx-to-md.js +++ b/scripts/process-mdx-to-md.js @@ -22,19 +22,39 @@ function processMdxToMarkdown(content) { // Convert CustomCard components to markdown links processed = processed.replace( - /]*\s+title="([^"]*)"[^>]*\s+description="([^"]*)"[^>]*\s+href="([^"]*)"[^>]*\/>/g, - (match, title, description, href) => { - const absoluteUrl = makeAbsoluteUrl(href); - return `- **[${title}](${absoluteUrl})**: ${description}`; + /]*)\/>/g, + (match, attrs) => { + // Extract attributes regardless of order + const titleMatch = attrs.match(/title="([^"]*)"/); + const descMatch = attrs.match(/description="([^"]*)"/); + const hrefMatch = attrs.match(/href="([^"]*)"/); + + if (titleMatch && hrefMatch) { + const title = titleMatch[1]; + const description = descMatch ? descMatch[1] : ''; + const absoluteUrl = makeAbsoluteUrl(hrefMatch[1]); + return description + ? `- **[${title}](${absoluteUrl})**: ${description}` + : `- **[${title}](${absoluteUrl})**`; + } + return match; // Return unchanged if required attributes are missing } ); // Convert Card components to markdown links processed = processed.replace( - /]*\s+title="([^"]*)"[^>]*\s+href="([^"]*)"[^>]*\/>/g, - (match, title, href) => { - const absoluteUrl = makeAbsoluteUrl(href); - return `- **[${title}](${absoluteUrl})**`; + /]*)\/>/g, + (match, attrs) => { + // Extract attributes regardless of order + const titleMatch = attrs.match(/title="([^"]*)"/); + const hrefMatch = attrs.match(/href="([^"]*)"/); + + if (titleMatch && hrefMatch) { + const title = titleMatch[1]; + const absoluteUrl = makeAbsoluteUrl(hrefMatch[1]); + return `- **[${title}](${absoluteUrl})**`; + } + return match; // Return unchanged if required attributes are missing } ); From 09aabd8690fad0ab1453962b7318557fe647c154 Mon Sep 17 00:00:00 2001 From: Edinaldo Junior Date: Fri, 15 Aug 2025 01:06:14 -0300 Subject: [PATCH 7/9] fix: callout regex --- scripts/process-mdx-to-md.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/process-mdx-to-md.js b/scripts/process-mdx-to-md.js index ba630dc6..db7ca7e4 100644 --- a/scripts/process-mdx-to-md.js +++ b/scripts/process-mdx-to-md.js @@ -69,8 +69,11 @@ function processMdxToMarkdown(content) { // Convert Callout components to markdown blockquotes processed = processed.replace( - /]*type="([^"]*)"[^>]*>([\s\S]*?)<\/Callout>/g, - (match, type, content) => { + /]*)>([\s\S]*?)<\/Callout>/g, + (match, attrs, content) => { + // Extract attributes regardless of order + const typeMatch = attrs.match(/type="([^"]*)"/); + const type = typeMatch ? typeMatch[1] : ''; const cleanContent = content.trim(); const prefix = type === 'warning' ? '⚠️ ' : type === 'info' ? 'ℹ️ ' : ''; return `> ${prefix}${cleanContent}`; From 0acde6d45b0baaf5158bc1bece9d9b18b802ee51 Mon Sep 17 00:00:00 2001 From: Edinaldo Junior Date: Tue, 19 Aug 2025 20:42:41 -0300 Subject: [PATCH 8/9] feat: including new components and fixing image src with space --- scripts/process-mdx-to-md.js | 99 ++++++++++++++++++++++++++++-------- 1 file changed, 79 insertions(+), 20 deletions(-) diff --git a/scripts/process-mdx-to-md.js b/scripts/process-mdx-to-md.js index db7ca7e4..8b52eac9 100644 --- a/scripts/process-mdx-to-md.js +++ b/scripts/process-mdx-to-md.js @@ -6,13 +6,21 @@ function processMdxToMarkdown(content) { // Helper function to convert relative URLs to absolute function makeAbsoluteUrl(url) { + // Keep anchors as-is + if (url.startsWith('#')) return url; + + // Absolute URLs if (url.startsWith('http://') || url.startsWith('https://')) { - return url; // Already absolute + return encodeURI(url); } + + // Relative to root if (url.startsWith('/')) { - return baseUrl + url; // Relative to root + return encodeURI(baseUrl + url); } - return url; // Keep as-is for anchors (#) or other formats + + // Other relative paths + return encodeURI(url); } let processed = content; @@ -80,36 +88,84 @@ function processMdxToMarkdown(content) { } ); + // Convert Tabs with labeled items into headings with their respective content + processed = processed.replace( + /]*items=\{\[([\s\S]*?)\]\}[^>]*>([\s\S]*?)<\/Tabs>/g, + (match, itemsRaw, inner) => { + const tabTitles = itemsRaw + .split(',') + .map(s => s.trim()) + .map(s => s.replace(/^["']|["']$/g, '')) + .filter(Boolean); + + const tabContents = []; + const tabRegex = /]*>([\s\S]*?)<\/Tabs\.Tab>/g; + let m; + while ((m = tabRegex.exec(inner)) !== null) { + tabContents.push(m[1].trim()); + } + + // Map titles to contents; if counts mismatch, best-effort pairing + const sections = []; + const count = Math.max(tabTitles.length, tabContents.length); + for (let i = 0; i < count; i++) { + const title = tabTitles[i] || `Tab ${i + 1}`; + const content = (tabContents[i] || '').trim(); + if (content) { + sections.push(`### ${title}\n\n${content}`); + } else { + sections.push(`### ${title}`); + } + } + return sections.join('\n\n'); + } + ); + + // Fallback: strip any remaining Tabs wrappers (keep inner content) + processed = processed.replace(/]*>/g, ''); + processed = processed.replace(/<\/Tabs>/g, ''); + processed = processed.replace(/]*>/g, ''); + processed = processed.replace(/<\/Tabs\.Tab>/g, ''); + + // Strip Cards container (individual handled above) + processed = processed.replace(/]*>/g, ''); + processed = processed.replace(/<\/Cards>/g, ''); + + // Strip Bleed wrapper + processed = processed.replace(/]*>/g, ''); + processed = processed.replace(/<\/Bleed>/g, ''); + + // Strip Fragment wrapper + processed = processed.replace(/]*>/g, ''); + processed = processed.replace(/<\/Fragment>/g, ''); + // Convert simple HTML divs to text (remove div tags but keep content) processed = processed.replace(/]*>([\s\S]*?)<\/div>/g, '$1'); // Convert
tags to line breaks - processed = processed.replace(//g, '\n'); + processed = processed.replace(/(?!\s*<\/)/g, '\n'); - // Convert Image components to markdown images (with alt) + // Convert Image components to markdown images (with alt) - leave src as-is to avoid double-encoding processed = processed.replace( - /]*\s+src="([^"]*)"[^>]*\s+alt="([^"]*)"[^>]*\/?>/g, + /]*\s+src="([^"]*)"[^>]*\s+alt="([^"]*)"[^>]*\/?>(?!\s*<\/Image>)/g, (match, src, alt) => { - const absoluteUrl = makeAbsoluteUrl(src); - return `![${alt}](${absoluteUrl})`; + return `![${alt}](${src})`; } ); - // Convert Image components to markdown images (without alt) + // Convert Image components to markdown images (without alt) - leave src as-is processed = processed.replace( - /]*\s+src="([^"]*)"[^>]*\/?>/g, + /]*\s+src="([^"]*)"[^>]*\/?>(?!\s*<\/Image>)/g, (match, src) => { - const absoluteUrl = makeAbsoluteUrl(src); - return `![Image](${absoluteUrl})`; + return `![Image](${src})`; } ); - // Convert regular tags to markdown images + // Convert regular tags to markdown images - leave src as-is processed = processed.replace( - /]*\s+src="([^"]*)"[^>]*\s+alt="([^"]*)"[^>]*\/?>/g, + /]*\s+src="([^"]*)"[^>]*\s+alt="([^"]*)"[^>]*\/?>(?!\s*<\/img>)/g, (match, src, alt) => { - const absoluteUrl = makeAbsoluteUrl(src); - return `![${alt}](${absoluteUrl})`; + return `![${alt}](${src})`; } ); @@ -122,12 +178,12 @@ function processMdxToMarkdown(content) { } ); - // Convert regular markdown links to absolute URLs + // Convert regular markdown links to absolute URLs (skip images) processed = processed.replace( - /\[([^\]]*)\]\(([^)]*)\)/g, - (match, text, href) => { + /(^|[^!])\[([^\]]*)\]\(([^)]*)\)/gm, + (match, prefix, text, href) => { const absoluteUrl = makeAbsoluteUrl(href); - return `[${text}](${absoluteUrl})`; + return `${prefix}[${text}](${absoluteUrl})`; } ); @@ -144,6 +200,9 @@ function processMdxToMarkdown(content) { .join('\n') .trim(); + // Normalize list indentation (remove unintended leading spaces before list markers) + processed = processed.replace(/^[ \t]+- /gm, '- '); + return processed; } From 507956f0460baa11baae157d72f960d8e0c14712 Mon Sep 17 00:00:00 2001 From: Edinaldo Junior Date: Tue, 19 Aug 2025 22:35:20 -0300 Subject: [PATCH 9/9] fix: not removing imports from code blocks --- scripts/process-mdx-to-md.js | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/scripts/process-mdx-to-md.js b/scripts/process-mdx-to-md.js index 8b52eac9..079e0c8b 100644 --- a/scripts/process-mdx-to-md.js +++ b/scripts/process-mdx-to-md.js @@ -1,6 +1,24 @@ const fs = require('fs'); const path = require('path'); +function stripTopLevelImports(input) { + const lines = input.split('\n'); + let inFence = false; + return lines + .map((line) => { + const trimmed = line.trim(); + if (trimmed.startsWith('```')) { + inFence = !inFence; + return line; + } + if (!inFence && /^import\s+.*$/.test(line)) { + return ''; + } + return line; + }) + .join('\n'); +} + function processMdxToMarkdown(content) { const baseUrl = 'https://docs.genlayer.com'; @@ -25,8 +43,8 @@ function processMdxToMarkdown(content) { let processed = content; - // Remove import statements - processed = processed.replace(/^import\s+.*$/gm, ''); + // Remove top-level MDX import statements (skip fenced code blocks) + processed = stripTopLevelImports(processed); // Convert CustomCard components to markdown links processed = processed.replace(