1export function normalizeName(value) { 2 return String(value) 3 .normalize('NFD') 4 .replace(/[\u0300-\u036f]/g, '') 5 .replace(/[^a-z0-9]+/gi, '') 6 .toLowerCase(); 7} 8 9export function escHtml(str) { 10 return String(str || '') 11 .replace(/&/g, '&') 12 .replace(/"/g, '"') 13 .replace(/</g, '<') 14 .replace(/>/g, '>'); 15} 16 17export function safe(str) { 18 if (str === null || str === undefined) return ''; 19 return String(str) 20 .replace(/&/g, '&') 21 .replace(/</g, '<') 22 .replace(/>/g, '>') 23 .replace(/"/g, '"') 24 .replace(/'/g, ''') 25 .replace(/\//g, '/'); 26} 27 28const ALLOWED_IMAGE_DOMAINS = [ 29 'flagcdn.com', 30 'raw.githubusercontent.com', 31 'olborwfuotqrzpuvwnhu.supabase.co', 32 'upload.wikimedia.org', 33]; 34 35export function isAllowedImageUrl(url) { 36 if (!url) return false; 37 try { 38 const parsed = new URL(url); 39 if (parsed.protocol !== 'https:') return false; 40 return ALLOWED_IMAGE_DOMAINS.some(domain => 41 parsed.hostname === domain || parsed.hostname.endsWith('.' + domain) 42 ); 43 } catch { 44 return false; 45 } 46}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.