import { getPostBySlug, getPostSlugs } from '@/lib/mdx'; import { MDXRemote } from 'next-mdx-remote/rsc'; import fs from 'fs'; import NextImage, { type ImageProps } from 'next/image'; import Link from 'next/link'; import path from 'path'; import { notFound } from 'next/navigation'; import { isValidElement } from 'react'; import type { ComponentPropsWithoutRef, ReactNode } from 'react'; import { TableOfContents } from '@/components/mdx/TableOfContents'; import { SideNote } from '@/components/mdx/SideNote'; import { Citation, Bibliography } from '@/components/mdx/Citation'; import { formatPostDate } from '@/lib/format'; const slugify = (text: string): string => { return text .toLowerCase() .replace(/[^a-z0-9]+/g, '-') .replace(/^-+|-+$/g, '') || 'section'; }; const publicDirectory = path.join(process.cwd(), 'public'); const imageDimensionCache = new Map(); const PNG_SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]); const JPEG_START_OF_FRAME_MARKERS = new Set([ 0xc0, 0xc1, 0xc2, 0xc3, 0xc5, 0xc6, 0xc7, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf, ]); function normalizeHeadingText(text: string) { return text .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') .replace(/[`*_~]/g, '') .replace(/<[^>]+>/g, '') .trim(); } function createSlugger() { const counts = new Map(); return (text: string) => { const base = slugify(text); const count = counts.get(base) || 0; counts.set(base, count + 1); return count === 0 ? base : `${base}-${count}`; }; } function toPlainText(node: ReactNode): string { if (typeof node === 'string' || typeof node === 'number') return String(node); if (Array.isArray(node)) return node.map(toPlainText).join(''); if (isValidElement<{ children?: ReactNode }>(node)) return toPlainText(node.props.children); return ''; } function extractHeadings(content: string) { const slugger = createSlugger(); const headingLines = content.match(/^#{1,3}\s+(.+)$/gm) || []; return headingLines.flatMap((line) => { const level = line.match(/^#+/)?.[0].length || 2; const text = normalizeHeadingText(line.replace(/^#+\s+/, '')); const id = slugger(text); return level > 1 ? [{ id, text, level }] : []; }); } function getPngDimensions(buffer: Buffer) { if (buffer.length < 24 || !buffer.subarray(0, 8).equals(PNG_SIGNATURE)) return null; return { width: buffer.readUInt32BE(16), height: buffer.readUInt32BE(20), }; } function getJpegDimensions(buffer: Buffer) { if (buffer.length < 4 || buffer[0] !== 0xff || buffer[1] !== 0xd8) return null; let offset = 2; while (offset < buffer.length - 9) { if (buffer[offset] !== 0xff) { offset += 1; continue; } const marker = buffer[offset + 1]; offset += 2; if (marker === 0xd8 || marker === 0xd9 || (marker >= 0xd0 && marker <= 0xd7)) { continue; } const length = buffer.readUInt16BE(offset); if (length < 2 || offset + length > buffer.length) break; if (JPEG_START_OF_FRAME_MARKERS.has(marker)) { return { height: buffer.readUInt16BE(offset + 3), width: buffer.readUInt16BE(offset + 5), }; } offset += length; } return null; } function getLocalImageDimensions(src: string) { const pathname = src.split(/[?#]/, 1)[0]; if (!pathname.startsWith('/') || pathname.includes('\0') || pathname.includes('..')) return null; const imagePath = path.join(publicDirectory, pathname.replace(/^\/+/, '')); if (!imagePath.startsWith(`${publicDirectory}${path.sep}`)) return null; if (imageDimensionCache.has(imagePath)) { return imageDimensionCache.get(imagePath) ?? null; } try { const buffer = fs.readFileSync(imagePath); const dimensions = getPngDimensions(buffer) ?? getJpegDimensions(buffer); imageDimensionCache.set(imagePath, dimensions); return dimensions; } catch { imageDimensionCache.set(imagePath, null); return null; } } function numericDimension(value: ImageProps['width'] | ImageProps['height']) { if (typeof value === 'number') return value; if (typeof value === 'string') { const parsed = Number(value); return Number.isFinite(parsed) ? parsed : undefined; } return undefined; } function MdxImage({ src, alt, width, height, sizes, ...props }: ImageProps) { if (typeof src !== 'string') { return ; } const localDimensions = getLocalImageDimensions(src); const resolvedWidth = numericDimension(width) ?? localDimensions?.width; const resolvedHeight = numericDimension(height) ?? localDimensions?.height; const displayWidth = Math.min(resolvedWidth ?? 704, 704); const responsiveSizes = sizes ?? `(max-width: 768px) 100vw, ${displayWidth}px`; return ( ); } function createMdxComponents() { const slugger = createSlugger(); const getHeadingId = (children: ReactNode) => slugger(toPlainText(children)); return { h1: ({ children, ...props }: ComponentPropsWithoutRef<'h1'>) =>

{children}

, h2: ({ children, ...props }: ComponentPropsWithoutRef<'h2'>) =>

{children}

, h3: ({ children, ...props }: ComponentPropsWithoutRef<'h3'>) =>

{children}

, p: (props: ComponentPropsWithoutRef<'p'>) =>

, ul: (props: ComponentPropsWithoutRef<'ul'>) =>