import { Link } from "lucide-react"; import type { JSX, ReactNode } from "react"; import { Children, isValidElement } from "react"; import type { ApiMethodOptions, ApiMethodProperty } from "@/lib/api-method"; import { generateApiMethodExamples, parseApiMethod } from "@/lib/api-method"; import { cn } from "@/lib/utils"; import { ApiMethodTabs, ApiMethodTabsContent, ApiMethodTabsList, ApiMethodTabsTrigger, } from "./api-method-tabs"; import { Endpoint } from "./endpoint"; import { Button } from "./ui/button"; import { DynamicCodeBlock } from "./ui/dynamic-code-block"; const apiMethodTabs = [ { value: "client", label: "Client", icon: ( <> ), }, { value: "server", label: "Server", icon: ( <> ), }, ] as const; export function APIMethod({ children, ...options }: ApiMethodOptions & { children: ReactNode }) { const { path, method, isServerOnly, isClientOnly, isExternalOnly, note, clientOnlyNote, serverOnlyNote, } = options; const definition = parseApiMethod(getTextContent(children)); const examples = generateApiMethodExamples(definition, options); const properties = definition.properties; const serverTabContent = (
{isClientOnly || isServerOnly ? null : ( )} {serverOnlyNote || note ? ( {note && tsxifyBackticks(note)} {serverOnlyNote ? ( <> {note ?
: null} {tsxifyBackticks(serverOnlyNote)} ) : null}
) : null}
{isClientOnly ? (
This is a client-only endpoint
) : null}
{!isClientOnly ? : null}
); if (isExternalOnly) { return serverTabContent; } const pathId = path.replaceAll("/", "-"); return ( <>
{apiMethodTabs.map((tab) => ( {tab.icon} {tab.label} ))}
{isServerOnly ? null : ( )} {clientOnlyNote || note ? ( {note && tsxifyBackticks(note)} {clientOnlyNote ? ( <> {note ?
: null} {tsxifyBackticks(clientOnlyNote)} ) : null}
) : null}
{isServerOnly ? (
This is a server-only endpoint
) : null}
{!isServerOnly ? ( ) : null}
{serverTabContent}
); } function getTextContent(node: ReactNode): string { return Children.toArray(node) .map((child) => isValidElement<{ children?: ReactNode }>(child) ? getTextContent(child.props.children) : String(child), ) .join(""); } function TypeTable({ properties, isServer, }: { properties: ApiMethodProperty[]; isServer: boolean; }) { const visibleProperties = properties.filter( (property) => !(property.serverOnly && isServer === false) && !(property.clientOnly && isServer === true), ); if (!visibleProperties.length) return null; return (
Parameters
); } function PropertyItem({ property }: { property: ApiMethodProperty }) { return (
{property.name} {property.type} {property.nullable ? " | null" : ""} {!property.optional && ( required )} {property.serverOnly && ( server )}
); } function PropertyList({ properties, nested = false, }: { properties: ApiMethodProperty[]; nested?: boolean; }) { const groups: { property: ApiMethodProperty; children: ApiMethodProperty[]; }[] = []; let propertyIndex = 0; while (propertyIndex < properties.length) { const property = properties[propertyIndex]; if (property.type === "Object") { const parentSegments = [...property.path, property.name]; const children: ApiMethodProperty[] = []; propertyIndex++; while ( propertyIndex < properties.length && properties[propertyIndex].path.length >= parentSegments.length && parentSegments.every( (segment, index) => properties[propertyIndex].path[index] === segment, ) ) { children.push(properties[propertyIndex]); propertyIndex++; } groups.push({ property, children }); } else { groups.push({ property, children: [] }); propertyIndex++; } } return (
{groups.map((group) => (
0 && "pb-3", )} > {group.property.description && (

{tsxifyBackticks(group.property.description)}

)} {group.children.length > 0 && (
)}
))}
); } function tsxifyBackticks(input: string): JSX.Element { const parts = input.split(/(`[^`]+`)/g); return ( <> {parts.map((part, index) => { if (part.startsWith("`") && part.endsWith("`")) { const content = part.slice(1, -1); return {content}; } return {part}; })} ); } function Note({ children }: { children: ReactNode }) { return (
Notes

{children}

); }