Skip to content

Add v1 headless integration surface and polish docs#35

Merged
KayleeWilliams merged 5 commits into
mainfrom
KayleeWilliams/better-rendering
May 13, 2026
Merged

Add v1 headless integration surface and polish docs#35
KayleeWilliams merged 5 commits into
mainfrom
KayleeWilliams/better-rendering

Conversation

@KayleeWilliams
Copy link
Copy Markdown
Collaborator

Summary

  • Adds the v1 framework-neutral integration surface: createDocsSource() at the root, plus new leadtype/mdx (tag prop contracts + mdxSourcePlugins source preset) and leadtype/fumadocs (first-party Source adapter) subpaths.
  • Polishes the docs onboarding flow: framework-agnostic Quickstart, multi-framework walkthrough page (Next, Astro, Vite + Vue/Solid/Svelte, Nuxt, SvelteKit), TL;DR blocks on the two main recipes, title="..." fence meta on every code block, kills the overlapping connect-docs-site + render-mdx-and-toc pages.
  • Fixes a mermaid flattening bug where <br/> was getting mangled in agent-flattened markdown across two passes, breaking downstream renderers.

New public API

Surface Purpose
createDocsSource({ contentDir }) (root) framework-neutral page loader, navigation, search index, include resolver
leadtype/mdx mdxSourcePlugins preset + tag prop types (CalloutProps, TabsProps, …) + include helpers
leadtype/fumadocs thin adapter mapping createDocsSource() to fumadocs-core's Source interface, walks pages + meta.json
convertMdxFile(path, plugins) (from leadtype/convert) in-memory MDX → { ast, frontmatter, data, markdown }
resolveInclude / parseIncludeSpecifier / extractMdxSection (from leadtype/mdx) standalone include resolution, no remark required
remarkResolveTypeTableJsx JSX-preserving variant of the type-table plugin for the source preset
order: frontmatter field optional sidebar ordering within a group
resolveDocsNavigation({ docsDirName }) optional override for non-docs/ folders

Bug fixes

  • Mermaid <br/> newline-in-label syntax is preserved in agent-flattened markdown — was being mangled to / and - in two separate passes (mermaid.remark.ts and convert.ts:compactMermaidBlocks), which broke any mermaid renderer downstream.
  • Mermaid plugin's backtick stripper now handles the common inline chart={`flowchart LR\n…`} form, not just backticks-on-their-own-lines.

Docs polish

  • Quickstart rewritten as a framework-agnostic primitive walkthrough (install → write one MDX → createDocsSource() → "Plug it into your framework" cards linking to per-framework anchors).
  • /docs/build/use-the-source-primitive restructured as a multi-framework umbrella with anchor-linkable sections for Next App Router, Astro Content Collections, Vite + @mdx-js/rollup, Nuxt, SvelteKit + mdsvex.
  • TL;DR blocks added to use-the-source-primitive and integrate-with-fumadocs so readers in a hurry can copy-paste the minimum before scrolling into the full walkthroughs.
  • Home page tightened: "Choose your path" Cards replaced with a single primary CTA to Quickstart + "What leadtype produces" capability cards.
  • Deleted overlapping connect-docs-site.mdx + render-mdx-and-toc.mdx; their content lives in the new build-a-docs-site (overview), use-the-source-primitive, generate-static-artifacts, and reference/mdx / reference/source pages.
  • All // filename code-block comments converted to title="..." fence meta. Renders as a title bar in rehype-code; agent flattening preserves the meta string.
  • All references to apps/example/ removed from docs (docs stand alone now).
  • use-the-source-primitive added to bestStartingPoints in docs/docs.config.ts so it surfaces in llms.txt.

Example app refactor

  • apps/example switched from 18 hand-rolled TanStack route files to a single [[...slug]] catch-all powered by a build-time createDocsSource() manifest. Adds a pipeline:source-manifest script.
  • New apps/fumadocs-example demonstrates leadtype/fumadocs end-to-end with c15t docs as the content fixture — Next.js 15 + fumadocs-ui 15, with rehypeCode syntax highlighting, top tabs (Frontend / Integrations / Self Host), framework switcher, and tailwind v4.

Test plan

  • bun --filter leadtype test — 179 / 179 passing (154 baseline + 25 new for include resolver, convert in-memory, source primitive)
  • bun --filter leadtype check-types — clean
  • bun --filter leadtype build — clean, 23 docs converted
  • bun --filter example build — clean, catch-all resolves every page
  • bun --filter fumadocs-example build — 216 static pages generated from c15t docs
  • grep -rn "apps/example" docs/ — zero matches
  • grep -rnE '^// [a-z][a-z0-9./_-]*\.(mjs|ts|tsx|js|json|mdx)' in docs — zero matches
  • Spot-check Quickstart Cards → all framework anchors resolve to real id headings in use-the-source-primitive
  • Mermaid blocks in apps/example/public/docs/build/build-a-docs-site.md — valid mermaid syntax with <br/> preserved

🤖 Generated with Claude Code

New public API:
- `createDocsSource()` at the root — framework-neutral source primitive
  (navigation, page loading, search, includes) for Next, Astro, Vite,
  Nuxt, SvelteKit, and any MDX-aware bundler
- `leadtype/mdx` subpath — tag prop contracts for every custom MDX tag
  plus `mdxSourcePlugins` (build-time include + ExtractedTypeTable
  resolution, leaves custom tags as JSX)
- `leadtype/fumadocs` subpath — thin Source adapter for fumadocs-core,
  walks pages + meta.json. Optional peer dep on fumadocs-core >= 15

New helpers:
- `convertMdxFile(path, plugins)` — in-memory MDX → {ast, frontmatter,
  data, markdown}
- `resolveInclude` / `parseIncludeSpecifier` / `extractMdxSection` /
  `resolveIncludePath` — standalone include resolution, no remark
  transform required
- `remarkResolveTypeTableJsx` — JSX-preserving variant of the type-table
  plugin for the source preset

Frontmatter:
- New optional `order:` field for sidebar ordering within a group

Navigation:
- `resolveDocsNavigation` accepts an optional `docsDirName` config
  (defaults to "docs") for projects whose docs folder isn't named docs/

Bug fixes:
- Mermaid `<br/>` syntax preserved in agent-flattened markdown (was
  being mangled to "/" and "-" by two separate passes, breaking
  downstream renderers)
- Mermaid plugin's backtick stripper handles inline template-literal
  form, not just backticks-on-their-own-lines

Docs polish:
- New `/docs/build/build-a-docs-site` umbrella with explicit decision
  tree (source primitive vs CLI artifacts)
- New `/docs/build/use-the-source-primitive` — multi-framework
  walkthrough with anchor-linkable per-host sections
- New `/docs/build/integrate-with-fumadocs` — first-party fumadocs
  recipe with TL;DR
- New `/docs/build/generate-static-artifacts` — CLI workflow
- New reference pages `/docs/reference/mdx` and `/docs/reference/source`
- Quickstart rewritten as framework-neutral primitive walkthrough
  (was Next-flavored CLI walkthrough); home page tightened; deleted
  the overlapping connect-docs-site + render-mdx-and-toc pages
- Code blocks now use `title="..."` fence meta instead of leading
  `// filename` comments — cleaner rendering via rehype-code
- apps/example refactored to a single `[[...slug]]` catch-all powered
  by a createDocsSource-generated manifest (was 18 hand-rolled route
  files)
- New apps/fumadocs-example demonstrates leadtype/fumadocs end-to-end
  with c15t docs as content
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 13, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Framework‑neutral docs source primitive with MDX build‑time preset, typed MDX tag contracts, fumadocs adapter, in‑memory MDX conversion, include‑resolution helpers, and example app manifest + runtime MDX mapping.
    • Docs ordering via optional frontmatter order and configurable docs directory name.
  • Documentation

    • New guides: "Use the source primitive", "Build a docs site", "Integrate with Fumadocs"; many quickstart/reference updates.
  • Bug Fixes

    • Mermaid blocks preserve
      and support inline chart embedding.

Walkthrough

Adds a v1 headless docs integration: a framework-neutral createDocsSource() primitive, leadtype/mdx MDX contracts and mdxSourcePlugins, include/type-table/mermaid plugin fixes, an in-memory convertMdxFile() API, a leadtype/fumadocs adapter, packaging/exports, tests, example apps (catch-all routing + Next fumadocs example), and extensive docs updates.

Changes

Core library: docs source, MDX, conversion, remark plugins, navigation, packaging

