diff --git a/apps/docs/lib/mdx-scopes.ts b/apps/docs/lib/mdx-scopes.ts new file mode 100644 index 00000000..833bb055 --- /dev/null +++ b/apps/docs/lib/mdx-scopes.ts @@ -0,0 +1,125 @@ +/** + * Type definitions for MDX scope variables. + * + * Each MDX content file receives a typed scope object via renderMDX. + * This file defines the scope interfaces for each MDX file and exports + * a registry mapping file paths to their expected scope types. + */ +import type { + PreloadMultiFileDiffResult, + PreloadedFileResult, +} from '@pierre/diffs/ssr'; + +import type { PackageManager } from '../app/docs/Installation/constants'; + +// ============================================================================= +// Individual Scope Interfaces +// ============================================================================= + +export interface InstallationScope { + installationExamples: Record>; +} + +export interface CoreTypesScope { + fileContentsType: PreloadedFileResult; + fileDiffMetadataType: PreloadedFileResult; + parseDiffFromFileExample: PreloadedFileResult; + parsePatchFilesExample: PreloadedFileResult; +} + +export interface OverviewScope { + initialDiffProps: PreloadMultiFileDiffResult; + reactSingleFile: PreloadedFileResult; + reactPatchFile: PreloadedFileResult; + vanillaSingleFile: PreloadedFileResult; + vanillaPatchFile: PreloadedFileResult; +} + +export interface ReactAPIScope { + reactAPIMultiFileDiff: PreloadedFileResult; + reactAPIPatch: PreloadedFileResult; + reactAPIFileDiff: PreloadedFileResult; + reactAPIFile: PreloadedFileResult; + sharedDiffOptions: PreloadedFileResult; + sharedDiffRenderProps: PreloadedFileResult; + sharedFileOptions: PreloadedFileResult; + sharedFileRenderProps: PreloadedFileResult; +} + +export interface VanillaAPIScope { + fileDiffExample: PreloadedFileResult; + fileExample: PreloadedFileResult; + fileDiffProps: PreloadedFileResult; + fileProps: PreloadedFileResult; + customHunk: PreloadedFileResult; + diffHunksRenderer: PreloadedFileResult; + diffHunksRendererPatch: PreloadedFileResult; + fileRenderer: PreloadedFileResult; +} + +export interface UtilitiesScope { + diffAcceptReject: PreloadedFileResult; + diffAcceptRejectReact: PreloadedFileResult; + disposeHighlighter: PreloadedFileResult; + getSharedHighlighter: PreloadedFileResult; + parseDiffFromFile: PreloadedFileResult; + parsePatchFiles: PreloadedFileResult; + preloadHighlighter: PreloadedFileResult; + registerCustomTheme: PreloadedFileResult; + setLanguageOverride: PreloadedFileResult; +} + +export interface StylingScope { + stylingGlobal: PreloadedFileResult; + stylingInline: PreloadedFileResult; + stylingUnsafe: PreloadedFileResult; +} + +export interface SSRScope { + usageServer: PreloadedFileResult; + usageClient: PreloadedFileResult; + preloadFileDiff: PreloadedFileResult; + preloadMultiFileDiff: PreloadedFileResult; + preloadPatchDiff: PreloadedFileResult; + preloadFileResult: PreloadedFileResult; + preloadPatchFile: PreloadedFileResult; +} + +export interface WorkerPoolScope { + helperVite: PreloadedFileResult; + helperNextJS: PreloadedFileResult; + vscodeLocalRoots: PreloadedFileResult; + vscodeWorkerUri: PreloadedFileResult; + vscodeInlineScript: PreloadedFileResult; + vscodeCsp: PreloadedFileResult; + vscodeGlobal: PreloadedFileResult; + vscodeBlobUrl: PreloadedFileResult; + vscodeFactory: PreloadedFileResult; + helperWebpack: PreloadedFileResult; + helperESBuild: PreloadedFileResult; + helperStatic: PreloadedFileResult; + helperVanilla: PreloadedFileResult; + vanillaUsage: PreloadedFileResult; + reactUsage: PreloadedFileResult; + apiReference: PreloadedFileResult; + cachingExample: PreloadedFileResult; + architectureASCII: PreloadedFileResult; +} + +// ============================================================================= +// Scope Registry - Maps file paths to their expected scope types +// ============================================================================= + +export interface MDXScopeRegistry { + 'docs/Installation/content.mdx': InstallationScope; + 'docs/CoreTypes/content.mdx': CoreTypesScope; + 'docs/Overview/content.mdx': OverviewScope; + 'docs/ReactAPI/content.mdx': ReactAPIScope; + 'docs/VanillaAPI/content.mdx': VanillaAPIScope; + 'docs/Utilities/content.mdx': UtilitiesScope; + 'docs/Styling/content.mdx': StylingScope; + 'docs/SSR/content.mdx': SSRScope; + 'docs/WorkerPool/content.mdx': WorkerPoolScope; +} + +export type MDXFilePath = keyof MDXScopeRegistry; diff --git a/apps/docs/lib/mdx.tsx b/apps/docs/lib/mdx.tsx index 7876b29e..4be27f46 100644 --- a/apps/docs/lib/mdx.tsx +++ b/apps/docs/lib/mdx.tsx @@ -25,6 +25,7 @@ import { VanillaComponentTabs, VanillaPropTabs, } from '../app/docs/VanillaAPI/ComponentTabs'; +import type { MDXFilePath, MDXScopeRegistry } from './mdx-scopes'; import rehypeHierarchicalSlug from './rehype-hierarchical-slug'; import remarkTocIgnore from './remark-toc-ignore'; @@ -62,18 +63,24 @@ const defaultComponents = { VanillaPropTabs, }; -interface RenderMDXOptions { +interface RenderMDXOptions

