export function normalizeLinkedInInput(raw: string): string { let working = (raw || '').trim(); if (!working) return ''; working = working.replace(/^['"]|['"]$/g, ''); const lower = working.toLowerCase(); const buildFromHandle = (handleRaw: string) => { let handle = (handleRaw || '').trim(); handle = handle.replace(/^@+/, ''); handle = handle.replace(/^in\//i, ''); handle = handle.replace(/^\/+/, ''); handle = handle.split('?')[0].split('#')[0]; handle = handle.replace(/[^a-zA-Z0-9._-]/g, '-'); handle = handle.replace(/-+/g, '-').replace(/^-+|-+$/g, ''); return handle ? `https://www.linkedin.com/in/${handle}` : 'https://www.linkedin.com/'; }; if (lower.includes('linkedin.com')) { let urlStr = working; if (!/^https?:\/\//i.test(urlStr)) { urlStr = 'https://' + urlStr.replace(/^\/+/, ''); } try { const u = new URL(urlStr); const parts = (u.pathname || '').split('/').filter(Boolean); const reserved = new Set(['pub', 'mwlite', 'profile', 'redir', 'sales', 'company', 'school', 'feed', 'posts', 'pulse']); let handle = ''; const inIndex = parts.findIndex(p => p.toLowerCase() === 'in'); if (inIndex >= 0 && parts[inIndex + 1]) { handle = parts[inIndex + 1]; } else { const candidates = parts.filter(p => !reserved.has(p.toLowerCase())); handle = candidates[candidates.length - 1] || ''; } return buildFromHandle(handle); } catch { // fall through to handle mode } } if (/^https?:\/\//i.test(working) || /^www\./i.test(working)) { return working; } return buildFromHandle(working); }