Layer / File(s) Summary
Docs source factory and runtime API
packages/leadtype/src/source/index.ts, packages/leadtype/src/source/source.test.ts
Adds createDocsSource(config) producing DocsSource with getNavigation(), listPages(), loadPage(slug), buildSearchIndex(), resolveInclude(); caches discovery; page conversion on demand; tests cover listing, loading, includes, TOC, navigation grouping, search index, and error paths.
MDX consumer surface & source preset
packages/leadtype/src/mdx/index.ts, packages/leadtype/src/mdx/source-preset.ts, packages/leadtype/src/mdx/tag-types.ts
Adds leadtype/mdx subpath: re-exports docs URL helpers, mdxSourcePlugins preset (include expansion, type-table JSX resolution, placeholder resolution, import stripping), and a comprehensive set of typed MDX tag prop contracts for renderer implementers.
In-memory MDX conversion API
packages/leadtype/src/convert/convert.ts, packages/leadtype/src/convert/index.ts, packages/leadtype/src/convert/convert.test.ts
Adds convertMdxFile() returning { ast, frontmatter, data, markdown }; runs remark processor with optional plugins, synthesizes/enriches frontmatter, and returns AST + markdown; tests validate shape, synthesized frontmatter when missing, and plugin execution.
Include resolver & remark plugin refactor
packages/leadtype/src/remark/plugins/include.remark.ts, packages/leadtype/src/remark/plugins/include.remark.test.ts
Refactors include handling: exports parseIncludeSpecifier, extractMdxSection, resolveIncludePath, resolveInclude() (returns markdown or code classification); remarkInclude delegates to resolver; tests cover parsing, path precedence, classification, sections, and errors.
Type-table JSX resolver plugin
packages/leadtype/src/remark/plugins/type-table-jsx.remark.ts
Adds remarkResolveTypeTableJsx() which rewrites <ExtractedTypeTable>/<AutoTypeTable> into runtime <TypeTable properties={...} /> JSX by extracting types from source files (basePath override supported).
Mermaid fixes
packages/leadtype/src/remark/plugins/mermaid.remark.ts
Adjusts outer-backtick stripping to match leading/trailing backticks (supports inline chart={\...`}) and preserves
` inside Mermaid blocks.
Frontmatter ordering & navigation configurability
packages/leadtype/src/lint/schema.ts, packages/leadtype/src/llm/llm.ts
Adds optional order?: number to frontmatter schema and SourceDoc; navigation now sorts by explicit order (ascending) then urlPath; resolveDocsNavigation/readSourceDocs accept docsDirName (defaults to "docs").
Root exports, packaging, and build entries
packages/leadtype/src/index.ts, packages/leadtype/package.json, packages/leadtype/rollup.config.ts, packages/leadtype/src/internal/package-surface.test.ts
Re-exports createDocsSource and types at package root; adds ./mdx and ./fumadocs subpath exports; rollup entries for mdx/index and fumadocs/index; marks fumadocs-core as optional peer >=15.0.0; package-surface test updated.

Fumadocs adapter

Layer / File(s) Summary
Fumadocs adapter implementation
packages/leadtype/src/fumadocs/index.ts
Adds fumadocsSource(config) that wraps a DocsSource into a fumadocs-core Source; pre-walks listPages() to produce fumadocs file entries, optionally globs/reads **/meta.json into meta entries, exposes leadtype field, and delegates loadPage to leadtype.loadPage.

Example apps, build manifest, and catch-all routing

Layer / File(s) Summary
Docs manifest generator & build script
apps/example/scripts/docs-source-manifest.ts, apps/example/package.json
Adds pipeline:source-manifest and runs it from pipeline:build; script uses createDocsSource() to enumerate pages and writes src/generated/docs-pages.json with per-page metadata including globKey for import.meta.glob.
Catch-all routing and generated router update
apps/example/src/routes/docs/$.tsx, apps/example/src/routeTree.gen.ts
Introduces a TanStack Router catch-all "/docs/$" route that resolves _splat to pages via generated manifest, normalizes trailing slashes, lazy-loads MDX via import.meta.glob keyed by globKey, and updates router type mappings replacing many per-page route modules with the splat.
Removed static per-page route modules
apps/example/src/routes/docs/*
Removes many explicit per-page route modules in favor of the manifest + catch-all approach (multiple apps/example/src/routes/docs/*.tsx deletions).
Vite MDX pipeline update
apps/example/vite.config.ts
Adds mdxSourcePlugins to the MDX pipeline and uses an explicitly ordered remarkPlugins array (frontmatter, YAML strip, GFM, then ...mdxSourcePlugins).

Fumadocs example Next.js app & MDX components

Layer / File(s) Summary
Fumadocs example source wiring
apps/fumadocs-example/lib/source.ts, apps/fumadocs-example/scripts/setup-source.ts, apps/fumadocs-example/package.json
Adds fumadocs-example app: setup-source.ts clones/updates .docs-src/c15t; lib/source.ts resolves contentDir, awaits fumadocsSource({ contentDir }), exports source (fumadocs loader) and leadtypeSource; app scripts and deps added.
Next app layout/pages and tooling
apps/fumadocs-example/app/layout.tsx, apps/fumadocs-example/app/page.tsx, apps/fumadocs-example/app/global.css, apps/fumadocs-example/next.config.mjs, apps/fumadocs-example/tsconfig.json, apps/fumadocs-example/postcss.config.mjs, apps/fumadocs-example/css.d.ts
Adds root layout, metadata, Home page, global CSS importing Tailwind + fumadocs-ui, Next MDX config using mdxSourcePlugins + rehypeCode, PostCSS/Tailwind config, and TypeScript ambient CSS declaration.
Docs page, layout, MDX adapters
apps/fumadocs-example/app/docs/[[...slug]]/page.tsx, apps/fumadocs-example/app/docs/layout.tsx, apps/fumadocs-example/lib/mdx-components.tsx, apps/fumadocs-example/mdx-components.tsx, apps/fumadocs-example/lib/framework-switcher.tsx
Adds server page that loads pages via leadtypeSource.loadPage(slug), renders via MDXRemote with mdxComponents and code highlighting, exports generateStaticParams()/generateMetadata(); layout builds knownRoutes from listPages(); mdxComponents adapts leadtype tag contracts to fumadocs-ui primitives; FrameworkSwitcher selects framework-specific docs routes using knownRoutes.

Docs, tests, and polish

Layer / File(s) Summary
Documentation updates & new pages
docs/* (notable: docs/build/use-the-source-primitive.mdx, docs/build/integrate-with-fumadocs.mdx, docs/reference/source.mdx, docs/reference/mdx.mdx, docs/build/build-a-docs-site.mdx, others)
Adds comprehensive integration docs for createDocsSource(), leadtype/mdx surface, fumadocs integration, new build vs source guidance, frontmatter ordering, and cross-reference updates across quickstart/index/methodology.
Tests & CLI adjustments
packages/leadtype/src/cli.test.ts, packages/leadtype/src/convert/convert.test.ts, packages/leadtype/src/internal/package-surface.test.ts
Updates CLI tests to expect build-a-docs-site slug, adds tests for convertMdxFile and include resolver, and updates package-surface expectations for new subpaths.
Example runtime type update
apps/example/src/components/docs-mdx/callout.tsx
Callout props/types now derive from leadtype/mdx (CalloutProps/CalloutVariant re-exported or adapted).

Sequence Diagram(s)

sequenceDiagram
    participant Host as Docs App
    participant Source as createDocsSource()
    participant FS as File System
    participant Parser as MDX Parser (remark)
    participant Plugins as mdxSourcePlugins
    participant TOC as TOC Extractor

    Host->>Source: loadPage(slug)
    activate Source
    Source->>FS: read .mdx file
    FS-->>Source: raw MDX + frontmatter
    Source->>Parser: parse with remark
    activate Parser
    Parser->>Plugins: apply mdxSourcePlugins
    activate Plugins
    Plugins->>FS: resolve <include> refs
    FS-->>Plugins: include content
    Plugins->>Plugins: expand includes & resolve <ExtractedTypeTable>
    Plugins-->>Parser: transformed MDAST
    deactivate Plugins
    Parser->>Parser: serialize to markdown
    Parser-->>Source: ast + markdown
    deactivate Parser
    Source->>TOC: extract headings (if enabled)
    activate TOC
    TOC-->>Source: toc array
    deactivate TOC
    Source-->>Host: DocsPage { ast, markdown, frontmatter, toc, meta }
    deactivate Source
Loading
sequenceDiagram
    participant Next as Next.js Build
    participant FumadocsAdapter as fumadocsSource()
    participant LeadtypeSource as createDocsSource()
    participant FS as File System
    participant Fumadocs as fumadocs-core loader

    Next->>FumadocsAdapter: fumadocsSource({ contentDir })
    activate FumadocsAdapter
    FumadocsAdapter->>LeadtypeSource: createDocsSource(config)
    activate LeadtypeSource
    LeadtypeSource->>FS: scan contentDir
    FS-->>LeadtypeSource: .md/.mdx files
    LeadtypeSource-->>FumadocsAdapter: DocsSource
    deactivate LeadtypeSource
    FumadocsAdapter->>LeadtypeSource: listPages()
    LeadtypeSource-->>FumadocsAdapter: DocsPageMeta[]
    FumadocsAdapter->>FS: glob **/meta.json (optional)
    FS-->>FumadocsAdapter: meta.json entries
    FumadocsAdapter-->>Next: fumadocs Source object (files + loadPage)
    deactivate FumadocsAdapter
    Next->>Fumadocs: loader({ baseUrl, source })
    Fumadocs-->>Next: runtime source wiring
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • inthhq/leadtype#32: Touches convert/convert.ts; related to the new convertMdxFile API and frontmatter handling.
  • inthhq/leadtype#25: Documentation edits to methodology/positioning that overlap with this PR’s docs changes.

Poem

🐰 I nibbled on a markdown leaf,

stitched includes beyond belief.
Source and plugins hum along,
pages hop out, loud and strong.
Hooray — the docs now sing a song!

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch KayleeWilliams/better-rendering

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/example/scripts/docs-source-manifest.ts`:
- Line 48: The generated globKey is using path.relative which yields
OS-dependent separators (backslashes on Windows), causing mismatches with
import.meta.glob keys; update the code that builds globKey (the expression using
relative(join(appRoot, "src", "routes", "docs"), join(contentDir,
page.relativePath)) and page.extension) to normalize to POSIX separators before
writing the manifest — e.g., compute the relative path, replace backslashes with
forward slashes (or use path.posix equivalents) and then append page.extension
so globKey always uses forward slashes compatible with import.meta.glob.

In `@apps/example/src/routes/docs/`$.tsx:
- Around line 74-80: The useMemo for MdxComponent currently lists [page.globKey,
page.urlPath] as dependencies; simplify this to depend on the whole page object
instead (i.e., use [page]) so that any change to _splat producing a new page
reference will retrigger the memo; keep the inner logic using
mdxModules[page.globKey], lazy(loader), and MissingMdxModule(urlPath) unchanged.
- Line 72: The code uses a type assertion "as DocsPage" on resolvePage(_splat)
which bypasses TypeScript safety; instead remove the cast and either use a
non-null assertion on resolvePage(_splat) or perform an explicit runtime null
check and narrow the type: call resolvePage(_splat) into a const (e.g.,
pageCandidate), if it's null/undefined throw a descriptive error, otherwise
assign it to page typed as DocsPage so the type is safely narrowed without using
"as DocsPage" (referencing resolvePage, _splat, and DocsPage to locate where to
change).

In `@docs/build/integrate-with-fumadocs.mdx`:
- Around line 108-121: The snippet calls notFound() inside the Page component
but never imports it; add an import for notFound from "next/navigation" at the
top of the snippet so the call in the Page function resolves (locate the Page
function and the notFound() call in the app/docs/[[...slug]]/page.tsx code and
add the missing import for notFound from "next/navigation").

In `@packages/leadtype/src/convert/convert.ts`:
- Around line 353-357: The parameter enrichFromGitFlag in the convertMdxFile
function is missing an explicit type; update the function signature for
convertMdxFile to declare enrichFromGitFlag: boolean (keeping the default value
= false) so the parameter is explicitly typed, e.g. change the parameter list to
include enrichFromGitFlag: boolean = false to match the inferred type and
codebase conventions.
- Around line 227-232: The compactMermaidBlocks function is a no-op but
currently invokes markdown.replace with MERMAID_FENCE_REGEX; simplify by
returning the input directly: change compactMermaidBlocks to just return
markdown and remove the needless call to markdown.replace (you can keep
MERMAID_FENCE_REGEX if still referenced elsewhere, but do not use it in this
function).

In `@packages/leadtype/src/fumadocs/index.ts`:
- Line 114: Replace the redundant arrow wrapper for loadPage with a direct
reference to the underlying function: remove the wrapper expression "loadPage:
(slug) => leadtype.loadPage(slug)" and use the function reference "loadPage:
leadtype.loadPage" so the property directly points to leadtype.loadPage
(referencing the loadPage property in this module and the leadtype.loadPage
method).

In `@packages/leadtype/src/lint/schema.ts`:
- Line 64: The schema's order field currently allows any number via
v.optional(v.number()); change this to enforce integers (and optionally
non-negative) to prevent fractional orders—e.g., replace the current
v.optional(v.number()) with something like v.optional(v.number().int().min(0))
(or v.optional(v.integer().min(0)) if your validation lib exposes integer()) in
the schema where the order field is declared so ordering always uses whole
numbers.

In `@packages/leadtype/src/remark/plugins/type-table-jsx.remark.ts`:
- Around line 99-103: The double-cast "as unknown as Root['children'][number]"
bypasses TypeScript checks; replace it by giving the replacement a proper typed
identity or narrowing it with a type guard before splicing. Define a union MDX
node type (e.g., type MdxNode = Root['children'][number] | SomeOtherNode...) or
adjust the function that produces replacement to return
Root['children'][number], add a predicate function isMdxNode(node): node is
Root['children'][number] to validate the value, and only call
parentChildren.splice(index, 1, replacement) after the type guard ensures
replacement is the correct type (remove the double-cast). Ensure references to
replacement, parentChildren.splice and Root['children'][number] are updated
accordingly.
- Around line 84-91: Add an explicit return type to the main plugin factory
function remarkResolveTypeTableJsx: annotate its signature to return a
Transformer (or a function type like (tree: Root) => Root) to make the complex
transformer return explicit; keep the existing parameter type
RemarkResolveTypeTableJsxOptions and ensure you import/retain the Transformer or
Root types used for the annotation.

In `@packages/leadtype/src/source/index.ts`:
- Around line 216-219: The nested ternary for tocOptions (const tocOptions =
config.toc === false ? false : (config.toc ?? ({} as
DocsTableOfContentsOptions));) is hard to read—simplify by removing the inner
ternary and unnecessary inline type-assertion: either use an explicit if/else to
set tocOptions when config.toc === false else assign config.toc ?? {} with
tocOptions typed as DocsTableOfContentsOptions | false, or extract a small
helper like getTocOptions(config) that returns DocsTableOfContentsOptions |
false; update references to tocOptions accordingly.
- Around line 250-262: findMetaForSlug currently does a linear search on every
loadPage call causing O(n) cost; instead, when cachedMetas is computed create a
Map keyed by slug.join("/") (eg. cachedMetaMap: Map<string, DocsPageMeta>) and
populate it from cachedMetas, then replace uses of findMetaForSlug in loadPage
with a constant-time lookup cachedMetaMap.get(targetSlug). Update or remove the
findMetaForSlug function as needed and ensure cachedMetaMap is initialized once
alongside cachedMetas so subsequent loadPage calls use O(1) lookups.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 640aa7b8-3114-4c34-a073-2b69503040ba

📥 Commits

Reviewing files that changed from the base of the PR and between 1c66660 and 6c6dfa2.

⛔ Files ignored due to path filters (6)
  • apps/example/src/generated/agent-readability.json is excluded by !**/generated/**
  • apps/example/src/generated/docs-nav.json is excluded by !**/generated/**
  • apps/example/src/generated/docs-pages.json is excluded by !**/generated/**
  • apps/example/src/generated/docs-search-content.json is excluded by !**/generated/**
  • apps/example/src/generated/docs-search-index.json is excluded by !**/generated/**
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (80)
  • .changeset/v1-public-surface-and-docs-polish.md
  • apps/example/package.json
  • apps/example/scripts/docs-source-manifest.ts
  • apps/example/src/components/docs-mdx/callout.tsx
  • apps/example/src/routeTree.gen.ts
  • apps/example/src/routes/docs/$.tsx
  • apps/example/src/routes/docs/authoring/components.tsx
  • apps/example/src/routes/docs/authoring/frontmatter.tsx
  • apps/example/src/routes/docs/build/add-search.tsx
  • apps/example/src/routes/docs/build/connect-docs-site.tsx
  • apps/example/src/routes/docs/build/optimize-docs-for-agents.tsx
  • apps/example/src/routes/docs/build/render-mdx-and-toc.tsx
  • apps/example/src/routes/docs/build/validate-in-ci.tsx
  • apps/example/src/routes/docs/how-it-works.tsx
  • apps/example/src/routes/docs/methodology.tsx
  • apps/example/src/routes/docs/package-docs/bundle.tsx
  • apps/example/src/routes/docs/quickstart.tsx
  • apps/example/src/routes/docs/reference/cli.tsx
  • apps/example/src/routes/docs/reference/convert.tsx
  • apps/example/src/routes/docs/reference/evals.tsx
  • apps/example/src/routes/docs/reference/lint.tsx
  • apps/example/src/routes/docs/reference/llm.tsx
  • apps/example/src/routes/docs/reference/remark.tsx
  • apps/example/src/routes/docs/reference/search.tsx
  • apps/example/vite.config.ts
  • apps/fumadocs-example/app/docs/[[...slug]]/page.tsx
  • apps/fumadocs-example/app/docs/layout.tsx
  • apps/fumadocs-example/app/global.css
  • apps/fumadocs-example/app/layout.tsx
  • apps/fumadocs-example/app/page.tsx
  • apps/fumadocs-example/css.d.ts
  • apps/fumadocs-example/lib/framework-switcher.tsx
  • apps/fumadocs-example/lib/mdx-components.tsx
  • apps/fumadocs-example/lib/source.ts
  • apps/fumadocs-example/mdx-components.tsx
  • apps/fumadocs-example/next-env.d.ts
  • apps/fumadocs-example/next.config.mjs
  • apps/fumadocs-example/package.json
  • apps/fumadocs-example/postcss.config.mjs
  • apps/fumadocs-example/scripts/setup-source.ts
  • apps/fumadocs-example/tsconfig.json
  • docs/authoring/components.mdx
  • docs/authoring/frontmatter.mdx
  • docs/build/add-search.mdx
  • docs/build/build-a-docs-site.mdx
  • docs/build/generate-static-artifacts.mdx
  • docs/build/integrate-with-fumadocs.mdx
  • docs/build/optimize-docs-for-agents.mdx
  • docs/build/render-mdx-and-toc.mdx
  • docs/build/use-the-source-primitive.mdx
  • docs/build/validate-in-ci.mdx
  • docs/docs.config.ts
  • docs/index.mdx
  • docs/methodology.mdx
  • docs/package-docs/bundle.mdx
  • docs/quickstart.mdx
  • docs/reference/evals.mdx
  • docs/reference/llm.mdx
  • docs/reference/mdx.mdx
  • docs/reference/source.mdx
  • packages/leadtype/package.json
  • packages/leadtype/rollup.config.ts
  • packages/leadtype/src/cli.test.ts
  • packages/leadtype/src/convert/convert.test.ts
  • packages/leadtype/src/convert/convert.ts
  • packages/leadtype/src/convert/index.ts
  • packages/leadtype/src/fumadocs/index.ts
  • packages/leadtype/src/index.ts
  • packages/leadtype/src/internal/package-surface.test.ts
  • packages/leadtype/src/lint/schema.ts
  • packages/leadtype/src/llm/llm.ts
  • packages/leadtype/src/mdx/index.ts
  • packages/leadtype/src/mdx/source-preset.ts
  • packages/leadtype/src/mdx/tag-types.ts
  • packages/leadtype/src/remark/plugins/include.remark.test.ts
  • packages/leadtype/src/remark/plugins/include.remark.ts
  • packages/leadtype/src/remark/plugins/mermaid.remark.ts
  • packages/leadtype/src/remark/plugins/type-table-jsx.remark.ts
  • packages/leadtype/src/source/index.ts
  • packages/leadtype/src/source/source.test.ts
💤 Files with no reviewable changes (19)
  • apps/example/src/routes/docs/authoring/frontmatter.tsx
  • apps/example/src/routes/docs/build/optimize-docs-for-agents.tsx
  • apps/example/src/routes/docs/authoring/components.tsx
  • apps/example/src/routes/docs/reference/llm.tsx
  • apps/example/src/routes/docs/build/render-mdx-and-toc.tsx
  • apps/example/src/routes/docs/build/add-search.tsx
  • apps/example/src/routes/docs/quickstart.tsx
  • apps/example/src/routes/docs/build/validate-in-ci.tsx
  • apps/example/src/routes/docs/reference/evals.tsx
  • apps/example/src/routes/docs/methodology.tsx
  • apps/example/src/routes/docs/reference/remark.tsx
  • apps/example/src/routes/docs/reference/lint.tsx
  • apps/example/src/routes/docs/reference/cli.tsx
  • apps/example/src/routes/docs/reference/convert.tsx
  • apps/example/src/routes/docs/build/connect-docs-site.tsx
  • apps/example/src/routes/docs/package-docs/bundle.tsx
  • apps/example/src/routes/docs/reference/search.tsx
  • docs/build/render-mdx-and-toc.mdx
  • apps/example/src/routes/docs/how-it-works.tsx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use explicit types for function parameters and return values when they enhance clarity
Prefer unknown over any when the type is genuinely unknown
Use const assertions (as const) for immutable values and literal types
Leverage TypeScript's type narrowing instead of type assertions

Files:

  • apps/fumadocs-example/next-env.d.ts
  • apps/fumadocs-example/css.d.ts
  • apps/fumadocs-example/app/page.tsx
  • packages/leadtype/src/internal/package-surface.test.ts
  • packages/leadtype/src/convert/convert.test.ts
  • apps/example/vite.config.ts
  • apps/fumadocs-example/app/layout.tsx
  • apps/fumadocs-example/mdx-components.tsx
  • packages/leadtype/src/lint/schema.ts
  • apps/example/scripts/docs-source-manifest.ts
  • packages/leadtype/src/convert/index.ts
  • apps/fumadocs-example/scripts/setup-source.ts
  • packages/leadtype/src/remark/plugins/type-table-jsx.remark.ts
  • packages/leadtype/src/index.ts
  • apps/fumadocs-example/lib/framework-switcher.tsx
  • packages/leadtype/src/fumadocs/index.ts
  • packages/leadtype/src/mdx/source-preset.ts
  • apps/fumadocs-example/app/docs/layout.tsx
  • packages/leadtype/rollup.config.ts
  • apps/example/src/routes/docs/$.tsx
  • docs/docs.config.ts
  • packages/leadtype/src/remark/plugins/mermaid.remark.ts
  • packages/leadtype/src/mdx/index.ts
  • apps/example/src/components/docs-mdx/callout.tsx
  • packages/leadtype/src/cli.test.ts
  • packages/leadtype/src/llm/llm.ts
  • apps/fumadocs-example/lib/source.ts
  • apps/fumadocs-example/lib/mdx-components.tsx
  • packages/leadtype/src/source/index.ts
  • packages/leadtype/src/source/source.test.ts
  • apps/fumadocs-example/app/docs/[[...slug]]/page.tsx
  • packages/leadtype/src/mdx/tag-types.ts
  • packages/leadtype/src/remark/plugins/include.remark.test.ts
  • apps/example/src/routeTree.gen.ts
  • packages/leadtype/src/remark/plugins/include.remark.ts
  • packages/leadtype/src/convert/convert.ts
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,jsx,tsx}: Use meaningful variable names instead of magic numbers - extract constants with descriptive names
Use arrow functions for callbacks and short functions
Prefer for...of loops over .forEach() and indexed for loops
Use optional chaining (?.) and nullish coalescing (??) for safer property access
Prefer template literals over string concatenation
Use destructuring for object and array assignments
Use const by default, let only when reassignment is needed, never var
Always await promises in async functions - don't forget to use the return value
Use async/await syntax instead of promise chains for better readability
Handle errors appropriately in async code with try-catch blocks
Don't use async functions as Promise executors
Remove console.log, debugger, and alert statements from production code
Throw Error objects with descriptive messages, not strings or other values
Use try-catch blocks meaningfully - don't catch errors just to rethrow them
Prefer early returns over nested conditionals for error cases
Extract complex conditions into well-named boolean variables
Use early returns to reduce nesting
Prefer simple conditionals over nested ternary operators
Don't use eval() or assign directly to document.cookie
Avoid spread syntax in accumulators within loops
Use top-level regex literals instead of creating them in loops
Prefer specific imports over namespace imports
Use descriptive names for functions, variables, and types for meaningful naming
Add comments for complex logic, but prefer self-documenting code

Files:

  • apps/fumadocs-example/next-env.d.ts
  • apps/fumadocs-example/css.d.ts
  • apps/fumadocs-example/app/page.tsx
  • packages/leadtype/src/internal/package-surface.test.ts
  • packages/leadtype/src/convert/convert.test.ts
  • apps/example/vite.config.ts
  • apps/fumadocs-example/app/layout.tsx
  • apps/fumadocs-example/mdx-components.tsx
  • packages/leadtype/src/lint/schema.ts
  • apps/example/scripts/docs-source-manifest.ts
  • packages/leadtype/src/convert/index.ts
  • apps/fumadocs-example/scripts/setup-source.ts
  • packages/leadtype/src/remark/plugins/type-table-jsx.remark.ts
  • packages/leadtype/src/index.ts
  • apps/fumadocs-example/lib/framework-switcher.tsx
  • packages/leadtype/src/fumadocs/index.ts
  • packages/leadtype/src/mdx/source-preset.ts
  • apps/fumadocs-example/app/docs/layout.tsx
  • packages/leadtype/rollup.config.ts
  • apps/example/src/routes/docs/$.tsx
  • docs/docs.config.ts
  • packages/leadtype/src/remark/plugins/mermaid.remark.ts
  • packages/leadtype/src/mdx/index.ts
  • apps/example/src/components/docs-mdx/callout.tsx
  • packages/leadtype/src/cli.test.ts
  • packages/leadtype/src/llm/llm.ts
  • apps/fumadocs-example/lib/source.ts
  • apps/fumadocs-example/lib/mdx-components.tsx
  • packages/leadtype/src/source/index.ts
  • packages/leadtype/src/source/source.test.ts
  • apps/fumadocs-example/app/docs/[[...slug]]/page.tsx
  • packages/leadtype/src/mdx/tag-types.ts
  • packages/leadtype/src/remark/plugins/include.remark.test.ts
  • apps/example/src/routeTree.gen.ts
  • packages/leadtype/src/remark/plugins/include.remark.ts
  • packages/leadtype/src/convert/convert.ts
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{jsx,tsx}: Use function components over class components in React
Call hooks at the top level only, never conditionally
Specify all dependencies in hook dependency arrays correctly
Use the key prop for elements in iterables (prefer unique IDs over array indices)
Nest children between opening and closing tags instead of passing as props
Don't define components inside other components
Avoid dangerouslySetInnerHTML unless absolutely necessary
Use proper image components (e.g., Next.js <Image>) over <img> tags
Use Next.js <Image> component for images
Use next/head or App Router metadata API for head elements in Next.js
Use Server Components for async data fetching instead of async Client Components in Next.js
Use ref as a prop instead of React.forwardRef in React 19+

Files:

  • apps/fumadocs-example/app/page.tsx
  • apps/fumadocs-example/app/layout.tsx
  • apps/fumadocs-example/mdx-components.tsx
  • apps/fumadocs-example/lib/framework-switcher.tsx
  • apps/fumadocs-example/app/docs/layout.tsx
  • apps/example/src/routes/docs/$.tsx
  • apps/example/src/components/docs-mdx/callout.tsx
  • apps/fumadocs-example/lib/mdx-components.tsx
  • apps/fumadocs-example/app/docs/[[...slug]]/page.tsx
**/*.{jsx,tsx,html}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{jsx,tsx,html}: Use semantic HTML and ARIA attributes for accessibility: provide meaningful alt text for images, use proper heading hierarchy, add labels for form inputs, include keyboard event handlers alongside mouse events, use semantic elements instead of divs with roles
Add rel="noopener" when using target="_blank" on links

Files:

  • apps/fumadocs-example/app/page.tsx
  • apps/fumadocs-example/app/layout.tsx
  • apps/fumadocs-example/mdx-components.tsx
  • apps/fumadocs-example/lib/framework-switcher.tsx
  • apps/fumadocs-example/app/docs/layout.tsx
  • apps/example/src/routes/docs/$.tsx
  • apps/example/src/components/docs-mdx/callout.tsx
  • apps/fumadocs-example/lib/mdx-components.tsx
  • apps/fumadocs-example/app/docs/[[...slug]]/page.tsx
**/*.{test,spec}.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{test,spec}.{js,ts,jsx,tsx}: Write assertions inside it() or test() blocks
Avoid done callbacks in async tests - use async/await instead
Don't use .only or .skip in committed code
Keep test suites reasonably flat - avoid excessive describe nesting

Files:

  • packages/leadtype/src/internal/package-surface.test.ts
  • packages/leadtype/src/convert/convert.test.ts
  • packages/leadtype/src/cli.test.ts
  • packages/leadtype/src/source/source.test.ts
  • packages/leadtype/src/remark/plugins/include.remark.test.ts
**/index.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Avoid barrel files (index files that re-export everything)

Files:

  • packages/leadtype/src/convert/index.ts
  • packages/leadtype/src/index.ts
  • packages/leadtype/src/fumadocs/index.ts
  • packages/leadtype/src/mdx/index.ts
  • packages/leadtype/src/source/index.ts
🪛 LanguageTool
docs/reference/mdx.mdx

[style] ~225-~225: This phrase is redundant. Consider using “outside”.
Context: ... remark — useful when loading a partial outside of the bundler pipeline: ```ts import { r...

(OUTSIDE_OF)

docs/reference/source.mdx

[style] ~9-~9: Consider using “who” when you are referring to a person instead of an object.
Context: ...-neutral** entry point for any consumer that wants to render leadtype-authored MDX i...

(THAT_WHO)


[style] ~96-~96: This phrase is redundant. Consider using “outside”.
Context: ...ontentDir`. Useful for loading partials outside of the MDX compile path. ## Choosing betw...

(OUTSIDE_OF)

docs/build/generate-static-artifacts.mdx

[uncategorized] ~203-~203: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ... — hosted routing index with page-level markdown links - public/llms-full.txt — all ge...

(MARKDOWN_NNP)


[uncategorized] ~204-~204: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ... public/llms-full.txt — all generated markdown docs in one fallback file - `public/doc...

(MARKDOWN_NNP)

🪛 markdownlint-cli2 (0.22.1)
.changeset/v1-public-surface-and-docs-polish.md

[warning] 5-5: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

🪛 Stylelint (17.11.0)
apps/fumadocs-example/app/global.css

[error] 9-9: Unexpected unknown at-rule "@source" (scss/at-rule-no-unknown)

(scss/at-rule-no-unknown)

🔇 Additional comments (65)
apps/fumadocs-example/next-env.d.ts (1)

1-7: LGTM!

docs/reference/evals.mdx (1)

19-19: LGTM!

apps/fumadocs-example/postcss.config.mjs (1)

1-5: LGTM!

apps/fumadocs-example/css.d.ts (1)

1-1: LGTM!

docs/authoring/frontmatter.mdx (1)

15-16: LGTM!

Also applies to: 60-60

packages/leadtype/src/cli.test.ts (1)

179-179: LGTM!

Also applies to: 204-204, 812-812, 834-834, 844-844, 1043-1043

apps/fumadocs-example/tsconfig.json (1)

1-29: LGTM!

apps/fumadocs-example/app/layout.tsx (1)

1-19: LGTM!

apps/fumadocs-example/app/global.css (1)

9-9: ⚡ Quick win

No action needed — stylelint is not configured in this project, and @source is already used successfully in apps/example/src/styles.css. The directive is valid Tailwind v4 syntax with no CI/lint risk.

apps/fumadocs-example/app/page.tsx (1)

1-21: LGTM!

docs/build/add-search.mdx (1)

5-5: LGTM!

packages/leadtype/src/remark/plugins/mermaid.remark.ts (2)

14-15: LGTM!


27-42: LGTM!

apps/fumadocs-example/lib/framework-switcher.tsx (4)

5-14: LGTM!


16-28: LGTM!


30-43: LGTM!


45-75: LGTM!

packages/leadtype/src/remark/plugins/type-table-jsx.remark.ts (4)

1-25: LGTM!


50-82: LGTM!


106-159: LGTM!


38-48: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Consider adding explicit return types to helper functions.

While the return types are clear from the implementation, adding explicit : JsxAttribute return type annotations would enhance clarity and catch potential errors if the implementation changes. As per coding guidelines, explicit types should be used when they enhance clarity.

💡 Suggested improvement
-function stringAttribute(name: string, value: string) {
+function stringAttribute(name: string, value: string): JsxAttribute {
   return { type: "mdxJsxAttribute", name, value };
 }

-function expressionAttribute(name: string, expression: string) {
+function expressionAttribute(name: string, expression: string): JsxAttribute {
   return {
			> Likely an incorrect or invalid review comment.
packages/leadtype/src/convert/convert.ts (1)

331-340: LGTM!

packages/leadtype/src/convert/index.ts (1)

1-10: LGTM!

packages/leadtype/src/convert/convert.test.ts (1)

56-102: LGTM!

packages/leadtype/src/remark/plugins/include.remark.ts (6)

66-79: LGTM!


87-114: LGTM!


322-374: LGTM!


376-449: LGTM!


466-559: LGTM!


284-320: LGTM!

packages/leadtype/src/mdx/source-preset.ts (1)

1-36: LGTM!

packages/leadtype/src/remark/plugins/include.remark.test.ts (1)

1-177: LGTM!

packages/leadtype/src/mdx/tag-types.ts (1)

1-317: LGTM!

packages/leadtype/src/mdx/index.ts (1)

1-79: LGTM!

apps/example/vite.config.ts (1)

5-5: LGTM!

Also applies to: 39-48

docs/reference/mdx.mdx (1)

1-258: LGTM!

docs/build/validate-in-ci.mdx (1)

5-5: LGTM!

docs/reference/llm.mdx (1)

455-455: LGTM!

docs/build/optimize-docs-for-agents.mdx (1)

5-5: LGTM!

Also applies to: 210-210

docs/authoring/components.mdx (1)

30-30: LGTM!

docs/package-docs/bundle.mdx (1)

34-34: LGTM!

Also applies to: 96-96, 171-171

packages/leadtype/src/internal/package-surface.test.ts (1)

11-12: LGTM!

packages/leadtype/src/index.ts (1)

1-10: LGTM!

Also applies to: 23-29

apps/fumadocs-example/mdx-components.tsx (1)

11-12: ⚡ Quick win

Verify the component merge order.

The spread order { ...components, ...mdxComponents } means mdxComponents will override any caller-provided components. Typically, user-provided components should take precedence over defaults, suggesting the order should be { ...mdxComponents, ...components }.

If the intent is for the shared mdxComponents map to always take precedence (preventing overrides), then this is correct. Otherwise, consider reversing the merge order.

🔄 Proposed fix if user components should override defaults
 export function useMDXComponents(components: MDXComponents): MDXComponents {
-  return { ...components, ...mdxComponents };
+  return { ...mdxComponents, ...components };
 }
docs/docs.config.ts (1)

18-19: LGTM!

apps/fumadocs-example/next.config.mjs (1)

1-27: LGTM!

apps/fumadocs-example/scripts/setup-source.ts (1)

20-36: LGTM!

apps/fumadocs-example/package.json (1)

35-35: ⚖️ Poor tradeoff

Verify the TypeScript version.

TypeScript 6.0.3 does not exist in the public npm registry (latest stable is 5.x). Along with the @typescript/native-preview experimental package dated May 2026, this suggests experimental or internal tooling.

Confirm whether:

  1. This is an internal/preview build that all team members can access
  2. CI/CD is configured to resolve this version
  3. This is intentional for testing upcoming TypeScript features

If this is a typo, the latest stable TypeScript 5.x should be used instead.

#!/bin/bash
# Check if TypeScript 6.0.3 exists in npm registry and find latest stable version
npm view typescript versions --json | jq -r '.[-10:]' || echo "Failed to fetch versions"
npm view typescript version || echo "Failed to fetch latest version"
packages/leadtype/rollup.config.ts (1)

8-9: LGTM!

apps/example/package.json (1)

20-21: LGTM!

apps/fumadocs-example/app/docs/layout.tsx (1)

1-57: LGTM!

docs/build/build-a-docs-site.mdx (1)

1-84: LGTM!

apps/fumadocs-example/lib/source.ts (1)

1-29: LGTM!

packages/leadtype/src/source/source.test.ts (1)

1-177: LGTM!

docs/build/use-the-source-primitive.mdx (1)

1-239: LGTM!

packages/leadtype/package.json (1)

28-35: LGTM!

packages/leadtype/src/llm/llm.ts (1)

68-82: LGTM!

Also applies to: 195-201, 540-604, 670-683, 1204-1209

apps/fumadocs-example/lib/mdx-components.tsx (1)

1-243: LGTM!

apps/example/src/components/docs-mdx/callout.tsx (1)

1-13: LGTM!

apps/fumadocs-example/app/docs/[[...slug]]/page.tsx (1)

21-70: LGTM!

docs/reference/source.mdx (1)

1-198: LGTM!

docs/build/generate-static-artifacts.mdx (1)

134-196: LGTM!

apps/example/src/routeTree.gen.ts (1)

1-392: LGTM!

packages/leadtype/src/source/index.ts (1)

204-364: LGTM!

packages/leadtype/src/fumadocs/index.ts (1)

138-144: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Consider logging malformed meta.json files for easier debugging.

The catch block silently ignores JSON parse errors. While the comment indicates fumadocs will surface a warning during page-tree building, adding a console warning here would help developers debug malformed files during development.

📝 Proposed logging addition
       try {
         data = JSON.parse(raw) as LeadtypeFumadocsMetaData;
-      } catch {
+      } catch (err) {
         // Malformed meta.json: keep the entry so fumadocs can surface a
         // helpful warning during page-tree building instead of silently
         // ignoring it.
+        console.warn(`Failed to parse ${relativePath}:`, err);
       }
			> Likely an incorrect or invalid review comment.

Comment thread apps/example/scripts/docs-source-manifest.ts Outdated
Comment thread apps/example/src/routes/docs/$.tsx Outdated
Comment on lines +74 to +80
const MdxComponent = useMemo(() => {
const loader = mdxModules[page.globKey];
if (!loader) {
return () => <MissingMdxModule urlPath={page.urlPath} />;
}
return lazy(loader);
}, [page.globKey, page.urlPath]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | 💤 Low value

Consider simplifying useMemo dependencies.

The useMemo depends on page.globKey and page.urlPath individually, but since page itself is derived from _splat, you could simplify by depending on page directly:

- }, [page.globKey, page.urlPath]);
+ }, [page]);

This is clearer and equally correct since any change to _splat produces a new page object reference.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const MdxComponent = useMemo(() => {
const loader = mdxModules[page.globKey];
if (!loader) {
return () => <MissingMdxModule urlPath={page.urlPath} />;
}
return lazy(loader);
}, [page.globKey, page.urlPath]);
const MdxComponent = useMemo(() => {
const loader = mdxModules[page.globKey];
if (!loader) {
return () => <MissingMdxModule urlPath={page.urlPath} />;
}
return lazy(loader);
}, [page]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/example/src/routes/docs/`$.tsx around lines 74 - 80, The useMemo for
MdxComponent currently lists [page.globKey, page.urlPath] as dependencies;
simplify this to depend on the whole page object instead (i.e., use [page]) so
that any change to _splat producing a new page reference will retrigger the
memo; keep the inner logic using mdxModules[page.globKey], lazy(loader), and
MissingMdxModule(urlPath) unchanged.

Comment thread docs/build/integrate-with-fumadocs.mdx
Comment thread packages/leadtype/src/convert/convert.ts Outdated
Comment thread packages/leadtype/src/lint/schema.ts Outdated
Comment thread packages/leadtype/src/remark/plugins/type-table-jsx.remark.ts
Comment on lines +99 to +103
parentChildren.splice(
index,
1,
replacement as unknown as Root["children"][number]
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | ⚖️ Poor tradeoff

Type assertion reduces type safety.

The as unknown as Root["children"][number] double-cast bypasses TypeScript's type checking. Consider defining a proper union type for MDX nodes that can appear in the tree, or using a type guard to validate the replacement node's type before insertion.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/leadtype/src/remark/plugins/type-table-jsx.remark.ts` around lines
99 - 103, The double-cast "as unknown as Root['children'][number]" bypasses
TypeScript checks; replace it by giving the replacement a proper typed identity
or narrowing it with a type guard before splicing. Define a union MDX node type
(e.g., type MdxNode = Root['children'][number] | SomeOtherNode...) or adjust the
function that produces replacement to return Root['children'][number], add a
predicate function isMdxNode(node): node is Root['children'][number] to validate
the value, and only call parentChildren.splice(index, 1, replacement) after the
type guard ensures replacement is the correct type (remove the double-cast).
Ensure references to replacement, parentChildren.splice and
Root['children'][number] are updated accordingly.

Comment thread packages/leadtype/src/source/index.ts Outdated
Comment thread packages/leadtype/src/source/index.ts Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6c6dfa2b5e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/leadtype/src/source/index.ts Outdated
Comment on lines +257 to +258
if (metaPath === target) {
return meta;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject duplicate slugs before serving a page

When contentDir contains two files that normalize to the same route, such as guide.mdx and guide/index.mdx or both .md and .mdx variants, deriveSlug() maps both to the same joined slug. This loop silently returns whichever file sorts first, while listPages() and buildSearchIndex() still expose duplicate urlPath/document IDs; resolveDocsNavigation() already treats duplicate routes as an error, so the new source primitive can render/search a different page instead of failing fast. Please validate cachedMetas for duplicate slug/url paths before load/search.

Useful? React with 👍 / 👎.

// Path the runtime catch-all can use to look up the MDX module against
// `import.meta.glob('../../../../docs/**/*.mdx')`. Always relative to
// src/routes/docs/$.tsx so the glob key matches exactly.
globKey: `${relative(join(appRoot, "src", "routes", "docs"), join(contentDir, page.relativePath))}${page.extension}`,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Normalize manifest glob keys to POSIX paths

When pipeline:source-manifest runs on Windows, path.relative() returns backslash-separated paths like ..\..\..\..\..\docs\quickstart.mdx, but Vite's import.meta.glob() keys are forward-slash paths. That makes mdxModules[page.globKey] undefined for every generated docs page and the catch-all route renders the missing-module fallback. Normalize this value to / separators before writing the manifest.

Useful? React with 👍 / 👎.

@KayleeWilliams
Copy link
Copy Markdown
Collaborator Author

@pullfrog review

Applied:
- docs-source-manifest: normalize globKey to POSIX so the manifest
  works on Windows (import.meta.glob keys are always forward-slash)
- docs/$.tsx: replace `as DocsPage` cast with an explicit null check
  that surfaces a clear error if the beforeLoad invariant ever breaks
- integrate-with-fumadocs.mdx: add missing `notFound` import to the
  Next App Router snippet
- convert.ts: simplify `compactMermaidBlocks` to `return markdown`
  (drop the no-op .replace call and the now-unused regex)
- fumadocs/index.ts: replace `loadPage: (slug) => leadtype.loadPage(slug)`
  with `loadPage: leadtype.loadPage` — no this binding needed
- lint/schema.ts: enforce integer `order:` via valibot pipe + integer
- type-table-jsx.remark.ts: add explicit `(tree: Root) => Root` return
  type to the public plugin factory
- source/index.ts: simplify the tocOptions ternary by dropping the
  awkward `as DocsTableOfContentsOptions` cast
- source/index.ts: add `cachedMetaBySlug: Map<string, DocsPageMeta>` so
  loadPage runs in O(1) instead of O(n) per call

Skipped (with reason):
- useMemo deps `[page]` vs `[page.globKey, page.urlPath]`: page is a
  stable reference from a Map so the alternatives are equivalent;
  depending on primitives is more defensive
- convertMdxFile `enrichFromGitFlag: boolean` annotation: matches the
  existing inferred-type convention used by convertMdxToMarkdown in
  the same file
- type-table-jsx double cast: the type incompatibility is between
  mdast-util-mdx's MdxJsxFlowElement and mdast's Root["children"][number]
  — a runtime type guard can't bridge that; the cast is the conventional
  escape hatch
Copy link
Copy Markdown

@pullfrog pullfrog Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

Three of the multi-framework walkthroughs the PR adds will mislead users following them verbatim (Nuxt MDC config, fumadocs server-component example, fumadocs-example layout's sidebar tabs), and the docs catch-all route prints a copy-paste command that doesn't exist. Inline comments below. There's also a small set of stale references left over from the connect-docs-site.mdx deletion that aren't anchored to lines in this diff — they're listed at the bottom of this body.

TL;DR — Ships the v1 headless integration surface (createDocsSource(), leadtype/mdx, leadtype/fumadocs), reshapes the onboarding docs around it, refactors the example app to a single catch-all route, and adds a fumadocs-example app. Also fixes a mermaid <br/> flattening bug that mangled labels in agent-flattened markdown.

Key changes

  • v1 integration surfacecreateDocsSource({ contentDir }) at root; new leadtype/mdx (mdxSourcePlugins preset + tag prop types) and leadtype/fumadocs (fumadocs Source adapter) subpaths; new convertMdxFile in-memory convert helper.
  • Quickstart + multi-framework walkthrough — framework-agnostic Quickstart, use-the-source-primitive umbrella covering Next App Router, Astro, Vite + @mdx-js/rollup, Nuxt, and SvelteKit + mdsvex, plus TL;DR blocks on the two main recipes.
  • Docs reshuffle — deletes overlapping connect-docs-site.mdx and render-mdx-and-toc.mdx; converts // filename code-block comments to title="..." fence meta; drops apps/example/ references from docs.
  • Mermaid <br/> preservation — strips the old <br/>- substitution in compactMermaidBlocks and updates the remark plugin's backtick stripper to handle the inline chart={\…`}` form.
  • Example app catch-allapps/example switches from 18 hand-rolled TanStack routes to a single [[...slug]] route powered by a build-time pipeline:source-manifest manifest.
  • fumadocs-example app — Next 15 + fumadocs-ui 15 wired to c15t docs as the content fixture, with framework switcher and tailwind v4.

Summary | 86 files | 1 commit | base: mainKayleeWilliams/better-rendering


v1 integration surface

Before: Consumers pieced together remark plugins, frontmatter parsing, and navigation by hand; no first-party fumadocs adapter.
After: createDocsSource() returns pages + navigation + search + include resolution; leadtype/mdx ships the source plugin preset and tag prop contracts; leadtype/fumadocs adapts the source to fumadocs-core's Source.

The new convertMdxFile returns the post-transform mdast ast alongside the serialized markdown so a renderer doesn't need to re-parse. Note the helper splits frontmatter with the regex form rather than going through parseFrontmatter — files whose frontmatter has no trailing newline before the body are silently treated as having no frontmatter, then synthesizeFrontmatter kicks in. Worth flagging once convertMdxFile is a documented public export.

packages/leadtype/src/source/index.ts · packages/leadtype/src/mdx/index.ts · packages/leadtype/src/fumadocs/index.ts · packages/leadtype/src/convert/convert.ts


Multi-framework walkthrough

Before: Quickstart linked to overlapping "connect-docs-site" / "render-mdx-and-toc" pages with framework details inlined per recipe.
After: Quickstart points at one umbrella page with anchor-linkable sections per framework, plus TL;DR copy-paste blocks on the two main recipes.

Three of the framework samples have concrete issues that will trip up the first user who pastes them — see the inline comments on the Nuxt and fumadocs blocks. The Astro, Vite + @mdx-js/rollup, and SvelteKit + mdsvex snippets line up with their upstream APIs (note: Vite users on @vitejs/plugin-react should add enforce: 'pre' to the mdx() plugin per the official @mdx-js/rollup guide, otherwise React parses MDX before mdx does).

docs/build/use-the-source-primitive.mdx · docs/build/integrate-with-fumadocs.mdx · docs/quickstart.mdx


Mermaid <br/> preservation

Before: compactMermaidBlocks rewrote <br/>- "for readability", breaking mermaid renderers downstream.
After: Pass is a stable seam that returns each block unchanged.

The remark plugin's backtick stripper also gained the inline chart={\…`} form. One asymmetry to note: the JSX-children form (flowchart LR
label) still flows through extractNodeTextmdastToString, which drops mdxJsxTextElementnodes entirely — so
is lost beforecleanMermaidSource` ever sees it. The new behavior is preserved only for the template-literal attribute form. Worth a regression test if the JSX-children form is supposed to work too.

packages/leadtype/src/remark/plugins/mermaid.remark.ts · packages/leadtype/src/convert/convert.ts


Example app catch-all

Before: 18 hand-rolled per-page TanStack route files.
After: One [[...slug]] catch-all reads a build-time docs-source-manifest.json and renders the matching MDX module via import.meta.glob.

The fallback MissingMdxModule component prints an actionable command — but the printed command doesn't match the actual script name (see inline). The manifest's globKey is also built from path.relative() which returns OS-native separators; the catch-all looks the key up against import.meta.glob keys that are always unix-style, so the manifest authored on Windows won't resolve any page.

apps/example/src/routes/docs/$.tsx · apps/example/scripts/docs-source-manifest.ts


Stale references after connect-docs-site / render-mdx-and-toc removal

These aren't anchored to lines in this diff, so they couldn't be left as inline comments — ordered by severity:

  1. README.md:30,61 and packages/leadtype/README.md:43 still link to https://leadtype.dev/docs/build/connect-docs-site. The package README ships in the npm tarball, so once published these are broken links in every node_modules/leadtype/README.md. Repoint at /docs/build/build-a-docs-site.
  2. evals/evals/wire-content-negotiation/EVAL.ts:33-38 asserts the agent read node_modules/leadtype/docs/build/connect-docs-site.md. The target file no longer exists, so the eval will fail on every run after this PR lands. Retarget at build-a-docs-site.md.
  3. packages/leadtype/README.md Entry points table doesn't list the new ./mdx and ./fumadocs subpath exports added by this PR (they're present in package.json and asserted by package-surface.test.ts).
  4. evals/lib/llms-variants.ts:127 still uses path: "docs/build/connect-docs-site.md" / title "Connect a docs site" in synthetic fixture content — self-contained, low impact, but terminology has drifted from the rest of the repo.

Also worth thinking about before 1.0: the newly-public resolveInclude / parseIncludeSpecifier / extractMdxSection helpers do plain path.resolve(baseDir, file) with no containment check, so an authored include of ../../../etc/passwd reads arbitrary files. Fine as long as include specifiers are trusted-author input, but it's worth documenting that contract on the export.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using Claude Opus𝕏

Comment thread apps/example/src/routes/docs/$.tsx Outdated
return (
<div data-leadtype-mdx-error>
MDX module not found for <code>{urlPath}</code>. Re-run{" "}
<code>bun run docs-source-manifest</code> after adding docs files.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Script name is wrong — there's no docs-source-manifest script in apps/example/package.json (the one this PR adds is pipeline:source-manifest, see line 20 of the manifest). A user hitting this error gets command not found.

Suggested change
<code>bun run docs-source-manifest</code> after adding docs files.
<code>bun run pipeline:source-manifest</code> after adding docs files.

Comment thread docs/build/use-the-source-primitive.mdx Outdated

export default defineNuxtConfig({
modules: ["@nuxtjs/mdc"],
mdc: { remarkPlugins: { ...mdxSourcePlugins } },
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mdxSourcePlugins is a PluggableList (array). Spreading it into an object literal produces { "0": pluginFn, "1": pluginFn, … }, which @nuxtjs/mdc won't recognize as plugins. Every other framework snippet on this page uses array spread; this one is the only outlier. Note also that @nuxtjs/mdc documents remarkPlugins as an object keyed by plugin name with { src, options } values, so the array form may still need adjusting for Nuxt — at minimum match the other snippets:

Suggested change
mdc: { remarkPlugins: { ...mdxSourcePlugins } },
mdc: { remarkPlugins: [...mdxSourcePlugins] },

Comment on lines +108 to +130
```tsx title="app/docs/[[...slug]]/page.tsx"
import { source } from "@/content/source";
import { MDXRemote } from "next-mdx-remote/rsc";

export default async function Page({
params,
}: {
params: Promise<{ slug?: string[] }>;
}) {
const { slug } = await params;
const page = await source.loadPage(slug ?? []);
if (!page) {
notFound();
}

return (
<article>
<h1>{page.title}</h1>
<MDXRemote source={page.markdown} components={mdxComponents} />
</article>
);
}
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Three problems in this server-component sample: (1) notFound() is called without import { notFound } from "next/navigation";; (2) mdxComponents is referenced but never imported; (3) next-mdx-remote/rsc is the Hashicorp package, while the rest of this PR (the live apps/fumadocs-example/app/docs/[[...slug]]/page.tsx and use-the-source-primitive.mdx) standardizes on next-mdx-remote-client/rsc — readers comparing the two pages will get conflicting answers. Aligning with the working example:

Suggested change
```tsx title="app/docs/[[...slug]]/page.tsx"
import { source } from "@/content/source";
import { MDXRemote } from "next-mdx-remote/rsc";
export default async function Page({
params,
}: {
params: Promise<{ slug?: string[] }>;
}) {
const { slug } = await params;
const page = await source.loadPage(slug ?? []);
if (!page) {
notFound();
}
return (
<article>
<h1>{page.title}</h1>
<MDXRemote source={page.markdown} components={mdxComponents} />
</article>
);
}
```
```tsx title="app/docs/[[...slug]]/page.tsx"
import { notFound } from "next/navigation";
import { MDXRemote } from "next-mdx-remote-client/rsc";
import { source } from "@/content/source";
import { mdxComponents } from "@/lib/mdx-components";
export default async function Page({
params,
}: {
params: Promise<{ slug?: string[] }>;
}) {
const { slug } = await params;
const page = await source.leadtype.loadPage(slug ?? []);
if (!page) {
notFound();
}
return (
<article>
<h1>{page.title}</h1>
<MDXRemote source={page.markdown} components={mdxComponents} />
</article>
);
}

Comment on lines +47 to +50
nav={{ title: "c15t docs" }}
sidebar={{
tabs: sidebarTabs,
banner: <FrameworkSwitcher knownRoutes={knownRoutes} />,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tabs is a top-level DocsLayout prop in fumadocs-ui v15, not a property of SidebarOptions. As written, sidebarTabs is silently dropped — the audience-grouping switcher won't render. The v15 SidebarOptions shape documents enabled, banner, components, collapsible, defaultOpenLevel, prefetch, footer only. Move tabs up one level:

Suggested change
nav={{ title: "c15t docs" }}
sidebar={{
tabs: sidebarTabs,
banner: <FrameworkSwitcher knownRoutes={knownRoutes} />,
tabs={sidebarTabs}
sidebar={{
banner: <FrameworkSwitcher knownRoutes={knownRoutes} />,
}}

// Path the runtime catch-all can use to look up the MDX module against
// `import.meta.glob('../../../../docs/**/*.mdx')`. Always relative to
// src/routes/docs/$.tsx so the glob key matches exactly.
globKey: `${relative(join(appRoot, "src", "routes", "docs"), join(contentDir, page.relativePath))}${page.extension}`,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

relative() returns OS-native path separators, but the catch-all looks up keys against import.meta.glob(...) which always uses forward slashes. On Windows the manifest will contain backslashes and every page 404s. Normalize before joining the extension:

Suggested change
globKey: `${relative(join(appRoot, "src", "routes", "docs"), join(contentDir, page.relativePath))}${page.extension}`,
globKey: `${relative(join(appRoot, "src", "routes", "docs"), join(contentDir, page.relativePath)).split(sep).join("/")}${page.extension}`,

Copy link
Copy Markdown

@pullfrog pullfrog Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No new issues. Reviewed the following changes:

  • Normalized the generated globKey in docs-source-manifest.ts to POSIX separators so the catch-all route resolves on Windows.
  • Replaced the as DocsPage cast in the docs catch-all with an explicit null check that narrows the type and surfaces an invariant-break error.
  • Added the missing notFound import to the fumadocs server-component recipe.
  • Simplified compactMermaidBlocks to a true no-op and dropped the now-dead MERMAID_FENCE_REGEX.
  • Unwrapped loadPage in the fumadocs adapter to a bare method reference (safe — the underlying function is a free closure, no this).
  • Tightened the frontmatter order: field to reject fractional values via v.pipe(v.number(), v.integer()).
  • Added an explicit (tree: Root) => Root return type to remarkResolveTypeTableJsx.
  • Introduced cachedMetaBySlug for O(1) findMetaForSlug lookups, populated alongside cachedMetas.
  • Cleaned up the tocOptions nested ternary and replaced the as DocsTableOfContentsOptions cast with an explicit annotation.

Pullfrog  | View workflow run | Using Claude Opus𝕏

Copy link
Copy Markdown

@pullfrog pullfrog Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

Incremental review covering only 8f0b1f1 ("Address PR review: 9 fixes, 3 skips"). The new changes are clean — nothing new to flag.

TL;DR — Addresses several items from the previous review. New changes look correct.

Verified in this commit

  • Windows globKeyapps/example/scripts/docs-source-manifest.ts now normalizes separators via a toPosix helper.
  • Catch-all invariantapps/example/src/routes/docs/$.tsx replaces the as DocsPage cast with an explicit null check that throws if beforeLoad's invariant ever breaks.
  • compactMermaidBlocks — Simplified to a pure return markdown; no-op, dropping the now-unused MERMAID_FENCE_REGEX.
  • findMetaForSlug O(1)createDocsSource now keeps a Map<string, DocsPageMeta> alongside cachedMetas, so loadPage() is a hash lookup after the first call.
  • fumadocsSource.loadPage — Bound directly to leadtype.loadPage rather than wrapped.
  • integrate-with-fumadocs server-component samplenotFound is now imported.
  • order frontmatter validation — Tightened from v.number() to v.pipe(v.number(), v.integer()), with a JSDoc note that fractional orders are rejected.

Summary | 11 files | 1 incremental commit | base: mainKayleeWilliams/better-rendering

Pullfrog  | View workflow run | Using Claude Opus𝕏

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
packages/leadtype/src/remark/plugins/type-table-jsx.remark.ts (1)

99-103: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace unsafe cast with type-preserving transformation to avoid mdast structure violations.

The plugin accepts both mdxJsxTextElement and mdxJsxFlowElement (lines 120–122) but unconditionally returns mdxJsxFlowElement (line 77), creating a silent type mismatch. When <ExtractedTypeTable> appears inline within a paragraph (phrasing context), the replacement violates mdast constraints since flow elements cannot appear in phrasing content. The cast on line 102 masks this error.

Preserve the node kind by accepting it as a parameter:

Preserve text vs flow node type, remove unsafe cast
import type { Root } from "mdast";
-import type { MdxJsxFlowElement } from "mdast-util-mdx";
+import type { MdxJsxFlowElement, MdxJsxTextElement } from "mdast-util-mdx";

function buildTypeTableNode(
  opts: {
    properties: Record<string, unknown>;
    title?: string;
    description?: string;
    name?: string;
    path?: string;
-}): MdxJsxFlowElement {
+  },
+  kind: "flow" | "text"
+): MdxJsxFlowElement | MdxJsxTextElement {
   const attributes: JsxAttribute[] = [
     expressionAttribute("properties", JSON.stringify(opts.properties)),
   ];
   if (opts.title) {
     attributes.push(stringAttribute("title", opts.title));
   }
   if (opts.description) {
     attributes.push(stringAttribute("description", opts.description));
   }
   if (opts.name) {
     attributes.push(stringAttribute("name", opts.name));
   }
   if (opts.path) {
     attributes.push(stringAttribute("path", opts.path));
   }
   return {
-    type: "mdxJsxFlowElement",
+    type: kind === "flow" ? "mdxJsxFlowElement" : "mdxJsxTextElement",
     name: "TypeTable",
     attributes: attributes as MdxJsxFlowElement["attributes"],
     children: [],
   };
 }

-    const replace = (
-      parentChildren: Root["children"],
+    const replace = <TNode>(
+      parentChildren: TNode[],
       index: number,
-      replacement: MdxJsxFlowElement
+      replacement: TNode
     ) => {
-      parentChildren.splice(
-        index,
-        1,
-        replacement as unknown as Root["children"][number]
-      );
+      parentChildren.splice(index, 1, replacement);
     };

           const extracted = extractTypeFromFile(path, name, overrideBasePath);
+          const kind = child.type === "mdxJsxFlowElement" ? "flow" : "text";
           replace(
             parentChildren,
             index,
             buildTypeTableNode({
               properties: extracted ?? {},
               title,
               description,
               name,
               path,
-            })
+            }, kind)
           );

Add test coverage for both block-level and inline usages of <ExtractedTypeTable> and <AutoTypeTable> to prevent regression.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/leadtype/src/remark/plugins/type-table-jsx.remark.ts` around lines
99 - 103, The replacement currently forces an mdxJsxFlowElement and masks that
with an unsafe cast in parentChildren.splice (replacement as unknown as
Root["children"][number]), which breaks mdast when the original node was an
mdxJsxTextElement; modify the transformer that creates replacement nodes (the
function producing replacement) to accept the original node kind (or the
original node itself) and construct a replacement of the same kind (create an
mdxJsxTextElement when input is mdxJsxTextElement, mdxJsxFlowElement when input
is mdxJsxFlowElement) instead of casting, update parentChildren.splice to insert
that correctly typed node, and add tests covering inline (phrasing) and block
(flow) usages of <ExtractedTypeTable> and <AutoTypeTable> to prevent
regressions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/leadtype/src/fumadocs/index.ts`:
- Around line 137-140: Summary: JSON.parse(raw) may produce non-object values
which are being assigned to data typed as LeadtypeFumadocsMetaData and can break
consumers. Fix: inside the try block, capture the parsed value (e.g., parsed =
JSON.parse(raw)) and validate its shape before assigning to data: ensure parsed
is a non-null object (and not an array) and optionally contains expected keys,
otherwise keep data as {} (and optionally log or throw). Reference symbols to
change: the variable data, the raw input, JSON.parse(raw), and the
LeadtypeFumadocsMetaData type.

---

Duplicate comments:
In `@packages/leadtype/src/remark/plugins/type-table-jsx.remark.ts`:
- Around line 99-103: The replacement currently forces an mdxJsxFlowElement and
masks that with an unsafe cast in parentChildren.splice (replacement as unknown
as Root["children"][number]), which breaks mdast when the original node was an
mdxJsxTextElement; modify the transformer that creates replacement nodes (the
function producing replacement) to accept the original node kind (or the
original node itself) and construct a replacement of the same kind (create an
mdxJsxTextElement when input is mdxJsxTextElement, mdxJsxFlowElement when input
is mdxJsxFlowElement) instead of casting, update parentChildren.splice to insert
that correctly typed node, and add tests covering inline (phrasing) and block
(flow) usages of <ExtractedTypeTable> and <AutoTypeTable> to prevent
regressions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: d0054611-7477-42be-b2b4-9a9a5828ca25

📥 Commits

Reviewing files that changed from the base of the PR and between 6c6dfa2 and 8f0b1f1.

⛔ Files ignored due to path filters (3)
  • apps/example/src/generated/agent-readability.json is excluded by !**/generated/**
  • apps/example/src/generated/docs-search-content.json is excluded by !**/generated/**
  • apps/example/src/generated/docs-search-index.json is excluded by !**/generated/**
📒 Files selected for processing (8)
  • apps/example/scripts/docs-source-manifest.ts
  • apps/example/src/routes/docs/$.tsx
  • docs/build/integrate-with-fumadocs.mdx
  • packages/leadtype/src/convert/convert.ts
  • packages/leadtype/src/fumadocs/index.ts
  • packages/leadtype/src/lint/schema.ts
  • packages/leadtype/src/remark/plugins/type-table-jsx.remark.ts
  • packages/leadtype/src/source/index.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use explicit types for function parameters and return values when they enhance clarity
Prefer unknown over any when the type is genuinely unknown
Use const assertions (as const) for immutable values and literal types
Leverage TypeScript's type narrowing instead of type assertions

Files:

  • packages/leadtype/src/lint/schema.ts
  • packages/leadtype/src/source/index.ts
  • packages/leadtype/src/convert/convert.ts
  • packages/leadtype/src/fumadocs/index.ts
  • apps/example/scripts/docs-source-manifest.ts
  • apps/example/src/routes/docs/$.tsx
  • packages/leadtype/src/remark/plugins/type-table-jsx.remark.ts
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,jsx,tsx}: Use meaningful variable names instead of magic numbers - extract constants with descriptive names
Use arrow functions for callbacks and short functions
Prefer for...of loops over .forEach() and indexed for loops
Use optional chaining (?.) and nullish coalescing (??) for safer property access
Prefer template literals over string concatenation
Use destructuring for object and array assignments
Use const by default, let only when reassignment is needed, never var
Always await promises in async functions - don't forget to use the return value
Use async/await syntax instead of promise chains for better readability
Handle errors appropriately in async code with try-catch blocks
Don't use async functions as Promise executors
Remove console.log, debugger, and alert statements from production code
Throw Error objects with descriptive messages, not strings or other values
Use try-catch blocks meaningfully - don't catch errors just to rethrow them
Prefer early returns over nested conditionals for error cases
Extract complex conditions into well-named boolean variables
Use early returns to reduce nesting
Prefer simple conditionals over nested ternary operators
Don't use eval() or assign directly to document.cookie
Avoid spread syntax in accumulators within loops
Use top-level regex literals instead of creating them in loops
Prefer specific imports over namespace imports
Use descriptive names for functions, variables, and types for meaningful naming
Add comments for complex logic, but prefer self-documenting code

Files:

  • packages/leadtype/src/lint/schema.ts
  • packages/leadtype/src/source/index.ts
  • packages/leadtype/src/convert/convert.ts
  • packages/leadtype/src/fumadocs/index.ts
  • apps/example/scripts/docs-source-manifest.ts
  • apps/example/src/routes/docs/$.tsx
  • packages/leadtype/src/remark/plugins/type-table-jsx.remark.ts
**/index.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Avoid barrel files (index files that re-export everything)

Files:

  • packages/leadtype/src/source/index.ts
  • packages/leadtype/src/fumadocs/index.ts
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{jsx,tsx}: Use function components over class components in React
Call hooks at the top level only, never conditionally
Specify all dependencies in hook dependency arrays correctly
Use the key prop for elements in iterables (prefer unique IDs over array indices)
Nest children between opening and closing tags instead of passing as props
Don't define components inside other components
Avoid dangerouslySetInnerHTML unless absolutely necessary
Use proper image components (e.g., Next.js <Image>) over <img> tags
Use Next.js <Image> component for images
Use next/head or App Router metadata API for head elements in Next.js
Use Server Components for async data fetching instead of async Client Components in Next.js
Use ref as a prop instead of React.forwardRef in React 19+

Files:

  • apps/example/src/routes/docs/$.tsx
**/*.{jsx,tsx,html}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{jsx,tsx,html}: Use semantic HTML and ARIA attributes for accessibility: provide meaningful alt text for images, use proper heading hierarchy, add labels for form inputs, include keyboard event handlers alongside mouse events, use semantic elements instead of divs with roles
Add rel="noopener" when using target="_blank" on links

Files:

  • apps/example/src/routes/docs/$.tsx
🔇 Additional comments (7)
packages/leadtype/src/lint/schema.ts (1)

57-65: LGTM!

packages/leadtype/src/convert/convert.ts (1)

7-7: LGTM!

Also applies to: 227-233, 331-405

packages/leadtype/src/source/index.ts (1)

1-360: LGTM!

apps/example/scripts/docs-source-manifest.ts (1)

1-64: LGTM!

apps/example/src/routes/docs/$.tsx (1)

1-95: LGTM!

docs/build/integrate-with-fumadocs.mdx (1)

1-150: LGTM!

packages/leadtype/src/remark/plugins/type-table-jsx.remark.ts (1)

1-93: LGTM!

Also applies to: 155-165

Comment thread packages/leadtype/src/fumadocs/index.ts
Applied (5 of 6):
- docs-source-manifest reference fixed: error fallback in docs/$.tsx
  now points at `bun run pipeline:source-manifest` (the actual script
  name in apps/example/package.json), not the non-existent
  `docs-source-manifest`
- Nuxt snippet uses array spread `[...mdxSourcePlugins]` instead of
  object spread `{ ...mdxSourcePlugins }` — same fix in both
  docs/build/use-the-source-primitive.mdx and docs/reference/source.mdx.
  Object spread on a PluggableList produced `{ "0": fn, ... }` which
  @nuxtjs/mdc would reject
- Fumadocs server-component snippet aligned with the rest of the PR:
  imports MDXRemote from `next-mdx-remote-client/rsc` (matching the
  working apps/fumadocs-example app), adds the missing `mdxComponents`
  import, calls `source.leadtype.loadPage()` (the actual adapter shape)
  instead of bare `source.loadPage()`
- createDocsSource throws on duplicate slugs or urlPaths instead of
  silently picking whichever file sorts first. Matches the existing
  behavior of resolveDocsNavigation (which already errors on
  collisions) so the source primitive is consistent
- readMetaFiles validates JSON.parse output is a plain object before
  treating it as LeadtypeFumadocsMetaData — arrays/strings/numbers/null
  now fall through to the default `{}` rather than being passed to
  fumadocs as misshapen metadata

Skipped (1):
- fumadocs-example DocsLayout `tabs` prop placement: the pullfrog
  feedback says `tabs` is a top-level prop, but fumadocs-ui@15.8.5's
  installed `SidebarOptions` type explicitly includes
  `tabs?: Option[] | GetSidebarTabsOptions | false`. The nested form
  is correct for this version
Copy link
Copy Markdown

@pullfrog pullfrog Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

Two of the second-round fixes ship docs snippets that won't work as written: the fumadocs server-component snippet calls loadPage on undefined, and the Nuxt snippet still mismatches @nuxtjs/mdc's expected remarkPlugins shape. Other changes in this round verified correct.

Reviewed the following changes:

  • Pointed the catch-all error fallback at pipeline:source-manifest (the actual script name)
  • Aligned the fumadocs server-component snippet with the working example app (next-mdx-remote-client/rsc, mdxComponents import)
  • Switched the Nuxt remarkPlugins spread from object-spread to array-spread in both the source-primitive walkthrough and source reference (still not the right shape — see comment)
  • Added duplicate-slug/urlPath rejection to createDocsSource so it mirrors resolveDocsNavigation's collision behavior
  • Validated JSON.parse output is a plain object in readMetaFiles before treating it as fumadocs metadata

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using Claude Opus𝕏

params: Promise<{ slug?: string[] }>;
}) {
const { slug } = await params;
const page = await source.leadtype.loadPage(slug ?? []);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

source here is the result of fumadocs-core's loader({ source: fumadocsSource(...) }). loader() returns a fixed-shape LoaderOutput (getPage, getPages, pageTree, …) and does not preserve arbitrary properties from the input source, so source.leadtype is undefined and this line throws TypeError: Cannot read properties of undefined (reading 'loadPage') at runtime. The working apps/fumadocs-example/lib/source.ts:29 deliberately exports leadtypeSource = fumadocsSourceResult.leadtype from the pre-loader value — match that pattern here. The same defect exists at the TL;DR claim on line 66 and the search snippet on line 143 (outside this commit's diff, but worth fixing in the same pass).


export default defineNuxtConfig({
modules: ["@nuxtjs/mdc"],
mdc: { remarkPlugins: [...mdxSourcePlugins] },
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nuxtjs/mdc types remarkPlugins as Record<string, UnistPlugin | false> keyed by plugin name (see nuxt-modules/mdc/src/types/module.ts), not a unified PluggableList. Spreading mdxSourcePlugins (an array of plugin functions) into either { ... } or [ ... ] won't produce that shape — the snippet still won't compile. Either drop the Nuxt section or restructure it so each plugin is registered under a name (e.g. { 'leadtype-include': { src: '…' }, … }). The same applies to docs/reference/source.mdx:168.

Comment thread docs/reference/source.mdx
export default defineNuxtConfig({
modules: ["@nuxtjs/mdc"],
mdc: {
remarkPlugins: [...mdxSourcePlugins],
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as use-the-source-primitive.mdx:115@nuxtjs/mdc.remarkPlugins is Record<string, UnistPlugin | false> keyed by plugin name, so an array spread of mdxSourcePlugins (PluggableList of bare functions) doesn't match. The fix from object-spread to array-spread improves PluggableList type alignment but still isn't what @nuxtjs/mdc accepts.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/leadtype/src/source/index.ts`:
- Around line 126-129: The JSDoc comment for the include-resolution option uses
the wrong name (`fromPath`) which doesn't match the implementation/API
(`fromDir`); update the JSDoc to mention `fromDir` (or alternatively rename the
API to `fromPath` if you prefer that external name) so the exported DocsSource
type and its include-resolution method signature are consistent; look for the
exported DocsSource type and the include resolve method in
packages/leadtype/src/source/index.ts and change the JSDoc option name from
`fromPath` to `fromDir` (or rename the corresponding option in the
implementation and type if you choose the `fromPath` spelling).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 11b73fac-384a-49d2-a8fc-2d06a8247479

📥 Commits

Reviewing files that changed from the base of the PR and between 8f0b1f1 and 2156a52.

⛔ Files ignored due to path filters (3)
  • apps/example/src/generated/agent-readability.json is excluded by !**/generated/**
  • apps/example/src/generated/docs-search-content.json is excluded by !**/generated/**
  • apps/example/src/generated/docs-search-index.json is excluded by !**/generated/**
📒 Files selected for processing (6)
  • apps/example/src/routes/docs/$.tsx
  • docs/build/integrate-with-fumadocs.mdx
  • docs/build/use-the-source-primitive.mdx
  • docs/reference/source.mdx
  • packages/leadtype/src/fumadocs/index.ts
  • packages/leadtype/src/source/index.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use explicit types for function parameters and return values when they enhance clarity
Prefer unknown over any when the type is genuinely unknown
Use const assertions (as const) for immutable values and literal types
Leverage TypeScript's type narrowing instead of type assertions

Files:

  • apps/example/src/routes/docs/$.tsx
  • packages/leadtype/src/source/index.ts
  • packages/leadtype/src/fumadocs/index.ts
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,jsx,tsx}: Use meaningful variable names instead of magic numbers - extract constants with descriptive names
Use arrow functions for callbacks and short functions
Prefer for...of loops over .forEach() and indexed for loops
Use optional chaining (?.) and nullish coalescing (??) for safer property access
Prefer template literals over string concatenation
Use destructuring for object and array assignments
Use const by default, let only when reassignment is needed, never var
Always await promises in async functions - don't forget to use the return value
Use async/await syntax instead of promise chains for better readability
Handle errors appropriately in async code with try-catch blocks
Don't use async functions as Promise executors
Remove console.log, debugger, and alert statements from production code
Throw Error objects with descriptive messages, not strings or other values
Use try-catch blocks meaningfully - don't catch errors just to rethrow them
Prefer early returns over nested conditionals for error cases
Extract complex conditions into well-named boolean variables
Use early returns to reduce nesting
Prefer simple conditionals over nested ternary operators
Don't use eval() or assign directly to document.cookie
Avoid spread syntax in accumulators within loops
Use top-level regex literals instead of creating them in loops
Prefer specific imports over namespace imports
Use descriptive names for functions, variables, and types for meaningful naming
Add comments for complex logic, but prefer self-documenting code

Files:

  • apps/example/src/routes/docs/$.tsx
  • packages/leadtype/src/source/index.ts
  • packages/leadtype/src/fumadocs/index.ts
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{jsx,tsx}: Use function components over class components in React
Call hooks at the top level only, never conditionally
Specify all dependencies in hook dependency arrays correctly
Use the key prop for elements in iterables (prefer unique IDs over array indices)
Nest children between opening and closing tags instead of passing as props
Don't define components inside other components
Avoid dangerouslySetInnerHTML unless absolutely necessary
Use proper image components (e.g., Next.js <Image>) over <img> tags
Use Next.js <Image> component for images
Use next/head or App Router metadata API for head elements in Next.js
Use Server Components for async data fetching instead of async Client Components in Next.js
Use ref as a prop instead of React.forwardRef in React 19+

Files:

  • apps/example/src/routes/docs/$.tsx
**/*.{jsx,tsx,html}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{jsx,tsx,html}: Use semantic HTML and ARIA attributes for accessibility: provide meaningful alt text for images, use proper heading hierarchy, add labels for form inputs, include keyboard event handlers alongside mouse events, use semantic elements instead of divs with roles
Add rel="noopener" when using target="_blank" on links

Files:

  • apps/example/src/routes/docs/$.tsx
**/index.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Avoid barrel files (index files that re-export everything)

Files:

  • packages/leadtype/src/source/index.ts
  • packages/leadtype/src/fumadocs/index.ts
🪛 LanguageTool
docs/reference/source.mdx

[style] ~9-~9: Consider using “who” when you are referring to a person instead of an object.
Context: ...-neutral** entry point for any consumer that wants to render leadtype-authored MDX i...

(THAT_WHO)


[style] ~96-~96: This phrase is redundant. Consider using “outside”.
Context: ...ontentDir`. Useful for loading partials outside of the MDX compile path. ## Choosing betw...

(OUTSIDE_OF)

🔇 Additional comments (5)
apps/example/src/routes/docs/$.tsx (1)

1-94: LGTM!

packages/leadtype/src/fumadocs/index.ts (1)

1-165: LGTM!

docs/build/integrate-with-fumadocs.mdx (1)

1-151: LGTM!

docs/build/use-the-source-primitive.mdx (1)

1-239: LGTM!

docs/reference/source.mdx (1)

1-198: LGTM!

Comment on lines +126 to +129
* Resolve an `<include>` reference outside of a remark pass (e.g. when
* loading a partial for direct rendering). `fromPath` defaults to
* `contentDir`.
*/
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix JSDoc option name mismatch for include resolution.

The public comment says fromPath, but the API and implementation use fromDir. This can mislead consumers of the exported DocsSource type.

Suggested patch
-   * loading a partial for direct rendering). `fromPath` defaults to
+   * loading a partial for direct rendering). `fromDir` defaults to
    * `contentDir`.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
* Resolve an `<include>` reference outside of a remark pass (e.g. when
* loading a partial for direct rendering). `fromPath` defaults to
* `contentDir`.
*/
* Resolve an `<include>` reference outside of a remark pass (e.g. when
* loading a partial for direct rendering). `fromDir` defaults to
* `contentDir`.
*/
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/leadtype/src/source/index.ts` around lines 126 - 129, The JSDoc
comment for the include-resolution option uses the wrong name (`fromPath`) which
doesn't match the implementation/API (`fromDir`); update the JSDoc to mention
`fromDir` (or alternatively rename the API to `fromPath` if you prefer that
external name) so the exported DocsSource type and its include-resolution method
signature are consistent; look for the exported DocsSource type and the include
resolve method in packages/leadtype/src/source/index.ts and change the JSDoc
option name from `fromPath` to `fromDir` (or rename the corresponding option in
the implementation and type if you choose the `fromPath` spelling).

Was missing from the multi-framework section even though apps/example
itself runs on TanStack Start. Added the section in three places:

- docs/build/use-the-source-primitive.mdx — new `### TanStack Start`
  section between Astro and Vite, with the vite.config.ts wiring
  (mdx + tanstackStart + viteReact) and a catch-all route snippet
- docs/quickstart.mdx — new Card linking to the TanStack Start anchor
- docs/reference/source.mdx — parallel TanStack Start snippet in the
  Framework integrations section, with a cross-link to the longer
  walkthrough for the catch-all pattern

The TanStack Router catch-all snippet uses the same import.meta.glob +
build-time manifest pattern that apps/example dogfoods, generalized so
docs readers can reproduce it without reading the apps/ source.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (2)
docs/reference/source.mdx (1)

189-196: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Nuxt snippet likely uses the wrong remarkPlugins shape.

At Line 195, mdc.remarkPlugins: [...mdxSourcePlugins] appears incompatible with @nuxtjs/mdc’s keyed plugin registration shape, so this example can fail for users copying it.

For `@nuxtjs/mdc`, what is the exact expected type/shape for `mdc.remarkPlugins` in `defineNuxtConfig`, and how should unified remark plugins (function arrays like `PluggableList`) be registered?
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/reference/source.mdx` around lines 189 - 196, The example sets
mdc.remarkPlugins to an array of functions (spread mdxSourcePlugins) which
doesn't match `@nuxtjs/mdc`'s expected keyed plugin registration shape; update the
snippet so that inside defineNuxtConfig you assign mdc.remarkPlugins as an
object mapping a key (e.g., "default" or a filename) to the unified plugin list
(PluggableList) or wrap the PluggableList in the expected { remarkPlugins: {
"<key>": [...] } } shape; locate the mdxSourcePlugins usage and change the
registration to the keyed form required by `@nuxtjs/mdc` so unified remark plugins
are registered under a key rather than passed directly as top-level array.
docs/build/use-the-source-primitive.mdx (1)

179-185: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Nuxt config repeats the same remarkPlugins shape mismatch.

Line 184 uses array spread for mdc.remarkPlugins; this appears to conflict with Nuxt MDC’s expected keyed plugin config and can produce a non-working recipe.

In current `@nuxtjs/mdc` docs/source, does `mdc.remarkPlugins` accept an array of plugin functions, or only an object keyed by plugin name? Please include a minimal valid `nuxt.config.ts` example.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/build/use-the-source-primitive.mdx` around lines 179 - 185, The Nuxt
example incorrectly spreads mdxSourcePlugins into mdc.remarkPlugins (using
mdxSourcePlugins and mdc.remarkPlugins) which mismatches `@nuxtjs/mdc`'s expected
keyed-plugin config; update the docs to show the correct shape by replacing the
array spread with an object keyed by plugin name(s) (e.g., map the imported
mdxSourcePlugins to the plugin key expected by `@nuxtjs/mdc`) and provide a
minimal valid nuxt.config.ts that uses defineNuxtConfig and imports
mdxSourcePlugins, sets modules: ["@nuxtjs/mdc"], and assigns mdc.remarkPlugins
to the proper keyed object form instead of [...mdxSourcePlugins].
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@docs/build/use-the-source-primitive.mdx`:
- Around line 179-185: The Nuxt example incorrectly spreads mdxSourcePlugins
into mdc.remarkPlugins (using mdxSourcePlugins and mdc.remarkPlugins) which
mismatches `@nuxtjs/mdc`'s expected keyed-plugin config; update the docs to show
the correct shape by replacing the array spread with an object keyed by plugin
name(s) (e.g., map the imported mdxSourcePlugins to the plugin key expected by
`@nuxtjs/mdc`) and provide a minimal valid nuxt.config.ts that uses
defineNuxtConfig and imports mdxSourcePlugins, sets modules: ["@nuxtjs/mdc"],
and assigns mdc.remarkPlugins to the proper keyed object form instead of
[...mdxSourcePlugins].

In `@docs/reference/source.mdx`:
- Around line 189-196: The example sets mdc.remarkPlugins to an array of
functions (spread mdxSourcePlugins) which doesn't match `@nuxtjs/mdc`'s expected
keyed plugin registration shape; update the snippet so that inside
defineNuxtConfig you assign mdc.remarkPlugins as an object mapping a key (e.g.,
"default" or a filename) to the unified plugin list (PluggableList) or wrap the
PluggableList in the expected { remarkPlugins: { "<key>": [...] } } shape;
locate the mdxSourcePlugins usage and change the registration to the keyed form
required by `@nuxtjs/mdc` so unified remark plugins are registered under a key
rather than passed directly as top-level array.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2589a7ca-fbef-460f-80f3-c017c6f7224e

📥 Commits

Reviewing files that changed from the base of the PR and between 2156a52 and a194396.

⛔ Files ignored due to path filters (4)
  • apps/example/src/generated/agent-readability.json is excluded by !**/generated/**
  • apps/example/src/generated/docs-nav.json is excluded by !**/generated/**
  • apps/example/src/generated/docs-search-content.json is excluded by !**/generated/**
  • apps/example/src/generated/docs-search-index.json is excluded by !**/generated/**
📒 Files selected for processing (3)
  • docs/build/use-the-source-primitive.mdx
  • docs/quickstart.mdx
  • docs/reference/source.mdx
📜 Review details
🧰 Additional context used
🪛 LanguageTool
docs/reference/source.mdx

[style] ~9-~9: Consider using “who” when you are referring to a person instead of an object.
Context: ...-neutral** entry point for any consumer that wants to render leadtype-authored MDX i...

(THAT_WHO)


[style] ~96-~96: This phrase is redundant. Consider using “outside”.
Context: ...ontentDir`. Useful for loading partials outside of the MDX compile path. ## Choosing betw...

(OUTSIDE_OF)

🔇 Additional comments (1)
docs/quickstart.mdx (1)

3-3: LGTM!

Also applies to: 9-10, 17-110

Copy link
Copy Markdown

@pullfrog pullfrog Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the following changes:

  • Added a TanStack Start recipe to use-the-source-primitive.mdx (vite.config.ts wiring + catch-all src/routes/docs/$.tsx).
  • Duplicated the TanStack Start vite.config.ts into reference/source.mdx with a link back to the walkthrough.
  • Added a TanStack Start Card to the Quickstart "Pick the recipe" grid.
  • Regenerated apps/example agent-readability, docs-nav, and docs-search artifacts to pick up the new section.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using Claude Opus𝕏

Comment thread docs/build/use-the-source-primitive.mdx Outdated
if (!page) {
return null;
}
const Mdx = lazy(mdxModules[page.globKey]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling lazy() in the render body creates a fresh lazy component on every render, defeating Suspense caching and triggering remount loops on parent re-renders. React's lazy is documented to be called at module scope or memoized (https://react.dev/reference/react/lazy#caveats). The working reference at apps/example/src/routes/docs/$.tsx:81 wraps this in useMemo keyed by page.globKey and also guards mdxModules[page.globKey] being undefined — worth mirroring here since this snippet is meant to be copy-pasted.

The snippet I added in a194396 called lazy(mdxModules[page.globKey])
inline in the render body. React's lazy() is documented to be called
at module scope or memoized — calling it inline returns a fresh lazy
component on every render, busts Suspense's cache, and remounts the
MDX page on every parent re-render.

Also added a guard for mdxModules[page.globKey] being undefined (stale
manifest, file deleted between builds), matching the working pattern
in apps/example's catch-all. Since this snippet is meant to be copy-
pasted, it needs to mirror the production-ready shape rather than the
shortest-possible one.

Wraps the lazy() call in useMemo keyed by [page.globKey, page.urlPath]
and adds a MissingMdxModule fallback for the unresolved-loader case.
Copy link
Copy Markdown

@pullfrog pullfrog Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No new issues. Reviewed the following changes:

  • Memoized the TanStack catch-all's lazy() call in docs/build/use-the-source-primitive.mdx, addressing the prior round's MINOR finding — the snippet now mirrors the working reference at apps/example/src/routes/docs/$.tsx (typed DocsPage, resolvePage helper, useMemo keyed by globKey/urlPath, MissingMdxModule fallback when the glob is stale).
  • Regenerated apps/example/src/generated/{agent-readability,docs-search-content,docs-search-index}.json to reflect the updated snippet.

Prior open findings on docs/build/integrate-with-fumadocs.mdx (source.leadtype.loadPage() on a fumadocs loader result) and Nuxt remarkPlugins: [...mdxSourcePlugins] typing in use-the-source-primitive.mdx / reference/source.mdx are not touched by this commit.
false

Pullfrog  | Fix it ➔View workflow run | Using Claude Opus𝕏

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
docs/build/use-the-source-primitive.mdx (1)

204-210: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Verify the @nuxtjs/mdc remarkPlugins configuration.

Previous review identified that @nuxtjs/mdc types remarkPlugins as Record<string, UnistPlugin | false> keyed by plugin name, not as a PluggableList array. Spreading mdxSourcePlugins (an array) into [...] won't produce the expected object shape { 'plugin-name': { src: '...' }, ... }.

Either restructure the snippet so each plugin is registered under a name, or consider removing the Nuxt example until the correct API shape is confirmed.

Run the following script to verify the @nuxtjs/mdc type signature:

#!/bin/bash
# Description: Check `@nuxtjs/mdc` remarkPlugins type definition

# Search for the type definition in node_modules if `@nuxtjs/mdc` is installed
fd -t f "module.ts|types.ts" node_modules/@nuxtjs/mdc -x cat {} | rg -A5 -B5 "remarkPlugins"

# If not installed locally, check the npm registry metadata
echo "---"
echo "Checking npm package info:"
npm view `@nuxtjs/mdc` repository.url

Alternatively, search for the official @nuxtjs/mdc documentation on the correct remarkPlugins format:

`@nuxtjs/mdc` remarkPlugins configuration format
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/build/use-the-source-primitive.mdx` around lines 204 - 210, The Nuxt
snippet incorrectly spreads the array mdxSourcePlugins into mdc.remarkPlugins
which expects a Record keyed by plugin name (not a PluggableList); update the
nuxt.config.ts example to register each plugin under a name (e.g., build an
object like { "plugin-name": pluginConfig, ... } derived from mdxSourcePlugins)
or remove the `@nuxtjs/mdc` example until you confirm the API shape; locate the
config in the file where mdxSourcePlugins and mdc.remarkPlugins are referenced
and either transform the array into the required named object mapping or delete
the block and add a comment to reintroduce it after verifying the `@nuxtjs/mdc`
remarkPlugins type signature.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@docs/build/use-the-source-primitive.mdx`:
- Around line 204-210: The Nuxt snippet incorrectly spreads the array
mdxSourcePlugins into mdc.remarkPlugins which expects a Record keyed by plugin
name (not a PluggableList); update the nuxt.config.ts example to register each
plugin under a name (e.g., build an object like { "plugin-name": pluginConfig,
... } derived from mdxSourcePlugins) or remove the `@nuxtjs/mdc` example until you
confirm the API shape; locate the config in the file where mdxSourcePlugins and
mdc.remarkPlugins are referenced and either transform the array into the
required named object mapping or delete the block and add a comment to
reintroduce it after verifying the `@nuxtjs/mdc` remarkPlugins type signature.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8c3e006a-21d7-4a3b-9d86-9c56f1668be5

📥 Commits

Reviewing files that changed from the base of the PR and between a194396 and 841b8d9.

⛔ Files ignored due to path filters (3)
  • apps/example/src/generated/agent-readability.json is excluded by !**/generated/**
  • apps/example/src/generated/docs-search-content.json is excluded by !**/generated/**
  • apps/example/src/generated/docs-search-index.json is excluded by !**/generated/**
📒 Files selected for processing (1)
  • docs/build/use-the-source-primitive.mdx
📜 Review details
🔇 Additional comments (7)
docs/build/use-the-source-primitive.mdx (7)

1-27: LGTM!


42-78: LGTM!


80-186: LGTM!


188-200: LGTM!


213-223: LGTM!


225-319: LGTM!


321-333: LGTM!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant