refactor: opruimen EVENT_PREFIXES (geen dubbele keys), Engelse namen, uitgebreide event-woordenlijst
CI / check (push) Successful in 25s
CI / release (push) Skipped
CI / deploy (push) Successful in 48s

This commit is contained in:
openhands committed 2026-08-04 16:39:35 +02:00
1 parent 91254bcec2
commit d527ed9bfe
1 file changed
+248 -65
+248 -65
View File
@@ -31,74 +31,257 @@ function escSqlLiteral(value: string): string {
}
/**
* Derive a human-readable English page caption from a furniture classname that
* follows an event+year pattern (e.g. `xmas2025`, `hween2024`, `val_2025`).
* Covers the full range of seasonal/holiday prefixes that have appeared in
* Habbo's history. Falls back to `fallback` when no pattern matches.
* Mapping of event prefix substrings (lowercase, no leading underscore) to
* their human-readable English page labels. Covers every seasonal/holiday/event
* abbreviation that has appeared across Habbo's history. Extend this map as new
* prefixes surface.
*/
const EVENT_PREFIXES: Record<string, string> = {
// Seasonal / Holiday events
xmas: "Christmas",
christmas: "Christmas",
xmastree: "Christmas",
xmasgift: "Christmas",
xmaspresent: "Christmas",
xmaseve: "Christmas",
hween: "Halloween",
halloween: "Halloween",
hw: "Halloween",
hall: "Halloween",
spook: "Halloween",
easter: "Easter",
easterbunny: "Easter",
val: "Valentine's Day",
valentine: "Valentine's Day",
valentines: "Valentine's Day",
love: "Valentine's Day",
heart: "Valentine's Day",
newyear: "New Year",
nye: "New Year",
countdown: "New Year",
summer: "Summer",
summersale: "Summer",
sun: "Summer",
tropic: "Summer",
tropical: "Summer",
resort: "Summer",
fall: "Fall",
autumn: "Autumn",
harvest: "Fall",
winter: "Winter",
snow: "Winter",
snowman: "Winter",
frost: "Winter",
glacier: "Winter",
arctic: "Winter",
icicle: "Winter",
carnival: "Carnival",
festival: "Carnival",
mardi: "Carnival",
mardigras: "Carnival",
fair: "Fair",
rodeo: "Fair",
thanksgiving: "Thanksgiving",
stpat: "St. Patrick's Day",
stpaddy: "St. Patrick's Day",
green: "St. Patrick's Day",
hanukkah: "Hanukkah",
chanukah: "Hanukkah",
diwali: "Diwali",
deepavali: "Diwali",
holiday: "Holiday",
holidays: "Holiday",
// Habbo-specific events
anniversary: "Anniversary",
anniv: "Anniversary",
hb: "Habbo Birthday",
hbday: "Habbo Birthday",
birthday: "Birthday",
habbohome: "HabboHome",
quest: "Quest Event",
mission: "Mission Event",
task: "Task Event",
challenge: "Challenge Event",
gm: "GM Event",
gamemaker: "GM Event",
moderation: "Staff Event",
staff: "Staff Event",
club: "Habbo Club",
hc: "Habbo Club",
nitro: "Nitro Event",
bingo: "Bingo",
quiz: "Quiz",
trivia: "Quiz",
game: "Games",
arcade: "Arcade",
puzzle: "Puzzles",
// Clothing / Fashion
clothing: "Clothing",
clothes: "Clothing",
shirt: "Clothing",
pants: "Clothing",
shoes: "Clothing",
hat: "Clothing",
costume: "Costumes",
dress: "Dresses",
// Furniture categories
room: "Room Furniture",
wall: "Wall Items",
floor: "Floor Items",
wallpaper: "Wallpapers",
tile: "Floor Tiles",
carpet: "Carpets",
rug: "Rugs",
door: "Doors",
gate: "Gates",
stair: "Stairs",
light: "Lighting",
lamp: "Lighting",
chair: "Chairs",
table: "Tables",
sofa: "Sofas",
bed: "Beds",
storage: "Storage",
wardrobe: "Wardrobes",
closet: "Wardrobes",
plant: "Plants",
flower: "Plants",
tree: "Plants",
bush: "Plants",
grass: "Plants",
sign: "Signs",
board: "Signs",
poster: "Posters",
banner: "Banners",
flag: "Flags",
statue: "Statues",
fountain: "Fountains",
pond: "Ponds",
garden: "Garden",
kitchen: "Kitchen",
bathroom: "Bathroom",
bath: "Bathroom",
book: "Books",
shelf: "Shelves",
bookshelf: "Bookshelves",
cabinet: "Cabinets",
drawer: "Drawers",
chest: "Storage",
box: "Storage",
trunk: "Storage",
crate: "Storage",
// Pets
pet: "Pets",
dog: "Dogs",
cat: "Cats",
bird: "Birds",
horse: "Horses",
pig: "Pets",
monkey: "Monkeys",
frog: "Pets",
bear: "Bears",
spider: "Pets",
bunny: "Rabbits",
rabbit: "Rabbits",
reptile: "Reptiles",
lizard: "Reptiles",
snake: "Reptiles",
tank: "Fish Tank",
fish: "Fish",
// Effects / Badges
badge: "Badges",
effect: "Effects",
bg: "Background",
aura: "Auras",
// Wired
wired: "Wired",
wf: "Wired",
trigger: "Wired",
// Credits / Exchange
credit: "Credits",
cf: "Credit Furniture",
exe: "Exchange",
diamond: "Diamonds",
ducket: "Duckets",
// Music
trax: "Music",
jukebox: "Music",
sound: "Sound",
record: "Records",
stereo: "Music",
musicdisk: "Music",
musicdisc: "Music",
// VIP / Rares / Nitro
rare: "Rares",
vip: "VIP",
exclusive: "Exclusive",
collectible: "Collectible",
vintage: "Vintage",
retro: "Retro",
classic: "Classic",
};
/**
* Derive a human-readable English page caption from a furniture classname.
* Automatically detects event prefixes (xmas2025 → "Christmas 2025") using a
* comprehensive dictionary of Habbo event abbreviations. Handles multiple
* separator styles (_, nothing). When no known pattern matches, returns the
* fallback caption.
*/
function derivePageCaption(classname: string, fallback: string): string {
const m = classname.match(
/^(xmas|hween|halloween|easter|val_|valentine|hw_|newyear|nye|summer|sum_|carnival|carnival_|christmas|xmas_|easter_|valentines|anniversary|anniv_|anniv|hb_|_hb|hb|habbohome|hh_|easter_bunny|easterbunny|easter_b|spring|summer_|summer2|summersale|fall|autumn|autumn_|fall_|winter|winter_|xmas2|christmas2|xmas20|holiday|holidays|holiday_|halloween2|hween2|hween_)(_?)(\d{4})/i,
const lower = classname.toLowerCase();
// Try to extract a year from anywhere in the classname.
const yearMatch = lower.match(/(\d{4})/);
const year = yearMatch ? yearMatch[1] : null;
// Check for known event prefixes. Iterate from longest prefix to shortest
// to avoid partial matches (e.g., "hween" before "hw").
const sortedPrefixes = Object.keys(EVENT_PREFIXES).sort(
(a, b) => b.length - a.length,
);
if (!m) return fallback;
const event = m[1].toLowerCase();
const year = m[3];
const eventNames: Record<string, string> = {
xmas: "Christmas",
xmas_: "Christmas",
xmas2: "Christmas",
xmas20: "Christmas",
christmas: "Christmas",
christmas_: "Christmas",
christmas2: "Christmas",
hween: "Halloween",
hween_: "Halloween",
hween2: "Halloween",
halloween: "Halloween",
halloween_: "Halloween",
halloween2: "Halloween",
hw_: "Halloween",
easter: "Easter",
easter_: "Easter",
easter_bunny: "Easter",
easterbunny: "Easter",
easter_b: "Easter",
val_: "Valentine's Day",
valentine: "Valentine's Day",
valentine_: "Valentine's Day",
valentines: "Valentine's Day",
valentines_: "Valentine's Day",
newyear: "New Year",
nye: "New Year",
newyear_: "New Year",
summer: "Summer",
summer_: "Summer",
summer2: "Summer",
summersale: "Summer Sale",
fall: "Fall",
fall_: "Fall",
autumn: "Autumn",
autumn_: "Autumn",
winter: "Winter",
winter_: "Winter",
carnival: "Carnival",
carnival_: "Carnival",
anniversary: "Anniversary",
anniv: "Anniversary",
anniv_: "Anniversary",
anniversary_: "Anniversary",
hb: "Habbo Birthday",
_hb: "Habbo Birthday",
hb_: "Habbo Birthday",
habbohome: "HabboHome",
hh_: "Habbo Birthday",
spring: "Spring",
holiday: "Holiday",
holiday_: "Holiday",
holidays: "Holiday",
holidays_: "Holiday",
};
return `${eventNames[event] ?? event} ${year}`;
for (const prefix of sortedPrefixes) {
const re = new RegExp(`^${prefix.replace(/_/g, "[_]?")}(?:_)?(\\d*)`, "i");
const m = lower.match(re);
if (m) {
const matchEnd = m.index! + m[0].length;
const nextChar = lower[matchEnd];
if (
!nextChar ||
nextChar === "_" ||
nextChar === "." ||
/\d/.test(nextChar)
) {
const event = EVENT_PREFIXES[prefix.toLowerCase()];
return year ? `${event} ${year}` : event;
}
}
}
// Also try matching suffix patterns (e.g., "something_xmas2025").
for (const prefix of sortedPrefixes) {
const re = new RegExp(
`${prefix.replace(/_/g, "[_]?")}(?:_)?(\\d{4})` + "(_|$)",
"i",
);
const m = lower.match(re);
if (m) {
const event = EVENT_PREFIXES[prefix.toLowerCase()];
return year ? `${event} ${year}` : event;
}
}
return fallback;
}
/**