open source is social v-it.org
at main 97 lines 2.5 kB view raw
1// SPDX-License-Identifier: MIT 2// Copyright (c) 2026 sol pbc 3 4export function parseGitUrl(input) { 5 if (typeof input !== 'string' || input.trim() === '') { 6 throw new Error('Invalid git URL: ' + String(input)); 7 } 8 9 const raw = input.trim(); 10 const normalizedError = () => new Error('Invalid git URL: ' + raw); 11 12 let host = ''; 13 let path = ''; 14 15 if (raw.includes('@') && !raw.includes('://')) { 16 const atIndex = raw.lastIndexOf('@'); 17 const hostAndPath = raw.slice(atIndex + 1); 18 const colonIndex = hostAndPath.indexOf(':'); 19 if (colonIndex === -1) { 20 throw normalizedError(); 21 } 22 host = hostAndPath.slice(0, colonIndex); 23 path = hostAndPath.slice(colonIndex + 1); 24 if (!host || !path) { 25 throw normalizedError(); 26 } 27 } else if (raw.includes('://')) { 28 let url; 29 try { 30 url = new URL(raw); 31 } catch { 32 throw normalizedError(); 33 } 34 host = url.hostname; 35 path = url.pathname; 36 if (!host) { 37 throw normalizedError(); 38 } 39 } else { 40 const slashIndex = raw.indexOf('/'); 41 if (slashIndex !== -1) { 42 const maybeHost = raw.slice(0, slashIndex); 43 if (maybeHost.includes('.')) { 44 host = maybeHost; 45 path = raw.slice(slashIndex + 1); 46 if (!host) { 47 throw normalizedError(); 48 } 49 } else { 50 throw normalizedError(); 51 } 52 } else { 53 throw normalizedError(); 54 } 55 } 56 57 const cleanedPath = path.replace(/^\/+|\/+$/g, '').replace(/\.git$/, ''); 58 const segments = cleanedPath.split('/').filter(Boolean); 59 60 if (segments.length === 0 || segments.length >= 3) { 61 throw normalizedError(); 62 } 63 64 let org = ''; 65 let repo = ''; 66 if (segments.length === 1) { 67 repo = segments[0]; 68 } else { 69 org = segments[0]; 70 repo = segments[1]; 71 } 72 73 host = host.toLowerCase(); 74 org = org.toLowerCase(); 75 repo = repo.toLowerCase(); 76 77 if (!repo) { 78 throw normalizedError(); 79 } 80 81 return { host, org, repo }; 82} 83 84export function toBeacon(input) { 85 const { host, org, repo } = parseGitUrl(input); 86 return org ? `${host}/${org}/${repo}` : `${host}//${repo}`; 87} 88 89export function beaconToHttps(input) { 90 if (typeof input === 'string' && input.startsWith('vit:')) { 91 const path = input.slice(4); 92 if (!path) throw new Error('Invalid beacon URI: ' + input); 93 return 'https://' + path.replace(/\/\//, '/'); 94 } 95 const { host, org, repo } = parseGitUrl(input); 96 return org ? `https://${host}/${org}/${repo}` : `https://${host}/${repo}`; 97}