/** * Simple baseline normalization utility * Replaces dynamic values with placeholders for consistent baseline comparison */ export class BaselineNormalizer { /** * Normalize CLI output by replacing dynamic values with placeholders */ static normalize(output: string): string { let result = output; // Replace deprecation warnings first result = result.replace(/\(node:\d+\) \[DEP\d+\] DeprecationWarning: [^\n]+\n/g, ''); result = result.replace(/\(Use `node --trace-deprecation[^\n]+\n/g, ''); // Remove beta version warning result = result.replace(/You are running beta version[^\n]+\n/g, ''); // Replace environment result = result.replace(/Active environment: \w+/g, 'Active environment: '); // Replace user-specific data result = result.replace(/id: [a-f0-9-]{36}/g, 'id: '); result = result.replace(/email: [^\s]+@[^\s]+/g, 'email: '); result = result.replace(/role: [^\n]+/g, 'role: '); result = result.replace(/githubUsername: [^\s]+/g, 'githubUsername: '); result = result.replace(/createdAt: (?:'[^']+'|null)/g, "createdAt: "); result = result.replace(/vendor: [^\n]+/g, 'vendor: '); // Replace personal_apps - normalize to empty array result = result.replace(/personal_apps:\s*\n(?: - id: [^\n]+\n)+/g, 'personal_apps: []\n'); // Replace vendor_apps - keep structure but normalize to single entry result = result.replace(/vendor_apps:\s*\n(?: - id: [^\n]+\n?)+/g, 'vendor_apps:\n - id: '); // Replace timestamps first (before other patterns) result = result.replace(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z/g, ''); // Replace job IDs (UUIDs) result = result.replace(/[a-f0-9-]{36}/g, ''); // Replace version numbers (semantic versions including dev/beta/private) result = result.replace(/\d+\.\d+\.\d+(?:-dev\.\d+|-beta\.\d+|-private)?/g, ''); // Replace whois table data (normalize account info in table format) // Match lines that start with digits followed by spaces (account ID) result = result.replace(/^(\d+)(\s+)([A-Za-z0-9_-]+)(\s+)(.+?)(\s+)(\w+)$/gm, '$2$4$6'); // Replace directory info fields result = result.replace(/name\s+(.+)/g, 'name\t'); result = result.replace(/id\s+([a-zA-Z0-9_-]+)/g, 'id\t\t'); result = result.replace(/created\s+/g, 'created\t'); // Replace directory list table data (preserve table structure) // Only replace app IDs at start of lines that look like directory entries result = result.replace(/^([a-zA-Z0-9_-]+)(\s+\s+)/gm, '$2'); // Replace states and products result = result.replace(/(PUBLISHED|UNPUBLISHED|BUILT|BUILD_FAILED|BUILDING)/g, ''); result = result.replace(/(ODP|OCP|ZAIUS)(?=\s|$)/g, ''); result = result.replace(/(NOT_REQUIRED|REQUIRED)/g, ''); // Replace any remaining tracker IDs that look like Base64 result = result.replace(/[A-Za-z0-9_-]{22}/g, ''); // Replace job statuses and review statuses result = result.replace(/(COMPLETE|RUNNING|FAILED|PENDING|SUCCESS|ERROR|IN_REVIEW|APPROVED|REJECTED)/g, ''); // Replace function names (words before tracker IDs in job tables) result = result.replace(/\w+(?=\s+)/g, ''); // Replace durations result = result.replace(/[\d\.]+ms/g, ''); result = result.replace(/[\d\.]+s/g, ''); result = result.replace(/Duration: [\d\.]+/g, 'Duration: '); // Normalize whitespace result = result.replace(/\s+$/gm, ''); // Remove trailing whitespace result = result.replace(/\n{3,}/g, '\n\n'); // Normalize multiple newlines result = result.replace(/\s+/g, ' '); // Normalize formatting return result.trim(); } }