diff --git a/lib/constants.ts b/lib/constants.ts index 0dd67afac..67db9e18d 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -11,7 +11,11 @@ import path from "node:path"; import fs from "node:fs"; export const BASE_DIR = new URL("..", import.meta.url); -export const RUNTIME_IDS_WITH_PATCH_VERSIONING = new Set(["bun"]); // List of browsers/runtimes that might add features in patches +export const RUNTIME_IDS_WITH_PATCH_VERSIONING = new Set([ + "bun", + "servo", + "servo_android", +]); // List of browsers/runtimes that might add features in patches /** * Tests a specified path to see if it's a local checkout of mdn/browser-compat-data diff --git a/lib/ua-parser.test.ts b/lib/ua-parser.test.ts index 97d85e819..a318cfa34 100644 --- a/lib/ua-parser.test.ts +++ b/lib/ua-parser.test.ts @@ -42,6 +42,14 @@ const browsers = { name: "WebView Android", releases: {1.1: {}, 4.4: {}, "4.4.3": {}, 37: {}, 86: {}}, }, + servo: { + name: "Servo", + releases: {"0.0.1": {}}, + }, + servo_android: { + name: "Servo Android", + releases: {"0.0.1": {}}, + }, }; describe("getMajorMinorVersion", () => { @@ -407,6 +415,38 @@ describe("parseUA", () => { ); }); + it("Servo 140 Linux", () => { + assert.deepEqual( + parseUA( + "Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Servo/0.0.1 Firefox/140.0", + browsers, + ), + { + browser: {id: "servo", name: "Servo"}, + version: "0.0.1", + fullVersion: "0.0.1", + os: {name: "Linux", version: ""}, + inBcd: true, + }, + ); + }); + + it("Servo 140 Android", () => { + assert.deepEqual( + parseUA( + "Mozilla/5.0 (Android 10; Mobile; rv:140.0) Servo/0.0.1 Firefox/140.0", + browsers, + ), + { + browser: {id: "servo_android", name: "Servo Android"}, + version: "0.0.1", + fullVersion: "0.0.1", + os: {name: "Android", version: "10"}, + inBcd: true, + }, + ); + }); + it("WebView Android (Android Browser, 1.1)", () => { assert.deepEqual( parseUA( diff --git a/lib/ua-parser.ts b/lib/ua-parser.ts index 3c29f16d2..ccf7e670f 100644 --- a/lib/ua-parser.ts +++ b/lib/ua-parser.ts @@ -57,6 +57,16 @@ const parseUA = (userAgent: string, browsers: Browsers): ParsedUserAgent => { const [runtime, runtimeVersion] = userAgent.replace("!! ", "").split("/"); data.browser.id = runtime; data.fullVersion = runtimeVersion; + } else if (userAgent.includes("Servo/")) { + // Servo browser detection + const servoMatch = userAgent.match(/Servo\/([\d.]+)/); + if (servoMatch) { + data.browser.id = "servo"; + data.browser.name = "Servo"; + data.fullVersion = servoMatch[1]; + } + data.os.name = ua.os.name || ""; + data.os.version = ua.os.version || ""; } else { if (!ua.browser.name) { return data;