"use client" import { useState, useEffect } from "react" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { ScrollArea } from "@/components/ui/scroll-area" import { Separator } from "@/components/ui/separator" import { BookOpen, Code, FileText, Hash, Info, Settings, Tag, Users, ChevronRight } from "lucide-react" const SyntaxHighlighter = ({ code, language = "javascript" }: { code: string; language?: string }) => { const highlightCode = (text: string) => { // Escape HTML first let highlighted = text.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """) // Apply syntax highlighting with proper HTML structure highlighted = highlighted // JSDoc comments and tags .replace(/(\/\*\*[\s\S]*?\*\/)/g, '$1') .replace(/(@\w+)/g, '$1') // JavaScript keywords .replace( /\b(function|class|const|let|var|if|else|for|while|return|async|await|new|this|super|extends|implements|static|public|private|protected)\b/g, '$1', ) // Strings .replace(/(["'`])((?:\\.|(?!\1)[^\\])*?)\1/g, '$1$2$1') // Numbers .replace(/\b(\d+\.?\d*)\b/g, '$1') // Booleans and null/undefined .replace(/\b(true|false|null|undefined)\b/g, '$1') // Types in curly braces .replace(/\{([^}]+)\}/g, '{$1}') return highlighted } return (
      
    
) } const sections = [ { id: "kitchen-sink", title: "Kitchen Sink Example", icon: BookOpen, subsections: ["Complete Example"], }, { id: "basic", title: "Basic Tags", icon: Tag, subsections: ["@description", "@author", "@version", "@since", "@deprecated"], }, { id: "parameters", title: "Parameters & Returns", icon: Code, subsections: ["@param", "@returns", "@throws", "@yields"], }, { id: "types", title: "Type Definitions", icon: Hash, subsections: ["@typedef", "@property", "@enum", "@type"], }, { id: "functions", title: "Functions & Classes", icon: Settings, subsections: ["@function", "@class", "@constructor", "@method", "@static", "@override"], }, { id: "modules", title: "Modules & Namespaces", icon: FileText, subsections: ["@module", "@namespace", "@memberof", "@exports", "@requires"], }, { id: "advanced", title: "Advanced Tags", icon: BookOpen, subsections: ["@callback", "@event", "@fires", "@listens", "@mixes", "@abstract"], }, { id: "objects", title: "Objects & Interfaces", icon: Hash, subsections: ["@interface", "@implements", "@extends", "@mixin"], }, { id: "documentation", title: "Documentation Tags", icon: Info, subsections: ["@example", "@see", "@link", "@tutorial", "@todo"], }, { id: "examples", title: "Complete Examples", icon: Info, subsections: ["Function Example", "Class Example", "Module Example"], }, { id: "best-practices", title: "Best Practices", icon: Users, subsections: ["Consistency", "Completeness", "Clarity", "Type Safety", "Examples"], }, ] const jsdocData = { kitchenSink: { title: "Kitchen Sink Example", description: "A comprehensive example showcasing multiple JSDoc features in one code block", items: [ { tag: "Complete Example", syntax: "Complete function documentation", example: `/** * Advanced user management service with comprehensive JSDoc documentation * @module UserService * @description Handles user creation, authentication, and profile management * @author Jane Smith * @version 2.1.0 * @since 1.0.0 * @requires Database * @requires EmailService * @exports UserService * @example * // Initialize the service * const userService = new UserService(database, emailService); * * // Create a new user * const user = await userService.createUser({ * name: 'John Doe', * email: 'john@example.com', * role: 'admin' * }); */ /** * @typedef {Object} UserData * @property {string} name - Full name of the user * @property {string} email - Email address (must be unique) * @property {('admin'|'user'|'guest')} [role='user'] - User role in the system * @property {number} [age] - User age (optional) * @property {UserPreferences} [preferences] - User preferences object */ /** * @typedef {Object} UserPreferences * @property {boolean} emailNotifications - Whether to send email notifications * @property {string} theme - UI theme preference * @property {string} language - Preferred language code */ /** * @callback ValidationCallback * @param {Error|null} error - Validation error if any * @param {boolean} isValid - Whether the data is valid */ /** * User management service class * @class UserService * @implements {EventEmitter} * @fires UserService#userCreated * @fires UserService#userDeleted * @example * const service = new UserService(db, emailService); * service.on('userCreated', (user) => { * console.log('New user created:', user.name); * }); */ class UserService extends EventEmitter { /** * Creates a new UserService instance * @constructor * @param {Database} database - Database connection instance * @param {EmailService} emailService - Email service for notifications * @throws {TypeError} When database or emailService is not provided * @since 1.0.0 */ constructor(database, emailService) { super(); if (!database || !emailService) { throw new TypeError('Database and EmailService are required'); } this.db = database; this.emailService = emailService; } /** * Creates a new user in the system * @async * @method createUser * @memberof UserService * @param {UserData} userData - User information object * @param {Object} [options={}] - Additional options * @param {boolean} [options.sendWelcomeEmail=true] - Send welcome email * @param {boolean} [options.validateEmail=true] - Validate email format * @returns {Promise} Promise resolving to created user object * @throws {ValidationError} When user data is invalid * @throws {DuplicateEmailError} When email already exists * @throws {DatabaseError} When database operation fails * @fires UserService#userCreated * @example * // Basic user creation * const user = await userService.createUser({ * name: 'Alice Johnson', * email: 'alice@example.com' * }); * * @example * // Advanced user creation with options * const adminUser = await userService.createUser({ * name: 'Bob Admin', * email: 'bob@example.com', * role: 'admin', * preferences: { * emailNotifications: false, * theme: 'dark', * language: 'en' * } * }, { * sendWelcomeEmail: false, * validateEmail: true * }); * @since 1.0.0 * @todo Add support for bulk user creation * @todo Implement user avatar upload */ async createUser(userData, options = {}) { // Implementation here... /** * User created event * @event UserService#userCreated * @type {Object} * @property {User} user - The created user object * @property {Date} timestamp - When the user was created */ this.emit('userCreated', { user: newUser, timestamp: new Date() }); return newUser; } /** * Validates user email address * @static * @method validateEmail * @param {string} email - Email address to validate * @param {ValidationCallback} callback - Callback function for validation result * @returns {boolean} True if email format is valid * @example * // Synchronous validation * const isValid = UserService.validateEmail('test@example.com'); * * // Asynchronous validation with callback * UserService.validateEmail('test@example.com', (error, isValid) => { * if (error) { * console.error('Validation error:', error); * } else { * console.log('Email is valid:', isValid); * } * }); * @since 1.2.0 */ static validateEmail(email, callback) { // Implementation here... } /** * @deprecated Since version 2.0.0. Use {@link UserService#createUser} instead. * @method addUser * @param {UserData} userData - User data * @returns {Promise} Created user * @see {@link UserService#createUser} */ async addUser(userData) { console.warn('addUser is deprecated. Use createUser instead.'); return this.createUser(userData); } } /** * @namespace UserService.Utils * @description Utility functions for user management */ UserService.Utils = { /** * Formats user display name * @function formatDisplayName * @memberof UserService.Utils * @param {string} firstName - User's first name * @param {string} lastName - User's last name * @returns {string} Formatted display name * @example * const displayName = UserService.Utils.formatDisplayName('John', 'Doe'); * console.log(displayName); // "John D." */ formatDisplayName(firstName, lastName) { return \`\${firstName} \${lastName.charAt(0)}.\`; } }; module.exports = UserService;`, description: "Complete function documentation with all common tags", }, ], }, basic: { title: "Basic Tags", description: "Essential JSDoc tags for documenting your code", items: [ { tag: "@description", syntax: "@description {string} Description text", example: "/**\n * @description Calculates the sum of two numbers\n * @param {number} a - First number\n * @param {number} b - Second number\n * @returns {number} The sum\n */\nfunction add(a, b) {\n return a + b;\n}", description: "Provides a description of the function, class, or variable", }, { tag: "@author", syntax: "@author {string} Author name ", example: "/**\n * @author John Doe \n * @author Jane Smith \n */", description: "Specifies the author(s) of the code", }, { tag: "@version", syntax: "@version {string} Version number", example: "/**\n * @version 1.2.0\n * @since 1.0.0\n */", description: "Indicates the current version of the code", }, { tag: "@since", syntax: "@since {string} Version when added", example: "/**\n * @since 1.0.0\n * @description Added in the initial release\n */", description: "Specifies when the feature was first added", }, { tag: "@deprecated", syntax: "@deprecated {string} Deprecation message", example: "/**\n * @deprecated Since version 2.0.0. Use newFunction() instead.\n * @see {@link newFunction}\n */\nfunction oldFunction() {\n // deprecated implementation\n}", description: "Marks code as deprecated with migration guidance", }, ], }, parameters: { title: "Parameters & Returns", description: "Document function parameters, return values, and exceptions", items: [ { tag: "@param", syntax: "@param {type} name Description", example: "/**\n * @param {number} x - The first number\n * @param {number} y - The second number\n * @param {Object} [options] - Optional configuration\n * @param {boolean} [options.strict=false] - Use strict mode\n */\nfunction calculate(x, y, options = {}) {\n // implementation\n}", description: "Documents function parameters with types and descriptions", }, { tag: "@returns", syntax: "@returns {type} Description", example: "/**\n * @param {number[]} numbers - Array of numbers\n * @returns {number} The sum of all numbers\n * @returns {null} Returns null if array is empty\n */\nfunction sum(numbers) {\n if (numbers.length === 0) return null;\n return numbers.reduce((a, b) => a + b, 0);\n}", description: "Documents the return value and its type", }, { tag: "@throws", syntax: "@throws {ErrorType} Description", example: "/**\n * @param {string} email - User email address\n * @throws {TypeError} When email is not a string\n * @throws {Error} When email format is invalid\n */\nfunction validateEmail(email) {\n if (typeof email !== 'string') {\n throw new TypeError('Email must be a string');\n }\n if (!email.includes('@')) {\n throw new Error('Invalid email format');\n }\n}", description: "Documents exceptions that may be thrown", }, { tag: "@yields", syntax: "@yields {type} Description", example: "/**\n * @generator\n * @yields {number} The next number in the Fibonacci sequence\n * @returns {Generator}\n */\nfunction* fibonacci() {\n let a = 0, b = 1;\n while (true) {\n yield a;\n [a, b] = [b, a + b];\n }\n}", description: "Documents what a generator function yields", }, ], }, types: { title: "Type Definitions", description: "Define and document custom types and interfaces", items: [ { tag: "@typedef", syntax: "@typedef {Object} TypeName", example: "/**\n * @typedef {Object} User\n * @property {string} name\n * @property {number} age\n */", description: "Defines a custom type", }, { tag: "@property", syntax: "@property {type} name Description", example: "/**\n * @property {string} email - User email address\n */", description: "Documents object properties", }, { tag: "@enum", syntax: "@enum {type}", example: '/**\n * @enum {string}\n */\nconst Status = {\n PENDING: "pending",\n COMPLETE: "complete"\n}', description: "Documents enumeration values", }, { tag: "@type", syntax: "@type {type}", example: "/**\n * @type {string|number}\n */\nlet value;", description: "Specifies the type of a variable", }, ], }, functions: { title: "Functions & Classes", description: "Document functions, classes, constructors, and methods", items: [ { tag: "@function", syntax: "@function", example: "/**\n * @function calculateTotal\n * @description Calculates order total\n */", description: "Explicitly marks something as a function", }, { tag: "@class", syntax: "@class", example: "/**\n * @class\n * @description Represents a user account\n */", description: "Documents a class", }, { tag: "@constructor", syntax: "@constructor", example: "/**\n * @constructor\n * @param {string} name - User name\n */", description: "Documents a constructor function", }, { tag: "@method", syntax: "@method", example: "/**\n * @method getName\n * @returns {string} The user name\n */", description: "Documents a method", }, { tag: "@static", syntax: "@static", example: "/**\n * @static\n * @method createUser\n */", description: "Indicates a static method or property", }, { tag: "@override", syntax: "@override", example: "/**\n * @override\n * @method toString\n */", description: "Indicates method overrides parent method", }, ], }, modules: { title: "Modules & Namespaces", description: "Organize code with modules, namespaces, and membership", items: [ { tag: "@module", syntax: "@module ModuleName", example: "/**\n * @module UserUtils\n * @description Utilities for user management\n */", description: "Documents a module", }, { tag: "@namespace", syntax: "@namespace NamespaceName", example: "/**\n * @namespace MyApp.Utils\n */", description: "Documents a namespace", }, { tag: "@memberof", syntax: "@memberof ParentName", example: "/**\n * @memberof MyApp.Utils\n * @function formatName\n */", description: "Indicates membership in a parent", }, { tag: "@exports", syntax: "@exports ModuleName", example: "/**\n * @exports UserService\n */", description: "Documents what a module exports", }, { tag: "@requires", syntax: "@requires ModuleName", example: "/**\n * @requires lodash\n */", description: "Documents module dependencies", }, ], }, advanced: { title: "Advanced Tags", description: "Advanced JSDoc features for complex documentation needs", items: [ { tag: "@callback", syntax: "@callback CallbackName", example: "/**\n * @callback RequestCallback\n * @param {Error} error\n * @param {Object} response\n */", description: "Documents a callback function type", }, { tag: "@event", syntax: "@event EventName", example: "/**\n * @event MyClass#dataLoaded\n * @type {Object}\n */", description: "Documents an event", }, { tag: "@fires", syntax: "@fires EventName", example: "/**\n * @fires MyClass#dataLoaded\n */", description: "Indicates function fires an event", }, { tag: "@listens", syntax: "@listens EventName", example: "/**\n * @listens MyClass#dataLoaded\n */", description: "Indicates function listens to an event", }, { tag: "@mixes", syntax: "@mixes MixinName", example: "/**\n * @mixes EventEmitter\n */", description: "Documents that class mixes in another", }, { tag: "@abstract", syntax: "@abstract", example: "/**\n * @abstract\n * @method process\n */", description: "Indicates abstract method or class", }, ], }, examples: { title: "Complete Examples", description: "Real-world JSDoc documentation examples", items: [ { tag: "Function Example", syntax: "Complete function documentation", example: `/** * Calculates the area of a rectangle * @function calculateArea * @param {number} width - The width of the rectangle * @param {number} height - The height of the rectangle * @returns {number} The area of the rectangle * @throws {TypeError} When width or height is not a number * @example * // Calculate area of 5x3 rectangle * const area = calculateArea(5, 3); * console.log(area); // 15 * @since 1.0.0 * @author Jane Smith */ function calculateArea(width, height) { if (typeof width !== 'number' || typeof height !== 'number') { throw new TypeError('Width and height must be numbers'); } return width * height; }`, description: "Complete function documentation with all common tags", }, { tag: "Class Example", syntax: "Complete class documentation", example: `/** * Represents a user in the system * @class User * @param {string} name - The user's name * @param {string} email - The user's email address * @example * const user = new User('John Doe', 'john@example.com'); * console.log(user.getName()); // 'John Doe' */ class User { /** * Create a user * @constructor * @param {string} name - The user's name * @param {string} email - The user's email address */ constructor(name, email) { this.name = name; this.email = email; } /** * Get the user's name * @method getName * @returns {string} The user's name */ getName() { return this.name; } }`, description: "Complete class documentation with constructor and methods", }, { tag: "Module Example", syntax: "Complete module documentation", example: `/** * User management module * @module UserManagement * @description Handles user creation and deletion * @requires Database * @requires EmailService * @exports createUser * @exports deleteUser * @example * // Create a user * const user = createUser('John Doe', 'john@example.com'); * console.log(user); * * // Delete a user * deleteUser(user.id); */ const Database = require('./Database'); const EmailService = require('./EmailService'); function createUser(name, email) { // Implementation here } function deleteUser(userId) { // Implementation here } module.exports = { createUser, deleteUser };`, description: "Complete module documentation with dependencies and exports", }, ], }, "best-practices": { title: "Best Practices", description: "Guidelines for writing effective JSDoc documentation", items: [ { tag: "Consistency", syntax: "Use consistent formatting and style", example: "// Always use the same format for similar tags\n// Good: @param {string} name - User name\n// Good: @param {number} age - User age", description: "Maintain consistent formatting across your documentation", }, { tag: "Completeness", syntax: "Document all public APIs", example: "// Document all parameters, return values, and exceptions\n// Include examples for complex functions", description: "Ensure all public functions, classes, and modules are documented", }, { tag: "Clarity", syntax: "Write clear, concise descriptions", example: "// Good: Calculates user age from birth date\n// Bad: Does age stuff", description: "Use clear, descriptive language that explains purpose and behavior", }, { tag: "Type Safety", syntax: "Always specify types for parameters and returns", example: "// Always include types\n@param {string|null} name - User name or null\n@returns {Promise} Promise resolving to user object", description: "Include detailed type information to improve code reliability", }, { tag: "Examples", syntax: "Include usage examples for complex functions", example: "/**\n * @example\n * // Basic usage\n * const result = myFunction('input');\n * \n * @example\n * // Advanced usage\n * const result = myFunction('input', { option: true });\n */", description: "Provide practical examples showing how to use the code", }, ], }, objects: { title: "Objects & Interfaces", description: "Document object structures, interfaces, and inheritance", items: [ { tag: "@interface", syntax: "@interface InterfaceName", example: "/**\n * @interface Drawable\n * @description Interface for drawable objects\n */", description: "Documents an interface that classes can implement", }, { tag: "@implements", syntax: "@implements {InterfaceName}", example: "/**\n * @class Circle\n * @implements {Drawable}\n */", description: "Indicates that a class implements an interface", }, { tag: "@extends", syntax: "@extends ParentClass", example: "/**\n * @class ColoredCircle\n * @extends Circle\n */", description: "Documents class inheritance", }, { tag: "@mixin", syntax: "@mixin MixinName", example: "/**\n * @mixin EventEmitter\n * @description Adds event handling capabilities\n */", description: "Documents a mixin that can be mixed into classes", }, ], }, documentation: { title: "Documentation Tags", description: "Tags for linking, examples, and additional documentation", items: [ { tag: "@example", syntax: "@example\n// Example code here", example: "/**\n * @example\n * // Basic usage\n * const result = myFunction('test');\n * console.log(result);\n */", description: "Provides usage examples", }, { tag: "@see", syntax: "@see {reference}", example: "/**\n * @see {@link MyClass#method}\n * @see https://example.com/docs\n */", description: "References related documentation or code", }, { tag: "@link", syntax: "{@link reference}", example: "/**\n * Uses {@link MyClass} for processing\n */", description: "Creates inline links to other documentation", }, { tag: "@tutorial", syntax: "@tutorial TutorialName", example: "/**\n * @tutorial getting-started\n */", description: "Links to a tutorial document", }, { tag: "@todo", syntax: "@todo Description of what needs to be done", example: "/**\n * @todo Add input validation\n * @todo Optimize performance\n */", description: "Documents future improvements or fixes needed", }, ], }, } export default function JSDocCheatsheet() { const [activeSection, setActiveSection] = useState("kitchen-sink") const [expandedSections, setExpandedSections] = useState(["kitchen-sink"]) const [isScrolling, setIsScrolling] = useState(false) const toggleSection = (sectionId: string) => { setExpandedSections((prev) => prev.includes(sectionId) ? prev.filter((id) => id !== sectionId) : [...prev, sectionId], ) } const scrollToTag = (tag: string) => { const element = document.getElementById(tag.replace("@", "").replace(/[^a-zA-Z0-9]/g, "-")) if (element) { setIsScrolling(true) element.scrollIntoView({ behavior: "smooth", block: "start" }) // Reset scrolling state after animation setTimeout(() => setIsScrolling(false), 1000) // Highlight the element briefly element.classList.add("ring-2", "ring-primary", "ring-opacity-50") setTimeout(() => { element.classList.remove("ring-2", "ring-primary", "ring-opacity-50") }, 2000) } } useEffect(() => { const handleScroll = () => { if (isScrolling) return // Don't update during programmatic scrolling const sections = Object.keys(jsdocData) const scrollPosition = window.scrollY + 200 for (const sectionId of sections) { const element = document.getElementById(`section-${sectionId}`) if (element) { const { offsetTop, offsetHeight } = element if (scrollPosition >= offsetTop && scrollPosition < offsetTop + offsetHeight) { setActiveSection(sectionId) break } } } } window.addEventListener("scroll", handleScroll) return () => window.removeEventListener("scroll", handleScroll) }, [isScrolling]) return (
{/* Header */}

JSDoc Cheatsheet

Complete Reference for JavaScript Documentation

{/* Sidebar Navigation */} {/* Main Content */}
{/* Kitchen Sink Example */} Kitchen Sink Example A comprehensive example showcasing multiple JSDoc features in one code block {/* Section Header */}

{jsdocData[activeSection as keyof typeof jsdocData]?.title || "Section"}

{jsdocData[activeSection as keyof typeof jsdocData]?.description || "Documentation section"}

{/* Content Cards */}
{jsdocData[activeSection as keyof typeof jsdocData]?.items.map((item, index) => (
{item.tag}
{item.description}
{/* Syntax */}

Syntax:

{item.syntax}
{/* Example with Syntax Highlighting */}

Example:

)) || []}
{/* Footer */}
) }