feat: add react-syntax-highlighter and update JSDoc cheatsheet layout

Integrate react-syntax-highlighter for improved code example rendering and enhance the JSDoc cheatsheet layout with a new navigation structure and quick reference section.
This commit is contained in:
Luke Hagar
2025-09-18 02:57:02 +00:00
parent 26a4db0da8
commit 82090541ed
22 changed files with 3421 additions and 889 deletions

15
lib/data-loader.ts Normal file
View File

@@ -0,0 +1,15 @@
import { jsdocData } from '@/data/jsdoc-data'
import { restoredJSDocData } from '@/data/restored-jsdoc-data'
// Lazy load data for better performance
export const loadSectionData = async (sectionId: string) => {
return jsdocData[sectionId] || jsdocData.basic
}
// Preload critical data - use restored data for now
export const preloadCriticalData = async () => {
return {
...jsdocData,
...restoredJSDocData
}
}

632
lib/jsdoc-data.ts Normal file
View File

@@ -0,0 +1,632 @@
export 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 <jane@example.com>
* @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<User>} 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<User>} 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 <email>",
example: "/**\n * @author John Doe <john@example.com>\n * @author Jane Smith <jane@example.com>\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<number, void, unknown>}\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",
},
],
},
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",
},
],
},
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 <jane@example.com>
*/
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<User>} 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",
},
],
},
}