import { readFileSync, writeFileSync, existsSync } from 'fs' import { relative, resolve } from 'path' import type { SidebarItem } from './types' import { parseFrontmatter, stringifyFrontmatter } from './frontmatter' import { mergeSectionLinks, extractTopLevelLinks, extractItemsForPage } from './links' import { normalizeLink } from './path-utils' import { SectionLinkListItem } from '../../theme/components/SectionLinkList/SectionLinkList.types' const removeDuplicates = (links: SectionLinkListItem[]) => { const result: SectionLinkListItem[] = [] const seenLinks = new Set() for (const link of links) { if (link.link) { const normalized = normalizeLink(link.link) if (!seenLinks.has(normalized)) { seenLinks.add(normalized) result.push(link) } } } return result } const hasChanges = ( existingLinks: SectionLinkListItem[], mergedLinks: SectionLinkListItem[] ) => { if (existingLinks.length !== mergedLinks.length) return true const existingSet = new Set( existingLinks .filter(link => link.link) .map(link => `${normalizeLink(link.link!)}|${link.title}`) ) const mergedSet = new Set( mergedLinks .filter(link => link.link) .map(link => `${normalizeLink(link.link!)}|${link.title}`) ) if (existingSet.size !== mergedSet.size) return true for (const item of existingSet) { if (!mergedSet.has(item)) return true } return false } export const processIndexFile = ( filePath: string, sidebarItems: SidebarItem[], srcDir: string ) => { if (!existsSync(filePath)) return false try { const fileContent = readFileSync(filePath, 'utf-8') const { frontmatter, content } = parseFrontmatter(fileContent) const relativePath = relative(srcDir, filePath).replace(/\\/g, '/') const normalizedPath = relativePath.startsWith('/') ? relativePath : `/${relativePath}` const existingLinks = removeDuplicates( Array.isArray(frontmatter.section_links) ? [...frontmatter.section_links] : [] ) const newLinks = extractTopLevelLinks(sidebarItems, normalizedPath, srcDir) if (!newLinks.length) return false const mergedLinks = removeDuplicates(mergeSectionLinks(existingLinks, newLinks)) if (!hasChanges(existingLinks, mergedLinks)) return false frontmatter.section_links = mergedLinks writeFileSync(filePath, stringifyFrontmatter(frontmatter, content), 'utf-8') return true } catch { return false } } export const processPageWithItems = ( filePath: string, sidebarItems: SidebarItem[], srcDir: string ) => { if (!existsSync(filePath)) return false try { const fileContent = readFileSync(filePath, 'utf-8') const { frontmatter, content } = parseFrontmatter(fileContent) const relativePath = relative(srcDir, filePath).replace(/\\/g, '/') const normalizedPath = relativePath.startsWith('/') ? relativePath : `/${relativePath}` const existingLinks = removeDuplicates( Array.isArray(frontmatter.section_links) ? [...frontmatter.section_links] : [] ) const newLinks = extractItemsForPage(sidebarItems, normalizedPath, srcDir) const mergedLinks = newLinks.length > 0 ? removeDuplicates(mergeSectionLinks(existingLinks, newLinks)) : [] if (!hasChanges(existingLinks, mergedLinks)) return false frontmatter.section_links = mergedLinks writeFileSync(filePath, stringifyFrontmatter(frontmatter, content), 'utf-8') return true } catch { return false } }