'use client' import { colors, effects } from '@/lib/theme' import { cn } from '@/lib/utils' interface TypeLinkProps { type: string className?: string availableTypeIds?: Set } /** * Parses a type string and converts type references into clickable links * that scroll to the corresponding type definition in the documentation. * * Supports: * - Simple types: Domain, User, etc. * - Generic types: Array, Promise * - Union types: string | number * - Complex types: Record */ export default function TypeLink({ type, className, availableTypeIds }: TypeLinkProps) { const parseTypeString = (typeStr: string): React.ReactNode[] => { const parts: React.ReactNode[] = [] let currentIndex = 0 const typeNamePattern = /\b([A-Z][a-zA-Z0-9]*)\b/g const builtInTypes = new Set([ 'string', 'number', 'boolean', 'void', 'null', 'undefined', 'any', 'unknown', 'never', 'object', 'symbol', 'bigint', 'Array', 'Promise', 'Record', 'Partial', 'Required', 'Readonly', 'Pick', 'Omit', 'Exclude', 'Extract', 'NonNullable', 'ReturnType', 'InstanceType', 'ThisType', 'Parameters', 'ConstructorParameters', 'Date', 'Error', 'RegExp', 'Map', 'Set', 'WeakMap', 'WeakSet', 'Function', 'ReadonlyArray', 'String', 'Number', 'Boolean', 'Symbol', 'Object' ]) let match: RegExpExecArray | null while ((match = typeNamePattern.exec(typeStr)) !== null) { const typeName = match[1] const matchStart = match.index const matchEnd = typeNamePattern.lastIndex if (matchStart > currentIndex) { parts.push( {typeStr.substring(currentIndex, matchStart)} ) } if (builtInTypes.has(typeName)) { parts.push( {typeName} ) } else { // Check if this type exists in the documentation const typeExists = availableTypeIds?.has(typeName) ?? false if (typeExists) { parts.push( ) } else { // Type doesn't exist in docs, render as plain text parts.push( {typeName} ) } } currentIndex = matchEnd } if (currentIndex < typeStr.length) { parts.push( {typeStr.substring(currentIndex)} ) } return parts } return ( {parseTypeString(type)} ) }