1const SEMVER = /^\d+\.\d+\.\d+$/; 2const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/; 3 4const isRealIsoDate = (value) => { 5 if (!ISO_DATE.test(value)) return false; 6 const date = new Date(`${value}T00:00:00.000Z`); 7 return !Number.isNaN(date.getTime()) && date.toISOString().slice(0, 10) === value; 8}; 9 10export function normalizeReleaseMetadata(value) { 11 if (!value || typeof value !== 'object') return null; 12 const version = typeof value.version === 'string' ? value.version.trim() : ''; 13 const updated = typeof value.updated === 'string' ? value.updated.trim() : ''; 14 if (!SEMVER.test(version) || !isRealIsoDate(updated)) return null; 15 return { version, updated }; 16} 17 18export function formatReleaseDate(value) { 19 if (typeof value !== 'string' || !isRealIsoDate(value)) return ''; 20 const date = new Date(`${value}T00:00:00.000Z`); 21 return new Intl.DateTimeFormat('en-US', { 22 month: 'long', 23 day: 'numeric', 24 year: 'numeric', 25 timeZone: 'UTC', 26 }).format(date); 27} 28 29export function createReleaseMetadataLoader({ 30 fetchImpl = globalThis.fetch, 31 url = './version.json', 32 now = Date.now, 33} = {}) { 34 let pending = null; 35 36 return () => { 37 if (pending) return pending; 38 const separator = url.includes('?') ? '&' : '?'; 39 const requestUrl = `${url}${separator}t=${now()}`; 40 const current = (async () => { 41 const response = await fetchImpl(requestUrl, { cache: 'no-store' }); 42 if (!response?.ok) { 43 throw new Error(`release metadata request failed: HTTP ${response?.status ?? 'unknown'}`); 44 } 45 const metadata = normalizeReleaseMetadata(await response.json()); 46 if (!metadata) throw new Error('release metadata response is invalid'); 47 return metadata; 48 })(); 49 50 pending = current; 51 current.catch(() => { 52 if (pending === current) pending = null; 53 }); 54 return current; 55 }; 56} 57 58export const loadReleaseMetadata = createReleaseMetadataLoader();
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.