123 lines
3.5 KiB
TypeScript
123 lines
3.5 KiB
TypeScript
import { HTMLElement, parse } from "node-html-parser";
|
|
|
|
/**
|
|
* Represents a BIOS entry with version, date, changelog, and optional download URL.
|
|
*/
|
|
export class Bios {
|
|
/** BIOS release date (YYYY/MM/DD) */
|
|
readonly date: string;
|
|
/** BIOS version string */
|
|
readonly version: string;
|
|
/** BIOS changelog/description */
|
|
readonly changelog: string;
|
|
/** Optional download URL for the BIOS file */
|
|
readonly url?: string;
|
|
|
|
/**
|
|
* @param date - BIOS release date
|
|
* @param version - BIOS version string
|
|
* @param changelog - BIOS changelog/description
|
|
* @param url - Optional download URL
|
|
* @throws Error if required fields are missing
|
|
*/
|
|
constructor(
|
|
date: string,
|
|
version: string,
|
|
changelog: string,
|
|
url?: string,
|
|
) {
|
|
if (!date?.trim() || !version?.trim() || !changelog?.trim()) {
|
|
throw new Error(
|
|
"Required BIOS information missing: date, version, or changelog",
|
|
);
|
|
}
|
|
this.date = date.trim();
|
|
this.version = version.trim();
|
|
this.changelog = changelog.trim();
|
|
this.url = url?.trim();
|
|
}
|
|
|
|
/**
|
|
* Returns a formatted string representation of the BIOS entry.
|
|
*/
|
|
toString(): string {
|
|
return `${this.version} (${this.date}):\n ${this.changelog}\n ${this.url}`;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fetches and parses BIOS information from a motherboard support page.
|
|
* @param mobo - URL of the motherboard support page
|
|
* @returns Promise containing array of Bios objects
|
|
* @throws Error if the URL is invalid or parsing fails
|
|
*/
|
|
export async function getBios(mobo: string): Promise<Bios[]> {
|
|
if (!mobo || !/^https?:\/\//.test(mobo)) {
|
|
throw new Error("Invalid motherboard URL: must start with http or https");
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(mobo);
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
}
|
|
const body = await response.text();
|
|
const root = parse(body);
|
|
const biosList: Bios[] = [];
|
|
|
|
const rows = root.querySelectorAll("table>tbody>tr");
|
|
if (!rows.length) {
|
|
console.warn("No BIOS entries found in the table");
|
|
return biosList;
|
|
}
|
|
|
|
for (const tr of rows) {
|
|
try {
|
|
biosList.push(parseBiosRow(tr));
|
|
} catch (error) {
|
|
const message = error instanceof Error ? error.message : String(error);
|
|
console.error("Failed to parse BIOS row:", message);
|
|
}
|
|
}
|
|
return biosList;
|
|
} catch (error) {
|
|
const message = error instanceof Error ? error.message : String(error);
|
|
throw new Error(`Failed to fetch BIOS information: ${message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parses a table row into a Bios object.
|
|
* @param tr - HTML table row element
|
|
* @returns Bios object
|
|
* @throws Error if the row format is invalid
|
|
*/
|
|
function parseBiosRow(tr: HTMLElement): Bios {
|
|
try {
|
|
const tds = tr.querySelectorAll("td");
|
|
if (tds.length < 6) {
|
|
throw new Error(
|
|
`Invalid table row format: expected >=6 columns, got ${tds.length}`,
|
|
);
|
|
}
|
|
// Try to resolve the link to an absolute URL if possible
|
|
const link = tds[5].querySelector("a")?.getAttribute("href");
|
|
let url: string | undefined = undefined;
|
|
if (link) {
|
|
try {
|
|
url = encodeURI(link).replace(/[(]/g, "%28").replace(/[)]/g, "%29");
|
|
} catch {
|
|
url = link;
|
|
}
|
|
}
|
|
return new Bios(
|
|
tds[1].text, // date
|
|
tds[0].text, // version
|
|
tds[4].text, // changelog
|
|
url,
|
|
);
|
|
} catch (error) {
|
|
const message = error instanceof Error ? error.message : String(error);
|
|
throw new Error(`Error parsing BIOS row: ${message}`);
|
|
}
|
|
}
|