The browsers
The browsers the rules' floors name, worked out from MDN's
browser-compat-data. The date is the data's own, not today's, so the list moves only when
pnpm align moves the package, and two runs on one version agree.
A release counts once it's out, so a beta or a planned one doesn't. Samsung Internet names the Chromium it runs on as its engine version.
import bcd from "@mdn/browser-compat-data" with { type: "json" };
type Release = { release_date?: string; status: string; engine_version?: string };
const OUT = ["retired", "current", "esr"];
function released(browser: string): [string, Release][] {
const releases = (bcd.browsers as Record<string, { releases: Record<string, Release> }>)[browser];
return Object.entries(releases?.releases ?? {}).filter(
([, r]) => r.release_date && r.release_date <= bcd.__meta.timestamp && OUT.includes(r.status),
);
}
const major = (version: string): number => Number(version.split(".")[0]);
// Blink: the oldest Chromium released in the year before the data's date, or the current
// Samsung Internet's, when that's older.
function blink(): number {
const year = new Date(bcd.__meta.timestamp);
year.setFullYear(year.getFullYear() - 1);
const since = year.toISOString();
const chrome = released("chrome")
.filter(([, r]) => (r.release_date ?? "") >= since)
.map(([version]) => major(version));
const samsung = released("samsunginternet_android").find(([, r]) => r.status === "current");
return Math.min(...chrome, major(samsung?.[1].engine_version ?? "Infinity"));
}
// Gecko: the oldest ESR Mozilla supports.
const gecko = (): number =>
Math.min(
...released("firefox")
.filter(([, r]) => r.status === "esr")
.map(([v]) => major(v)),
);
// WebKit: the newest release listed of the major two before the current one.
function webkit(browser: string): string {
const versions = released(browser).map(([version]) => version);
const majors = [...new Set(versions.map(major))].sort((a, b) => b - a);
const floor = versions.filter((v) => major(v) === majors[2]);
return floor.sort((a, b) => Number.parseFloat(b) - Number.parseFloat(a))[0] ?? "";
}
export const BROWSERS = [
`chrome${blink()}`,
`edge${blink()}`,
`firefox${gecko()}`,
`safari${webkit("safari")}`,
`ios${webkit("safari_ios")}`,
];