Files
MikrotikManager/lib/release-metadata.ts
T

32 lines
2.2 KiB
TypeScript

export interface ReleaseCommit {
sha:string; shortSha:string; subject:string; author:string; type:string
}
export interface ReleaseManifest {
version:string; tag:string; publishedAt:string|null; releaseUrl:string; commits:ReleaseCommit[]
}
export function safeReleaseUrl(value:unknown):string|null {
if(typeof value!=="string"||!value.trim())return null
try{const url=new URL(value.trim());return ["https:","http:"].includes(url.protocol)&&!url.username&&!url.password?url.href:null}catch{return null}
}
const text=(value:unknown,max:number):value is string=>typeof value==="string"&&value.length>0&&value.length<=max
export function parseReleaseManifest(value:unknown):ReleaseManifest|null {
if(!value||typeof value!=="object"||Array.isArray(value))return null
const row=value as Record<string,unknown>
if(!text(row.version,100)||!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(row.version)||row.tag!=="v"+row.version)return null
if(row.publishedAt!==null&&(typeof row.publishedAt!=="string"||!/^\d{4}-\d{2}-\d{2}T.*(?:Z|[+-]\d{2}:\d{2})$/.test(row.publishedAt)||!Number.isFinite(Date.parse(row.publishedAt))))return null
if(typeof row.releaseUrl!=="string"||(row.releaseUrl!==""&&!safeReleaseUrl(row.releaseUrl)))return null
if(!Array.isArray(row.commits)||row.commits.length>1000)return null
const commits:ReleaseCommit[]=[];const ids=new Set<string>()
for(const item of row.commits){
if(!item||typeof item!=="object"||Array.isArray(item))return null
const c=item as Record<string,unknown>
if(!text(c.sha,64)||! /^[a-f0-9]{7,64}$/i.test(c.sha)||ids.has(c.sha)||!text(c.shortSha,12)||! /^[a-f0-9]{4,12}$/i.test(c.shortSha)||!c.sha.startsWith(c.shortSha)||!text(c.subject,4000)||!text(c.author,500)||!text(c.type,30))return null
ids.add(c.sha);commits.push({sha:c.sha,shortSha:c.shortSha,subject:c.subject,author:c.author,type:c.type})
}
return {version:row.version,tag:row.tag as string,publishedAt:row.publishedAt as string|null,releaseUrl:row.releaseUrl? safeReleaseUrl(row.releaseUrl)!:"",commits}
}
export function shouldShowReleaseNotes(manifest:ReleaseManifest,currentVersion:string):boolean {
return !currentVersion.endsWith("-dev")&&manifest.version===currentVersion&&manifest.commits.length>0
}