import type { OperationCategory } from '../types.js' /** * Category inference for route contracts. * Pure functions, no side effects. * Optimized: direct string comparison over Set for hot path. */ // Fast path: direct string comparison for most common utility paths const isUtilityPath = (path: string): boolean => { // Check exact matches first (fastest) if ( path === '/reset' || path === '/health' || path === '/ping' || path === '/login' || path === '/logout' || path === '/auth' || path === '/callback' || path === '/purge' || path === '/clear' || path === '/initialize' || path === '/setup' || path === '/webhook' ) { return true } // Check trailing slash variants const last = path.charCodeAt(path.length - 1) if (last === 47) { const base = path.slice(0, -1) return ( base === '/reset' || base === '/health' || base === '/ping' || base === '/login' || base === '/logout' || base === '/auth' || base === '/callback' || base === '/purge' || base === '/clear' || base === '/initialize' || base === '/setup' || base === '/webhook' ) } return false } // Fast path: check last 7 chars for common suffixes const isObserverSuffix = (path: string): boolean => { const len = path.length if (len >= 7) { const end = path.slice(-7) if (end === '/search') return true } if (len >= 6) { const end = path.slice(-6) if (end === '/count' || end === '/stats') return true } if (len >= 7) { const end = path.slice(-7) if (end === '/status') return true } return false } const isCollectionPath = (path: string): boolean => { const len = path.length let i = len - 1 // Skip trailing slash while (i > 0 && path.charCodeAt(i) === 47) i-- // Find last segment const lastSlash = path.lastIndexOf('/', i) const segment = path.slice(lastSlash + 1, i + 1) return segment.length > 0 && segment.charCodeAt(0) !== 58 // ':'.charCodeAt(0) === 58 } const hasPathParam = (path: string): boolean => path.includes(':') export const inferCategory = ( path: string, method: string, override: string | undefined ): OperationCategory => { if (override !== undefined && override !== '') { return override as OperationCategory } if (isUtilityPath(path)) { return 'utility' } const upperMethod = method.toUpperCase() if (upperMethod === 'GET' || isObserverSuffix(path)) { return 'observer' } if (upperMethod === 'POST' && isCollectionPath(path)) { return 'constructor' } if (upperMethod === 'PUT' || upperMethod === 'PATCH' || upperMethod === 'DELETE' || (upperMethod === 'POST' && hasPathParam(path))) { return 'mutator' } return 'observer' }