{ /** Path to MDX file relative to app directory */ - filePath: string; + filePath: P; /** Data passed to MDX scope - available as variables in MDX */ - scope?: Record; + scope: MDXScopeRegistry[P]; } /** * Render an MDX file with components and scope data. * Works in React Server Components with Turbopack. + * + * The scope parameter is type-checked against the MDXScopeRegistry + * to ensure the correct variables are passed for each MDX file. */ -export async function renderMDX({ filePath, scope = {} }: RenderMDXOptions) { +export async function renderMDX

({ + filePath, + scope, +}: RenderMDXOptions

) { const fullPath = join(process.cwd(), 'app', filePath); const source = await readFile(fullPath, 'utf-8'); @@ -86,7 +93,9 @@ export async function renderMDX({ filePath, scope = {} }: RenderMDXOptions) { remarkPlugins: [remarkGfm, remarkTocIgnore], rehypePlugins: [[rehypeHierarchicalSlug, { levels: [2, 3, 4] }]], }, - scope, + // Cast to Record for compileMDX compatibility + // Type safety is enforced at the renderMDX call site via MDXScopeRegistry + scope: scope as unknown as Record, }, }); diff --git a/apps/docs/tsconfig.json b/apps/docs/tsconfig.json index 962758ea..df0a7283 100644 --- a/apps/docs/tsconfig.json +++ b/apps/docs/tsconfig.json @@ -4,6 +4,7 @@ "next-env.d.ts", "**/*.ts", "**/*.tsx", + "app/docs/**/*.mdx", ".next/types/**/*.ts", "types/**/*.d.ts" ], @@ -38,5 +39,8 @@ "paths": { "@/*": ["./*"] } + }, + "mdx": { + "checkMdx": true } } diff --git a/apps/docs/types/mdx-globals.d.ts b/apps/docs/types/mdx-globals.d.ts new file mode 100644 index 00000000..645d0076 --- /dev/null +++ b/apps/docs/types/mdx-globals.d.ts @@ -0,0 +1,100 @@ +/** + * Global type declarations for MDX scope variables. + * + * These variables are injected into MDX files via renderMDX's scope parameter. + * Declaring them globally allows the MDX language server to type-check their usage. + */ +import type { + PreloadMultiFileDiffResult, + PreloadedFileResult, +} from '@pierre/diffs/ssr'; + +import type { PackageManager } from '../app/docs/Installation/constants'; + +declare global { + // Installation scope + const installationExamples: Record< + PackageManager, + PreloadedFileResult + >; + + // CoreTypes scope + const fileContentsType: PreloadedFileResult; + const fileDiffMetadataType: PreloadedFileResult; + const parseDiffFromFileExample: PreloadedFileResult; + const parsePatchFilesExample: PreloadedFileResult; + + // Overview scope + const initialDiffProps: PreloadMultiFileDiffResult; + const reactSingleFile: PreloadedFileResult; + const reactPatchFile: PreloadedFileResult; + const vanillaSingleFile: PreloadedFileResult; + const vanillaPatchFile: PreloadedFileResult; + + // ReactAPI scope + const reactAPIMultiFileDiff: PreloadedFileResult; + const reactAPIPatch: PreloadedFileResult; + const reactAPIFileDiff: PreloadedFileResult; + const reactAPIFile: PreloadedFileResult; + const sharedDiffOptions: PreloadedFileResult; + const sharedDiffRenderProps: PreloadedFileResult; + const sharedFileOptions: PreloadedFileResult; + const sharedFileRenderProps: PreloadedFileResult; + + // VanillaAPI scope + const fileDiffExample: PreloadedFileResult; + const fileExample: PreloadedFileResult; + const fileDiffProps: PreloadedFileResult; + const fileProps: PreloadedFileResult; + const customHunk: PreloadedFileResult; + const diffHunksRenderer: PreloadedFileResult; + const diffHunksRendererPatch: PreloadedFileResult; + const fileRenderer: PreloadedFileResult; + + // Utilities scope + const diffAcceptReject: PreloadedFileResult; + const diffAcceptRejectReact: PreloadedFileResult; + const disposeHighlighter: PreloadedFileResult; + const getSharedHighlighter: PreloadedFileResult; + const parseDiffFromFile: PreloadedFileResult; + const parsePatchFiles: PreloadedFileResult; + const preloadHighlighter: PreloadedFileResult; + const registerCustomTheme: PreloadedFileResult; + const setLanguageOverride: PreloadedFileResult; + + // Styling scope + const stylingGlobal: PreloadedFileResult; + const stylingInline: PreloadedFileResult; + const stylingUnsafe: PreloadedFileResult; + + // SSR scope + const usageServer: PreloadedFileResult; + const usageClient: PreloadedFileResult; + const preloadFileDiff: PreloadedFileResult; + const preloadMultiFileDiff: PreloadedFileResult; + const preloadPatchDiff: PreloadedFileResult; + const preloadFileResult: PreloadedFileResult; + const preloadPatchFile: PreloadedFileResult; + + // WorkerPool scope + const helperVite: PreloadedFileResult; + const helperNextJS: PreloadedFileResult; + const vscodeLocalRoots: PreloadedFileResult; + const vscodeWorkerUri: PreloadedFileResult; + const vscodeInlineScript: PreloadedFileResult; + const vscodeCsp: PreloadedFileResult; + const vscodeGlobal: PreloadedFileResult; + const vscodeBlobUrl: PreloadedFileResult; + const vscodeFactory: PreloadedFileResult; + const helperWebpack: PreloadedFileResult; + const helperESBuild: PreloadedFileResult; + const helperStatic: PreloadedFileResult; + const helperVanilla: PreloadedFileResult; + const vanillaUsage: PreloadedFileResult; + const reactUsage: PreloadedFileResult; + const apiReference: PreloadedFileResult; + const cachingExample: PreloadedFileResult; + const architectureASCII: PreloadedFileResult; +} + +export {};