From d7ba6d2ba63eadef53dbc93cf9e640f4b055bb68 Mon Sep 17 00:00:00 2001 From: v0 Date: Wed, 17 Sep 2025 14:17:21 +0000 Subject: [PATCH] fix: resolve syntax highlighting error in Next.js Create custom syntax highlighter for reliable code examples. Co-authored-by: Luke Hagar <5702154+LukeHagar@users.noreply.github.com> --- app/page.tsx | 319 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 276 insertions(+), 43 deletions(-) diff --git a/app/page.tsx b/app/page.tsx index 5fc4d73..6ac031f 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -9,43 +9,51 @@ 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 [highlightedCode, setHighlightedCode] = useState(code) + const highlightCode = (text: string) => { + // Escape HTML first + let highlighted = text.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """) - useEffect(() => { - // Simple syntax highlighting for JavaScript/JSDoc - const highlight = (text: string) => { - return ( - text - // JSDoc tags - .replace(/(@\w+)/g, '$1') - // Comments - .replace(/(\/\*\*[\s\S]*?\*\/)/g, '$1') - .replace(/(\/\/.*$)/gm, '$1') - // Strings - .replace(/(['"`])((?:(?!\1)[^\\]|\\.)*)(\1)/g, '$1$2$3') - // Keywords - .replace( - /\b(function|class|const|let|var|if|else|for|while|return|new|this|typeof|instanceof)\b/g, - '$1', - ) - // Types in curly braces - .replace(/\{([^}]+)\}/g, '{$1}') - // Numbers - .replace(/\b(\d+\.?\d*)\b/g, '$1') + // 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', ) - } - setHighlightedCode(highlight(code)) - }, [code]) + // 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", @@ -109,6 +117,206 @@ const sections = [ ] 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", @@ -116,32 +324,34 @@ const jsdocData = { { tag: "@description", syntax: "@description {string} Description text", - example: "/**\n * @description Calculates the sum of two numbers\n */", + 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 */", - description: "Specifies the author of the code", + 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 */", - description: "Indicates the version of the code", + 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: "Specifies when the feature was 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 Use newFunction() instead\n */", - description: "Marks code as deprecated", + 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", }, ], }, @@ -152,25 +362,29 @@ const jsdocData = { { tag: "@param", syntax: "@param {type} name Description", - example: "/**\n * @param {number} x - The first number\n * @param {number} y - The second number\n */", - description: "Documents function parameters", + 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 * @returns {number} The sum of x and y\n */", - description: "Documents the return value", + 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 * @throws {TypeError} When input is not a number\n */", + 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 * @yields {number} The next number in sequence\n */", + 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", }, ], @@ -397,6 +611,7 @@ class User { * @module UserManagement * @description Handles user creation and deletion * @requires Database + * @requires EmailService * @exports createUser * @exports deleteUser * @example @@ -408,6 +623,7 @@ class User { * deleteUser(user.id); */ const Database = require('./Database'); +const EmailService = require('./EmailService'); function createUser(name, email) { // Implementation here @@ -534,8 +750,8 @@ module.exports = { } export default function JSDocCheatsheet() { - const [activeSection, setActiveSection] = useState("basic") - const [expandedSections, setExpandedSections] = useState(["basic"]) + const [activeSection, setActiveSection] = useState("kitchen-sink") + const [expandedSections, setExpandedSections] = useState(["kitchen-sink"]) const [isScrolling, setIsScrolling] = useState(false) const toggleSection = (sectionId: string) => { @@ -670,6 +886,23 @@ export default function JSDocCheatsheet() { {/* Main Content */}
+ {/* Kitchen Sink Example */} + + + + + Kitchen Sink Example + + + + A comprehensive example showcasing multiple JSDoc features in one code block + + + + + + + {/* Section Header */}