From edb4ef30e25957fed1f0598fd7bba2cff644c9da Mon Sep 17 00:00:00 2001 From: Shubhadeep Date: Sun, 16 Aug 2026 18:06:57 +0530 Subject: [PATCH] fix(supported): collapse brand typos onto canonical names Reddragon and Eyooso catalog submissions previously surfaced as separate brand groups. canonicalBrand() now folds free-text variants onto the canonical names (Redragon, E-YOOSO) used by the static table, and the Eyooso row is renamed to E-YOOSO. --- src/supported-live.test.ts | 31 +++++++++++++++++++++++++++++++ src/supported-live.ts | 18 +++++++++++++++--- src/supported-mice.ts | 2 +- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/supported-live.test.ts b/src/supported-live.test.ts index 17ee9fd..a204bfd 100644 --- a/src/supported-live.test.ts +++ b/src/supported-live.test.ts @@ -3,6 +3,7 @@ import test from "node:test"; import type { Mouse } from "./supported-mice.ts"; import { + canonicalBrand, mergeLiveMice, normalizeKey, registrySupportedModels, @@ -24,6 +25,36 @@ test("normalizeKey collapses case, spaces, and punctuation", () => { assert.equal(normalizeKey("Starlight-12 / ULX"), "starlight12ulx"); }); +test("canonicalBrand folds brand aliases onto the canonical name", () => { + assert.equal(canonicalBrand("Reddragon"), "Redragon"); + assert.equal(canonicalBrand(" REDDRAGON "), "Redragon"); + assert.equal(canonicalBrand("Red Dragon"), "Redragon"); + assert.equal(canonicalBrand("Redragon"), "Redragon"); + assert.equal(canonicalBrand("Eyooso"), "E-YOOSO"); + assert.equal(canonicalBrand("e-yooso"), "E-YOOSO"); + assert.equal(canonicalBrand("E-YOOSO"), "E-YOOSO"); + assert.equal(canonicalBrand("Logitech"), "Logitech"); +}); + +test("Reddragon requests merge under the Redragon brand instead of a new group", () => { + const merged = mergeLiveMice(BASE, live({}, [ + { + id: "r1", + manufacturer: "Reddragon", + model: "M725", + connection: "Wired", + features: [], + can_test: false, + status: "submitted", + vote_count: 7, + created_at: "2026-01-01T00:00:00Z", + }, + ])); + assert.equal(merged.filter((m) => m.brand === "Reddragon").length, 0, "no Reddragon brand may exist"); + const redragon = merged.find((m) => m.brand === "Redragon"); + assert.deepEqual([redragon?.brand, redragon?.model, redragon?.status, redragon?.req], ["Redragon", "M725", "pending", 7]); +}); + test("registrySupportedModels lists named driver-covered models without receivers or dupes", () => { const models = registrySupportedModels(); assert.ok(models.length > 0, "expected some registry-listed models"); diff --git a/src/supported-live.ts b/src/supported-live.ts index 6ae0942..12e98e3 100644 --- a/src/supported-live.ts +++ b/src/supported-live.ts @@ -24,8 +24,20 @@ export function normalizeKey(part: string): string { return part.toLowerCase().replace(/[^a-z0-9]+/g, "").trim(); } +/** + * Catalog submissions carry free-text manufacturer names, so brand typos and + * aliases collapse onto the canonical name used by the static table. + */ +export function canonicalBrand(brand: string): string { + const canonical: Record = { + reddragon: "Redragon", + eyooso: "E-YOOSO", + }; + return canonical[normalizeKey(brand)] ?? brand; +} + function brandModelKey(brand: string, model: string): string { - return `${normalizeKey(brand)}|${normalizeKey(model)}`; + return `${normalizeKey(canonicalBrand(brand))}|${normalizeKey(model)}`; } /** @@ -122,7 +134,7 @@ export function mergeLiveMice(base: Mouse[], live: LiveData | null): Mouse[] { if (r.status === "supported") { if (known.has(key)) continue; rows.push({ - brand: r.manufacturer, + brand: canonicalBrand(r.manufacturer), model: r.model, status: "supported", req: r.vote_count, @@ -134,7 +146,7 @@ export function mergeLiveMice(base: Mouse[], live: LiveData | null): Mouse[] { if (!PENDING_CATALOG_STATUSES.has(r.status)) continue; if (known.has(key)) continue; rows.push({ - brand: r.manufacturer, + brand: canonicalBrand(r.manufacturer), model: r.model, status: "pending", req: r.vote_count, diff --git a/src/supported-mice.ts b/src/supported-mice.ts index d53dfa6..b6c1b47 100644 --- a/src/supported-mice.ts +++ b/src/supported-mice.ts @@ -549,7 +549,7 @@ export const MICE: Mouse[] = [ note: "Protocol unknown" }, { brand: "Solakaka", model: "SM802 Pro", status: "unknown", req: 1, note: "Has its own web configurator" }, - { brand: "Eyooso", model: "X-44 Lite", status: "unknown", req: 1, + { brand: "E-YOOSO", model: "X-44 Lite", status: "unknown", req: 1, note: "Protocol unknown" }, { brand: "HAVIT", model: "Gamenote", status: "unknown", req: 1, note: "Protocol unknown" },