Skip to content

Commit 0e94250

Browse files
committed
Bun
1 parent d241612 commit 0e94250

File tree

4 files changed

+82
-24
lines changed

4 files changed

+82
-24
lines changed

lib/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import path from "node:path";
1111
import fs from "node:fs";
1212

1313
export const BASE_DIR = new URL("..", import.meta.url);
14+
export const RUNTIME_IDS_WITH_PATCH_VERSIONING = new Set(["bun"]); // List of browsers/runtimes that might add features in patches
1415

1516
/**
1617
* Tests a specified path to see if it's a local checkout of mdn/browser-compat-data

lib/ua-parser.test.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {assert} from "chai";
1111
import {getMajorMinorVersion, parseUA} from "./ua-parser.js";
1212

1313
const browsers = {
14+
bun: {name: "Bun", releases: {"1.0.0": {}, "1.1.15": {}, "1.2.0": {}}},
1415
chrome: {name: "Chrome", releases: {82: {}, 83: {}, 84: {}, 85: {}}},
1516
chrome_android: {name: "Chrome Android", releases: {85: {}}},
1617
deno: {name: "Deno", releases: {1.42: {}}},
@@ -522,6 +523,46 @@ describe("parseUA", () => {
522523
});
523524
});
524525

526+
it("Bun 1.0.0 (preserves patch version)", () => {
527+
assert.deepEqual(parseUA("!! bun/1.0.0", browsers), {
528+
browser: {id: "bun", name: "Bun"},
529+
version: "1.0.0",
530+
fullVersion: "1.0.0",
531+
os: {name: "", version: ""},
532+
inBcd: true,
533+
});
534+
});
535+
536+
it("Bun 1.1.15 (preserves patch version)", () => {
537+
assert.deepEqual(parseUA("!! bun/1.1.15", browsers), {
538+
browser: {id: "bun", name: "Bun"},
539+
version: "1.1.15",
540+
fullVersion: "1.1.15",
541+
os: {name: "", version: ""},
542+
inBcd: true,
543+
});
544+
});
545+
546+
it("Bun 1.2.0 (preserves patch version)", () => {
547+
assert.deepEqual(parseUA("!! bun/1.2.0", browsers), {
548+
browser: {id: "bun", name: "Bun"},
549+
version: "1.2.0",
550+
fullVersion: "1.2.0",
551+
os: {name: "", version: ""},
552+
inBcd: true,
553+
});
554+
});
555+
556+
it("Bun 1.1.16 (not in BCD)", () => {
557+
assert.deepEqual(parseUA("!! bun/1.1.16", browsers), {
558+
browser: {id: "bun", name: "Bun"},
559+
version: "1.1.16",
560+
fullVersion: "1.1.16",
561+
os: {name: "", version: ""},
562+
inBcd: false,
563+
});
564+
});
565+
525566
it("Chrome on iOS (not in BCD)", () => {
526567
assert.deepEqual(
527568
parseUA(

lib/ua-parser.ts

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
import {UAParser} from "ua-parser-js";
1515

1616
import type {ParsedUserAgent} from "../types/types.d.ts";
17+
import {RUNTIME_IDS_WITH_PATCH_VERSIONING} from "./constants.js";
1718

1819
/**
1920
* Returns the major version from a given version string.
@@ -111,7 +112,12 @@ const parseUA = (userAgent: string, browsers: Browsers): ParsedUserAgent => {
111112
}
112113

113114
data.fullVersion = data.fullVersion || ua.browser.version || "0";
114-
data.version = getMajorMinorVersion(data.fullVersion);
115+
116+
if (RUNTIME_IDS_WITH_PATCH_VERSIONING.has(data.browser.id)) {
117+
data.version = data.fullVersion;
118+
} else {
119+
data.version = getMajorMinorVersion(data.fullVersion);
120+
}
115121

116122
if (data.browser.id == "bun") {
117123
data.version = data.fullVersion;
@@ -155,36 +161,46 @@ const parseUA = (userAgent: string, browsers: Browsers): ParsedUserAgent => {
155161
// with this, find the pair of versions in |versions| that sandwiches
156162
// |version|, and use the first of this pair. For example, given |version|
157163
// "10.1" and |versions| entries "10.0" and "10.2", return "10.0".
158-
for (let i = 0; i < versions.length - 1; i++) {
159-
const current = versions[i];
160-
const next = versions[i + 1];
161-
if (
162-
compareVersions(data.version, current, ">=") &&
163-
compareVersions(data.version, next, "<")
164-
) {
164+
// However, for Bun, we need exact version matches because patch versions can add features.
165+
if (RUNTIME_IDS_WITH_PATCH_VERSIONING.has(data.browser.id)) {
166+
// For Bun, only mark as inBcd if exact version exists
167+
if (versions.includes(data.version)) {
165168
data.inBcd = true;
166-
data.version = current;
167-
break;
169+
}
170+
} else {
171+
for (let i = 0; i < versions.length - 1; i++) {
172+
const current = versions[i];
173+
const next = versions[i + 1];
174+
if (
175+
compareVersions(data.version, current, ">=") &&
176+
compareVersions(data.version, next, "<")
177+
) {
178+
data.inBcd = true;
179+
data.version = current;
180+
break;
181+
}
168182
}
169183
}
170184

171185
// We reached the last entry in |versions|. With no |next| to compare against
172186
// we have to check if it looks like a significant release or not. By default
173187
// that means a new major version, but for Safari and Samsung Internet the
174188
// major and minor version are significant.
175-
let normalize = getMajorVersion;
176-
if (
177-
data.browser.id.startsWith("safari") ||
178-
data.browser.id === "samsunginternet_android"
179-
) {
180-
normalize = getMajorMinorVersion;
181-
}
182-
if (
183-
data.inBcd == false &&
184-
normalize(data.version) === normalize(versions[versions.length - 1])
185-
) {
186-
data.inBcd = true;
187-
data.version = versions[versions.length - 1];
189+
if (!RUNTIME_IDS_WITH_PATCH_VERSIONING.has(data.browser.id)) {
190+
let normalize = getMajorVersion;
191+
if (
192+
data.browser.id.startsWith("safari") ||
193+
data.browser.id === "samsunginternet_android"
194+
) {
195+
normalize = getMajorMinorVersion;
196+
}
197+
if (
198+
data.inBcd == false &&
199+
normalize(data.version) === normalize(versions[versions.length - 1])
200+
) {
201+
data.inBcd = true;
202+
data.version = versions[versions.length - 1];
203+
}
188204
}
189205

190206
return data;

scripts/find-missing-reports.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ const generateReportMap = (filter: string) => {
5050
for (const browser of Object.keys(browsers)) {
5151
if (
5252
filter !== "all" &&
53-
["ie", "nodejs", "deno", "oculus"].includes(browser)
53+
["ie", "nodejs", "deno", "bun", "oculus"].includes(browser)
5454
) {
5555
continue;
5656
}

0 commit comments

Comments
 (0)