Files
vercel__workflow/docs/lib/geistdocs/section-children.ts
Pranay Prakash 6fad87b2a4 docs: derive section landing-page cards from the page tree + lint drift (#2567)
Section index card grids (e.g. foundations) were hand-written and drifted
from the sidebar (meta.json) and the actual pages. Make them derive from
the fumadocs page tree (single source of truth) and add CI lint so the
card grid and navigation can't fall out of sync again.

- resolveSectionChildren + <AutoCards/>, bound in both v4 and v5 docs
  routes (correct /docs vs /v5/docs URL spaces)
- getLLMText expands <AutoCards/> so llms.txt/.md/copy-page keep child links
- manualCards frontmatter opt-out for curated pages (source.config.ts)
- checkSectionCards (card<->nav completeness) + checkMetaEntriesResolve
  (dangling meta entries) in scripts/lint.ts
- convert foundations + errors (drift fixes) and v5 observability to AutoCards
- mark deploying + ai as manualCards (intentionally curated)
- remove dangling meta entries: v4 cancellation (x2), root introduction
  (x2), v4/internal serializable-abort-controller

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 14:37:35 -07:00

67 lines
2.0 KiB
TypeScript

import type { Folder, Node, Root } from 'fumadocs-core/page-tree';
import type { ReactNode } from 'react';
export interface SectionChild {
title: ReactNode;
url: string;
description?: ReactNode;
icon?: ReactNode;
}
/**
* Find the folder whose index page is served at `sectionUrl` (e.g. the
* `foundations` folder for `/docs/foundations`). Searches the tree recursively
* so it works regardless of nesting depth.
*/
function findSectionFolder(
nodes: Node[],
sectionUrl: string
): Folder | undefined {
for (const node of nodes) {
if (node.type !== 'folder') continue;
if (node.index?.url === sectionUrl) return node;
const nested = findSectionFolder(node.children, sectionUrl);
if (nested) return nested;
}
return undefined;
}
/**
* Resolve the child pages of a section's landing page directly from the
* fumadocs page tree — the same tree that builds the sidebar (driven by
* `meta.json` + page frontmatter). This is the single source of truth shared by
* the `<AutoCards />` component, the markdown export in `getLLMText`, and the
* docs lint, so the card grid can never drift from the navigation.
*
* Children are returned in navigation order. Both leaf pages and sub-folders
* (which surface via their own index page) become cards; separators and
* index-less folders are skipped.
*/
export function resolveSectionChildren(
tree: Root,
sectionUrl: string
): SectionChild[] {
const folder = findSectionFolder(tree.children, sectionUrl);
if (!folder) return [];
const children: SectionChild[] = [];
for (const child of folder.children) {
if (child.type === 'page') {
children.push({
title: child.name,
url: child.url,
description: child.description,
icon: child.icon,
});
} else if (child.type === 'folder' && child.index) {
children.push({
title: child.index.name ?? child.name,
url: child.index.url,
description: child.index.description ?? child.description,
icon: child.index.icon ?? child.icon,
});
}
}
return children;
}