import type { GeneratedDoc, Generator } from 'fumadocs-typescript'; import { filterGeneratedDoc, getSharedPropProject, loadExportedPropDeclaration, lukeUiReactSrcDir, typeForwardsDomProps, } from './component-prop-analysis.js'; import { NATIVE_PROPS_FORWARDING_KEY, renderNativePropsNote } from './component-prop-groups.js'; import type { LiveTypescriptGeneratorOptions } from './create-live-typescript-generator.js'; import { createLiveTypescriptGenerator } from './create-live-typescript-generator.js'; import { enrichGeneratedDocTypes } from './enrich-generated-doc-types.js'; interface GenerateDocumentationOptions { basePath?: string; } /** * Wraps the fumadocs generator to remove generic DOM props from component Props tables, restore their * declared types, and collect the definitions those types name. */ export function createComponentPropsGenerator( options: LiveTypescriptGeneratorOptions = {}, ): Generator { const generator = createLiveTypescriptGenerator(options); const generateDocumentation = generator.generateDocumentation.bind(generator); generator.generateDocumentation = async (file, name, generateOptions = {}) => { const docs = await generateDocumentation(file, name, generateOptions); const basePath = (generateOptions as GenerateDocumentationOptions).basePath; if (name === undefined || file.path === undefined || basePath === undefined) { return docs; } const repoRoot = basePath; const project = await getSharedPropProject(repoRoot); const declaration = loadExportedPropDeclaration( project, repoRoot, relativeRepoPath(repoRoot, file.path), name, ); if (declaration === undefined) return docs; const reactSrcDir = lukeUiReactSrcDir(repoRoot); const checker = project.getTypeChecker().compilerObject; const forwardsDomProps = typeForwardsDomProps(declaration, reactSrcDir); return docs.map((doc) => enrichGeneratedDocTypes( markNativePropsForwarding( filterGeneratedDoc(doc, declaration, reactSrcDir), name, forwardsDomProps, ), declaration, reactSrcDir, checker, ), ); }; return generator; } /** * Appends a reserved entry carrying the native-props note markdown, so the client-side table can * render it without importing the ts-morph analysis that decided the type forwards DOM props. */ function markNativePropsForwarding( doc: GeneratedDoc, exportName: string, forwardsDomProps: boolean, ): GeneratedDoc { if (!forwardsDomProps) return doc; return { ...doc, entries: [ ...doc.entries, { deprecated: false, description: renderNativePropsNote(exportName), name: NATIVE_PROPS_FORWARDING_KEY, required: true, simplifiedType: '', tags: [], type: '', }, ], }; } function relativeRepoPath(repoRoot: string, absolutePath: string): string { return absolutePath.startsWith(`${repoRoot}/`) ? absolutePath.slice(repoRoot.length + 1) : absolutePath; }