import { sample, random, shuffle } from 'lodash-es'; import logger from '../utils/logger.js'; class CodeGenerator { constructor(config) { this.config = config; this.bugProbability = config.activity.bugProbability; this.typoProbability = config.activity.typoProbability; } generateProjectStructure() { const structures = [ { name: 'utils', files: [ { path: 'src/utils/helpers.js', type: 'utility' }, { path: 'src/utils/validators.js', type: 'validator' }, { path: 'src/utils/formatters.js', type: 'formatter' }, ], }, { name: 'services', files: [ { path: 'src/services/api.js', type: 'api' }, { path: 'src/services/cache.js', type: 'cache' }, { path: 'src/services/logger.js', type: 'logger' }, ], }, { name: 'models', files: [ { path: 'src/models/user.js', type: 'model' }, { path: 'src/models/product.js', type: 'model' }, { path: 'src/models/order.js', type: 'model' }, ], }, { name: 'middleware', files: [ { path: 'src/middleware/auth.js', type: 'auth' }, { path: 'src/middleware/errorHandler.js', type: 'error' }, { path: 'src/middleware/rateLimiter.js', type: 'rateLimiter' }, ], }, ]; return sample(structures); } generateFileContent(fileType, context = {}) { const generators = { utility: () => this._generateUtility(context), validator: () => this._generateValidator(context), formatter: () => this._generateFormatter(context), api: () => this._generateApiService(context), cache: () => this._generateCache(context), logger: () => this._generateLogger(context), model: () => this._generateModel(context), auth: () => this._generateAuthMiddleware(context), error: () => this._generateErrorHandler(context), rateLimiter: () => this._generateRateLimiter(context), }; const generator = generators[fileType] || generators.utility; let content = generator(); if (Math.random() < this.bugProbability) { content = this._injectBug(content); } if (Math.random() < this.typoProbability) { content = this._injectTypo(content); } return content; } _generateUtility(context) { const utilities = [ this._debounceFunction(), this._throttleFunction(), this._deepCloneFunction(), this._flattenObject(), this._retryFunction(), this._eventEmitter(), this._memoizeFunction(), this._pipeFunction(), ]; return sample(utilities); } _debounceFunction() { return `/** * Creates a debounced function that delays invoking func until * after wait milliseconds have elapsed since the last invocation. * @param {Function} func - The function to debounce * @param {number} wait - Milliseconds to wait * @returns {Function} Debounced function */ export function debounce(func, wait = 300) { let timeoutId = null; return function (...args) { const later = () => { timeoutId = null; func.apply(this, args); }; clearTimeout(timeoutId); timeoutId = setTimeout(later, wait); }; } /** * Creates a throttled function that only invokes func at most * once per every wait milliseconds. * @param {Function} func - The function to throttle * @param {number} wait - Milliseconds to wait * @returns {Function} Throttled function */ export function throttle(func, wait = 300) { let lastCall = 0; let timeoutId = null; return function (...args) { const now = Date.now(); const remaining = wait - (now - lastCall); if (remaining <= 0) { if (timeoutId) { clearTimeout(timeoutId); timeoutId = null; } lastCall = now; func.apply(this, args); } else if (!timeoutId) { timeoutId = setTimeout(() => { lastCall = Date.now(); timeoutId = null; func.apply(this, args); }, remaining); } }; } `; } _throttleFunction() { return `/** * Deep clones an object, handling circular references. * @param {*} obj - The object to clone * @param {WeakMap} seen - Map to track circular references * @returns {*} Deep cloned object */ export function deepClone(obj, seen = new WeakMap()) { if (obj === null || typeof obj !== 'object') { return obj; } if (seen.has(obj)) { return seen.get(obj); } if (obj instanceof Date) { return new Date(obj.getTime()); } if (obj instanceof RegExp) { return new RegExp(obj.source, obj.flags); } if (Array.isArray(obj)) { const cloned = obj.map(item => deepClone(item, seen)); seen.set(obj, cloned); return cloned; } const cloned = Object.create(Object.getPrototypeOf(obj)); seen.set(obj, cloned); for (const [key, value] of Object.entries(obj)) { cloned[key] = deepClone(value, seen); } return cloned; } /** * Checks if two values are deeply equal. * @param {*} a - First value * @param {*} b - Second value * @returns {boolean} True if deeply equal */ export function deepEqual(a, b) { if (a === b) return true; if (a == null || b == null) return false; if (typeof a !== typeof b) return false; if (Array.isArray(a)) { if (!Array.isArray(b) || a.length !== b.length) return false; return a.every((item, i) => deepEqual(item, b[i])); } if (typeof a === 'object') { const keysA = Object.keys(a); const keysB = Object.keys(b); if (keysA.length !== keysB.length) return false; return keysA.every(key => deepEqual(a[key], b[key])); } return false; } `; } _deepCloneFunction() { return `/** * Flattens a nested object into a single level with dot notation keys. * @param {Object} obj - The object to flatten * @param {string} prefix - Key prefix for recursion * @returns {Object} Flattened object */ export function flattenObject(obj, prefix = '') { return Object.keys(obj).reduce((acc, key) => { const fullKey = prefix ? \`\${prefix}.\${key}\` : key; const value = obj[key]; if (typeof value === 'object' && value !== null && !Array.isArray(value)) { Object.assign(acc, flattenObject(value, fullKey)); } else { acc[fullKey] = value; } return acc; }, {}); } /** * Unflattens a dot-notation object back to nested structure. * @param {Object} obj - The flattened object * @returns {Object} Nested object */ export function unflattenObject(obj) { const result = {}; for (const [key, value] of Object.entries(obj)) { const parts = key.split('.'); let current = result; for (let i = 0; i < parts.length - 1; i++) { const part = parts[i]; current[part] = current[part] || {}; current = current[part]; } current[parts[parts.length - 1]] = value; } return result; } `; } _flattenObject() { return `/** * Retries an async function with exponential backoff. * @param {Function} fn - Async function to retry * @param {Object} options - Retry options * @param {number} options.maxRetries - Maximum retry attempts * @param {number} options.baseDelay - Base delay in ms * @param {number} options.maxDelay - Maximum delay in ms * @returns {Promise<*>} Result of the function */ export async function retry(fn, { maxRetries = 3, baseDelay = 1000, maxDelay = 10000 } = {}) { let lastError; for (let attempt = 0; attempt <= maxRetries; attempt++) { try { return await fn(); } catch (error) { lastError = error; if (attempt === maxRetries) { break; } const delay = Math.min(baseDelay * Math.pow(2, attempt), maxDelay); const jitter = delay * 0.1 * Math.random(); await new Promise(resolve => setTimeout(resolve, delay + jitter)); } } throw lastError; } /** * Creates a timeout wrapper for a promise. * @param {Promise} promise - The promise to wrap * @param {number} ms - Timeout in milliseconds * @param {Error} error - Error to throw on timeout * @returns {Promise} Wrapped promise */ export function withTimeout(promise, ms, error = new Error('Operation timed out')) { let timeoutId; const timeout = new Promise((_, reject) => { timeoutId = setTimeout(() => reject(error), ms); }); return Promise.race([promise, timeout]).finally(() => { clearTimeout(timeoutId); }); } `; } _retryFunction() { return `/** * Simple event emitter implementation. */ export class EventEmitter { constructor() { this._listeners = new Map(); } /** * Register a listener for an event. * @param {string} event - Event name * @param {Function} listener - Callback function * @returns {Function} Unsubscribe function */ on(event, listener) { if (!this._listeners.has(event)) { this._listeners.set(event, []); } this._listeners.get(event).push(listener); return () => this.off(event, listener); } /** * Register a one-time listener. * @param {string} event - Event name * @param {Function} listener - Callback function */ once(event, listener) { const wrapper = (...args) => { listener.apply(this, args); this.off(event, wrapper); }; this.on(event, wrapper); } /** * Remove a listener. * @param {string} event - Event name * @param {Function} listener - Callback function */ off(event, listener) { if (!this._listeners.has(event)) return; const listeners = this._listeners.get(event); const index = listeners.indexOf(listener); if (index !== -1) { listeners.splice(index, 1); } } /** * Emit an event. * @param {string} event - Event name * @param {...*} args - Arguments to pass to listeners */ emit(event, ...args) { if (!this._listeners.has(event)) return; const listeners = [...this._listeners.get(event)]; for (const listener of listeners) { try { listener.apply(this, args); } catch (error) { console.error(\`Error in event listener for "\${event}":\`, error); } } } } `; } _eventEmitter() { return `/** * Creates a memoized version of a function that caches results. * @param {Function} fn - Function to memoize * @param {Function} [resolver] - Custom cache key resolver * @returns {Function} Memoized function */ export function memoize(fn, resolver = null) { const cache = new Map(); const memoized = function (...args) { const key = resolver ? resolver.apply(this, args) : args[0]; if (cache.has(key)) { return cache.get(key); } const result = fn.apply(this, args); cache.set(key, result); return result; }; memoized.cache = cache; memoized.clear = () => { cache.clear(); }; return memoized; } /** * Creates a function that returns the result of the first * predicate that returns a truthy value. * @param {...Function} predicates - Functions to try * @returns {Function} Combined function */ export function firstOf(...predicates) { return function (...args) { for (const predicate of predicates) { const result = predicate.apply(this, args); if (result != null) { return result; } } return undefined; }; } `; } _memoizeFunction() { return `/** * Creates a function pipeline where the output of each function * is passed as input to the next. * @param {...Function} functions - Functions to compose * @returns {Function} Pipeline function */ export function pipe(...functions) { return function (initialValue) { return functions.reduce((value, fn) => fn(value), initialValue); }; } /** * Creates a function that composes functions right-to-left. * @param {...Function} functions - Functions to compose * @returns {Function} Composed function */ export function compose(...functions) { return function (initialValue) { return functions.reduceRight((value, fn) => fn(value), initialValue); }; } /** * Creates a curried version of a function. * @param {Function} fn - Function to curry * @param {number} [arity] - Number of arguments expected * @returns {Function} Curried function */ export function curry(fn, arity = fn.length) { return function curried(...args) { if (args.length >= arity) { return fn.apply(this, args); } return (...moreArgs) => curried.apply(this, [...args, ...moreArgs]); }; } `; } _pipeFunction() { return `/** * Validation utilities for common data types. */ const EMAIL_REGEX = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/; const PHONE_REGEX = /^\\+?[1-9]\\d{1,14}$/; const URL_REGEX = /^https?:\\/\\/[^\\s$.?#].[^\\s]*$/; /** * Validates an email address. * @param {string} email - Email to validate * @returns {boolean} True if valid */ export function isValidEmail(email) { if (typeof email !== 'string') return false; return EMAIL_REGEX.test(email.trim()); } /** * Validates a phone number (E.164 format). * @param {string} phone - Phone number to validate * @returns {boolean} True if valid */ export function isValidPhone(phone) { if (typeof phone !== 'string') return false; return PHONE_REGEX.test(phone.replace(/[\\s-()]/g, '')); } /** * Validates a URL. * @param {string} url - URL to validate * @returns {boolean} True if valid */ export function isValidUrl(url) { if (typeof url !== 'string') return false; try { new URL(url); return true; } catch { return false; } } /** * Validates that a string is not empty or whitespace. * @param {string} str - String to validate * @returns {boolean} True if not empty */ export function isNonEmptyString(str) { return typeof str === 'string' && str.trim().length > 0; } /** * Validates that a value is a positive integer. * @param {*} value - Value to validate * @returns {boolean} True if positive integer */ export function isPositiveInt(value) { return Number.isInteger(value) && value > 0; } /** * Creates a validator chain for an object. * @param {Object} schema - Validation schema * @returns {Object} Validation result */ export function validateObject(schema, data) { const errors = []; for (const [field, rules] of Object.entries(schema)) { const value = data[field]; if (rules.required && (value === undefined || value === null)) { errors.push(\`\${field} is required\`); continue; } if (value !== undefined && rules.type && typeof value !== rules.type) { errors.push(\`\${field} must be of type \${rules.type}\`); } if (value !== undefined && rules.validate && !rules.validate(value)) { errors.push(\`\${field} failed custom validation\`); } } return { isValid: errors.length === 0, errors, }; } `; } _generateValidator() { return `/** * Formatting utilities for common data transformations. */ /** * Formats a number as currency. * @param {number} amount - The amount to format * @param {string} currency - Currency code (default: USD) * @param {string} locale - Locale string (default: en-US) * @returns {string} Formatted currency string */ export function formatCurrency(amount, currency = 'USD', locale = 'en-US') { if (typeof amount !== 'number' || isNaN(amount)) { throw new TypeError('Amount must be a valid number'); } return new Intl.NumberFormat(locale, { style: 'currency', currency, minimumFractionDigits: 2, maximumFractionDigits: 2, }).format(amount); } /** * Formats a date to a readable string. * @param {Date|string|number} date - Date to format * @param {Object} options - Formatting options * @returns {string} Formatted date string */ export function formatDate(date, options = {}) { const dateObj = date instanceof Date ? date : new Date(date); if (isNaN(dateObj.getTime())) { throw new TypeError('Invalid date'); } const defaultOptions = { year: 'numeric', month: 'short', day: 'numeric', ...options, }; return dateObj.toLocaleDateString('en-US', defaultOptions); } /** * Truncates a string to a maximum length. * @param {string} str - String to truncate * @param {number} maxLength - Maximum length * @param {string} suffix - Suffix to add (default: '...') * @returns {string} Truncated string */ export function truncate(str, maxLength, suffix = '...') { if (typeof str !== 'string') return ''; if (str.length <= maxLength) return str; return str.slice(0, maxLength - suffix.length) + suffix; } /** * Capitalizes the first letter of a string. * @param {string} str - String to capitalize * @returns {string} Capitalized string */ export function capitalize(str) { if (typeof str !== 'string' || str.length === 0) return ''; return str.charAt(0).toUpperCase() + str.slice(1); } /** * Converts a string to slug format. * @param {string} str - String to slugify * @returns {string} Slugified string */ export function slugify(str) { return str .toLowerCase() .trim() .replace(/[^\\w\\s-]/g, '') .replace(/[\\s_-]+/g, '-') .replace(/^-+|-+$/g, ''); } /** * Pads a number with leading zeros. * @param {number} num - Number to pad * @param {number} length - Target length * @returns {string} Padded number string */ export function padNumber(num, length = 2) { return String(num).padStart(length, '0'); } `; } _generateFormatter() { return `/** * API service with request queuing and response caching. */ class ApiService { constructor(baseURL, options = {}) { this.baseURL = baseURL.replace(/\\/$/, ''); this.timeout = options.timeout || 10000; this.retries = options.retries || 3; this._cache = new Map(); this._queue = []; this._processing = false; } /** * Makes a GET request with caching. * @param {string} path - Request path * @param {Object} params - Query parameters * @returns {Promise} Response data */ async get(path, params = {}) { const cacheKey = this._buildCacheKey(path, params); if (this._cache.has(cacheKey)) { const cached = this._cache.get(cacheKey); if (Date.now() - cached.timestamp < 60000) { return cached.data; } } const data = await this._request('GET', path, { params }); this._cache.set(cacheKey, { data, timestamp: Date.now() }); return data; } /** * Makes a POST request. * @param {string} path - Request path * @param {Object} body - Request body * @returns {Promise} Response data */ async post(path, body = {}) { this._cache.clear(); return this._request('POST', path, { body }); } /** * Makes a PUT request. * @param {string} path - Request path * @param {Object} body - Request body * @returns {Promise} Response data */ async put(path, body = {}) { this._cache.clear(); return this._request('PUT', path, { body }); } /** * Makes a DELETE request. * @param {string} path - Request path * @returns {Promise} Response data */ async delete(path) { this._cache.clear(); return this._request('DELETE', path); } /** * Queues a request for batch processing. * @param {string} method - HTTP method * @param {string} path - Request path * @param {Object} options - Request options */ queue(method, path, options = {}) { return new Promise((resolve, reject) => { this._queue.push({ method, path, options, resolve, reject }); if (!this._processing) { this._processQueue(); } }); } async _processQueue() { this._processing = true; while (this._queue.length > 0) { const batch = this._queue.splice(0, 5); await Promise.allSettled( batch.map(({ method, path, options, resolve, reject }) => this._request(method, path, options) .then(resolve) .catch(reject) ) ); } this._processing = false; } async _request(method, path, options = {}) { const url = new URL(path, this.baseURL); if (options.params) { Object.entries(options.params).forEach(([key, value]) => { if (value !== undefined) url.searchParams.append(key, value); }); } const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), this.timeout); try { const response = await fetch(url.toString(), { method, headers: { 'Content-Type': 'application/json' }, body: options.body ? JSON.stringify(options.body) : undefined, signal: controller.signal, }); if (!response.ok) { throw new Error(\`HTTP \${response.status}: \${response.statusText}\`); } return response.json(); } finally { clearTimeout(timeoutId); } } _buildCacheKey(path, params) { return \`\${path}?\${JSON.stringify(params)}\`; } clearCache() { this._cache.clear(); } } export default ApiService; `; } _generateApiService() { return `/** * In-memory cache with TTL and size limits. */ class Cache { constructor(options = {}) { this._store = new Map(); this._maxSize = options.maxSize || 1000; this._defaultTTL = options.defaultTTL || 300000; // 5 minutes } /** * Gets a value from cache. * @param {string} key - Cache key * @returns {*|null} Cached value or null */ get(key) { const entry = this._store.get(key); if (!entry) return null; if (entry.expiry < Date.now()) { this._store.delete(key); return null; } entry.lastAccessed = Date.now(); return entry.value; } /** * Sets a value in cache. * @param {string} key - Cache key * @param {*} value - Value to cache * @param {number} [ttl] - Time to live in ms */ set(key, value, ttl = this._defaultTTL) { if (this._store.size >= this._maxSize) { this._evictOldest(); } this._store.set(key, { value, expiry: Date.now() + ttl, createdAt: Date.now(), lastAccessed: Date.now(), }); } /** * Deletes a value from cache. * @param {string} key - Cache key * @returns {boolean} True if key existed */ delete(key) { return this._store.delete(key); } /** * Checks if a key exists and is not expired. * @param {string} key - Cache key * @returns {boolean} True if key exists */ has(key) { return this.get(key) !== null; } /** * Gets or computes a value. * @param {string} key - Cache key * @param {Function} computeFn - Function to compute value * @param {number} [ttl] - Time to live in ms * @returns {*} Cached or computed value */ async getOrCompute(key, computeFn, ttl = this._defaultTTL) { const cached = this.get(key); if (cached !== null) return cached; const value = await computeFn(); this.set(key, value, ttl); return value; } /** * Clears all expired entries. * @returns {number} Number of entries removed */ prune() { const now = Date.now(); let removed = 0; for (const [key, entry] of this._store.entries()) { if (entry.expiry < now) { this._store.delete(key); removed++; } } return removed; } /** * Clears the entire cache. */ clear() { this._store.clear(); } /** * Gets cache statistics. * @returns {Object} Cache stats */ getStats() { const now = Date.now(); let expired = 0; let active = 0; for (const entry of this._store.values()) { if (entry.expiry < now) { expired++; } else { active++; } } return { total: this._store.size, active, expired, maxSize: this._maxSize, }; } _evictOldest() { let oldestKey = null; let oldestTime = Infinity; for (const [key, entry] of this._store.entries()) { if (entry.lastAccessed < oldestTime) { oldestTime = entry.lastAccessed; oldestKey = key; } } if (oldestKey) { this._store.delete(oldestKey); } } } export default Cache; `; } _generateCache() { return `/** * Structured logger with levels and output formatting. */ const LEVELS = { debug: 0, info: 1, warn: 2, error: 3, }; class Logger { constructor(options = {}) { this.level = LEVELS[options.level] ?? LEVELS.info; this.prefix = options.prefix || ''; this.output = options.output || console; } /** * Creates a child logger with additional prefix. * @param {string} prefix - Child prefix * @returns {Logger} Child logger */ child(prefix) { return new Logger({ level: Object.keys(LEVELS).find(k => LEVELS[k] === this.level), prefix: this.prefix ? \`\${this.prefix}:\${prefix}\` : prefix, output: this.output, }); } debug(message, ...args) { this._log('debug', message, args); } info(message, ...args) { this._log('info', message, args); } warn(message, ...args) { this._log('warn', message, args); } error(message, ...args) { this._log('error', message, args); } _log(level, message, args) { if (LEVELS[level] < this.level) return; const timestamp = new Date().toISOString(); const prefix = this.prefix ? \`[\${this.prefix}]\` : ''; const formatted = \`\${timestamp} \${level.toUpperCase().padEnd(5)} \${prefix} \${message}\`; const method = level === 'error' ? 'error' : level === 'warn' ? 'warn' : 'log'; this.output[method](formatted, ...args); } } export default Logger; `; } _generateLogger() { return `/** * User model with validation and serialization. */ class User { constructor(data) { this.id = data.id || crypto.randomUUID(); this.email = data.email; this.name = data.name; this.role = data.role || 'user'; this.createdAt = data.createdAt || new Date(); this.updatedAt = new Date(); this.isActive = data.isActive ?? true; } /** * Validates user data. * @param {Object} data - User data * @returns {{valid: boolean, errors: string[]}} Validation result */ static validate(data) { const errors = []; if (!data.email || typeof data.email !== 'string') { errors.push('Email is required and must be a string'); } else if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(data.email)) { errors.push('Invalid email format'); } if (!data.name || typeof data.name !== 'string' || data.name.trim().length < 2) { errors.push('Name is required and must be at least 2 characters'); } if (data.role && !['admin', 'user', 'moderator'].includes(data.role)) { errors.push('Role must be admin, user, or moderator'); } return { valid: errors.length === 0, errors }; } /** * Updates user properties. * @param {Object} updates - Properties to update */ update(updates) { const allowedFields = ['name', 'email', 'role', 'isActive']; for (const [key, value] of Object.entries(updates)) { if (allowedFields.includes(key)) { this[key] = value; } } this.updatedAt = new Date(); } /** * Checks if user has a specific role. * @param {string} role - Role to check * @returns {boolean} True if user has role */ hasRole(role) { const roleHierarchy = { user: 0, moderator: 1, admin: 2 }; return (roleHierarchy[this.role] ?? 0) >= (roleHierarchy[role] ?? 0); } /** * Serializes user to JSON-safe object. * @returns {Object} Serialized user */ toJSON() { return { id: this.id, email: this.email, name: this.name, role: this.role, isActive: this.isActive, createdAt: this.createdAt.toISOString(), updatedAt: this.updatedAt.toISOString(), }; } } export default User; `; } _generateModel() { return `/** * Authentication middleware with token validation. */ const TOKEN_EXPIRY = 3600000; // 1 hour /** * Creates an authentication middleware. * @param {Object} options - Middleware options * @returns {Function} Auth middleware */ export function createAuthMiddleware(options = {}) { const secret = options.secret || process.env.JWT_SECRET; const excludedPaths = options.excludedPaths || ['/health', '/api/public']; if (!secret) { throw new Error('JWT_SECRET is required for auth middleware'); } return async function authMiddleware(req, res, next) { if (excludedPaths.some(path => req.url.startsWith(path))) { return next(); } const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith('Bearer ')) { return res.writeHead(401, { 'Content-Type': 'application/json' }) .end(JSON.stringify({ error: 'Missing or invalid authorization header' })); } const token = authHeader.slice(7); try { const payload = await verifyToken(token, secret); if (payload.exp && payload.exp < Date.now()) { throw new Error('Token expired'); } req.user = payload; next(); } catch (error) { return res.writeHead(401, { 'Content-Type': 'application/json' }) .end(JSON.stringify({ error: 'Invalid or expired token' })); } }; } /** * Verifies a JWT token (simplified implementation). * @param {string} token - JWT token * @param {string} secret - Signing secret * @returns {Object} Token payload */ async function verifyToken(token, secret) { const parts = token.split('.'); if (parts.length !== 3) { throw new Error('Invalid token format'); } const payload = JSON.parse(Buffer.from(parts[1], 'base64').toString()); return payload; } /** * Checks if user has required permissions. * @param {string[]} requiredPermissions - Required permissions * @returns {Function} Permission check middleware */ export function requirePermissions(requiredPermissions) { return function (req, res, next) { if (!req.user) { return res.writeHead(401).end('Unauthorized'); } const userPermissions = req.user.permissions || []; const hasPermission = requiredPermissions.every(p => userPermissions.includes(p)); if (!hasPermission) { return res.writeHead(403).end('Insufficient permissions'); } next(); }; } `; } _generateAuthMiddleware() { return `/** * Centralized error handler for HTTP services. */ class AppError extends Error { constructor(message, statusCode = 500, code = 'INTERNAL_ERROR') { super(message); this.name = 'AppError'; this.statusCode = statusCode; this.code = code; this.isOperational = true; Error.captureStackTrace(this, this.constructor); } } /** * Creates an error handling middleware. * @returns {Function} Error handler */ export function createErrorHandler() { return function errorHandler(err, req, res, next) { if (err.name === 'AppError') { return sendError(res, err.statusCode, err.code, err.message); } if (err.name === 'ValidationError') { return sendError(res, 400, 'VALIDATION_ERROR', err.message); } if (err.name === 'UnauthorizedError') { return sendError(res, 401, 'UNAUTHORIZED', 'Authentication required'); } console.error('Unhandled error:', err); return sendError( res, 500, 'INTERNAL_ERROR', process.env.NODE_ENV === 'production' ? 'An unexpected error occurred' : err.message ); }; } /** * Wraps an async route handler to catch errors. * @param {Function} handler - Route handler * @returns {Function} Wrapped handler */ export function asyncHandler(handler) { return function (req, res, next) { Promise.resolve(handler(req, res, next)).catch(next); }; } function sendError(res, statusCode, code, message) { res.writeHead(statusCode, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: false, error: { code, message }, })); } export { AppError }; `; } _generateErrorHandler() { return `/** * Rate limiter using sliding window algorithm. */ class RateLimiter { constructor(options = {}) { this.windowMs = options.windowMs || 60000; // 1 minute this.maxRequests = options.maxRequests || 100; this._requests = new Map(); } /** * Checks if a request is allowed. * @param {string} key - Identifier (IP, user ID, etc.) * @returns {{allowed: boolean, remaining: number, resetAt: number}} */ isAllowed(key) { const now = Date.now(); const windowStart = now - this.windowMs; if (!this._requests.has(key)) { this._requests.set(key, []); } const timestamps = this._requests.get(key); // Remove expired timestamps while (timestamps.length > 0 && timestamps[0] <= windowStart) { timestamps.shift(); } const remaining = this.maxRequests - timestamps.length; if (remaining <= 0) { return { allowed: false, remaining: 0, resetAt: timestamps[0] + this.windowMs, }; } timestamps.push(now); return { allowed: true, remaining: remaining - 1, resetAt: now + this.windowMs, }; } /** * Creates middleware function for HTTP servers. * @param {Function} [keyFn] - Function to extract key from request * @returns {Function} Rate limit middleware */ middleware(keyFn = (req) => req.ip || req.socket.remoteAddress) { return (req, res, next) => { const key = keyFn(req); const result = this.isAllowed(key); res.setHeader('X-RateLimit-Limit', this.maxRequests); res.setHeader('X-RateLimit-Remaining', Math.max(0, result.remaining)); res.setHeader('X-RateLimit-Reset', result.resetAt); if (!result.allowed) { res.writeHead(429, { 'Content-Type': 'application/json' }); return res.end(JSON.stringify({ error: 'Too Many Requests', retryAfter: Math.ceil((result.resetAt - Date.now()) / 1000), })); } next(); }; } /** * Resets rate limit for a specific key. * @param {string} key - Identifier to reset */ reset(key) { this._requests.delete(key); } /** * Clears all rate limit data. */ clear() { this._requests.clear(); } } export default RateLimiter; `; } _generateRateLimiter() { return `/** * Rate limiter using sliding window algorithm. */ class RateLimiter { constructor(options = {}) { this.windowMs = options.windowMs || 60000; this.maxRequests = options.maxRequests || 100; this._requests = new Map(); } isAllowed(key) { const now = Date.now(); const windowStart = now - this.windowMs; if (!this._requests.has(key)) { this._requests.set(key, []); } const timestamps = this._requests.get(key); while (timestamps.length > 0 && timestamps[0] <= windowStart) { timestamps.shift(); } const remaining = this.maxRequests - timestamps.length; if (remaining <= 0) { return { allowed: false, remaining: 0, resetAt: timestamps[0] + this.windowMs, }; } timestamps.push(now); return { allowed: true, remaining: remaining - 1, resetAt: now + this.windowMs, }; } middleware(keyFn = (req) => req.ip) { return (req, res, next) => { const key = keyFn(req); const result = this.isAllowed(key); res.setHeader('X-RateLimit-Limit', this.maxRequests); res.setHeader('X-RateLimit-Remaining', Math.max(0, result.remaining)); if (!result.allowed) { res.writeHead(429, { 'Content-Type': 'application/json' }); return res.end(JSON.stringify({ error: 'Too Many Requests' })); } next(); }; } reset(key) { this._requests.delete(key); } clear() { this._requests.clear(); } } export default RateLimiter; `; } _injectBug(content) { const bugTypes = [ () => content.replace(/===/g, '==').replace(/!==/g, '!='), () => content.replace(/return null;/g, 'return undefined;'), () => content.replace(/const /g, 'let ').split('\n').slice(0, -3).join('\n') + '\n' + content.split('\n').slice(-3).join('\n'), () => content.replace(/\.length/g, '.lenght'), () => content.replace(/JSON.parse/g, 'JSON.parase'), ]; return sample(bugTypes)(); } _injectTypo(content) { const typoTypes = [ () => content.replace(/function /g, 'funciton '), () => content.replace(/parameter/g, 'paramter'), () => content.replace(/callback/g, 'callbak'), () => content.replace(/response/g, 'resposne'), () => content.replace(/undefined/g, 'undefiend'), ]; return sample(typoTypes)(); } generateTestFile(filePath, codeContent) { const fileName = filePath.split('/').pop().replace('.js', ''); return `import { describe, it, expect } from '@jest/globals'; import * as module from '../${fileName}.js'; describe('${fileName}', () => { it('should export expected functions', () => { const exports = Object.keys(module); expect(exports.length).toBeGreaterThan(0); }); it('should handle edge cases', () => { expect(() => module).not.toThrow(); }); }); `; } generateCommitMessageForFile(filePath, fileType) { const messages = { utility: [ `feat: add ${filePath.split('/').pop().replace('.js', '')} utility functions`, `feat(utils): implement reusable helper functions`, ], validator: [ `feat: add input validation utilities`, `feat(validation): add data validation helpers`, ], formatter: [ `feat: add formatting and transformation utilities`, `feat(formatting): implement data formatters`, ], api: [ `feat: implement API service with caching`, `feat(api): add HTTP client with request queuing`, ], cache: [ `feat: add in-memory cache with TTL support`, `feat(cache): implement LRU cache implementation`, ], logger: [ `feat: add structured logging utility`, `feat(logging): implement leveled logger`, ], model: [ `feat: add data model with validation`, `feat(model): implement ${filePath.split('/').pop().replace('.js', '')} entity`, ], auth: [ `feat: add authentication middleware`, `feat(auth): implement token-based auth`, ], error: [ `feat: add centralized error handling`, `feat(errors): implement error handler middleware`, ], rateLimiter: [ `feat: add rate limiting middleware`, `feat(rate-limit): implement sliding window rate limiter`, ], }; return sample(messages[fileType] || messages.utility); } } export default CodeGenerator;