import { slugFromTitle, watchBrand } from '../_auction-lib/categories.js'; import { popCultureCategory, sportsCategory } from '../_memorabilia-lib/index.js'; /** Firearms / ammunition are never emitted (compliance). */ export function isFirearm(text: string): boolean { return /\b(firearms?|rifles?|pistols?|shotguns?|revolvers?|handguns?|carbines?|ammunition|ammo|cartridges|\d+\s?(?:ga|gauge)\b|\.\d{2,3}\s?cal(?:iber)?|9\s?mm|air ?gun|bb gun)\b/i.test(text); } function tcg(title: string): string { if (/pok[eé]mon|charizard|pikachu/i.test(title)) return 'pokemon'; if (/magic:? the gathering|\bmtg\b/i.test(title)) return 'magic_the_gathering'; if (/yu-?gi-?oh/i.test(title)) return 'yugioh'; if (/\bone piece\b/i.test(title)) return 'one_piece_card_game'; if (/lorcana/i.test(title)) return 'disney_lorcana'; if (/\b(topps|panini|bowman|upper deck|fleer|donruss|rookie|psa|sgc|bgs)\b/i.test(title)) return sportsCategory(title); return 'other_tcg'; } /** * HiBid CategoryTree.fullCategory ("Coins & Currency - Currency - Canada") + lot title → taxonomy slug, * or null when the lot is outside the collectibles universe (real estate, vehicles, equipment, household…). * Only slugs present in data/taxonomy/categories.json are returned. */ /** New merchandise / liquidation lots that surface under collectible categories (wholesale, bulk packs, notices). */ const LIQUIDATION_TITLE = /\b(\d+\s?pcs?|\d+\s?pack|wholesale|liquidation|pallet|case of \d+|information only|do not bid|shelf pull|overstock|brand new in box|nib\b.*\bnew)\b/i; /** Sub-categories of "Antiques & Collectibles - Collectibles" that are household goods, not collectibles. */ const HOUSEHOLD_SUB = /bakeware|candle|ornaments?|kitchen|home d[eé]cor|linens?|bedding|lighting|office|garden|tools?|electronics|holiday|seasonal|party|crafts?|\bpet\b|baby|health|beauty|cleaning|storage|furniture|appliances?|cookware|tableware|dinnerware|drinkware|mugs?|frames?|wall art|rugs?|pillows?|blankets?|misc/; export function hibidCategory(fullCategory: string | null | undefined, title: string): string | null { const c = (fullCategory ?? '').toLowerCase(); if (!c) return null; if (isFirearm(c) || LIQUIDATION_TITLE.test(title)) return null; if (/^coins & currency/.test(c)) { const sub = c.replace(/^coins & currency/, ''); if (/currency|paper money|bank ?notes?/.test(sub) || /\b(bill|note|banknote|dollar bill)\b/i.test(title)) return 'banknotes'; if (/stamps?/.test(c)) return 'stamps'; return 'coins'; } if (/sports? (memorabilia|cards?)|sports? collectibles|^sports\b/.test(c)) return sportsCategory(title); if (/trading cards?|collectible card|card games?|tcg|non-?sport cards?/.test(c)) return /non-?sport/.test(c) ? 'non_sport_cards' : tcg(title); if (/comics?|comic books?/.test(c)) return popCultureCategory(title); if (/video ?games?|gaming consoles?/.test(c)) return 'video_games'; if (/toys? & hobbies|\btoys?\b|action figures?|dolls?|die-?cast|model (trains?|kits?|cars?)/.test(c)) { if (/model trains?|railroad/.test(c)) return 'model_trains'; if (/die-?cast|model cars?/.test(c)) return 'model_cars'; if (/dolls?/.test(c)) return 'dolls'; if (/action figures?/.test(c)) return 'action_figures'; return slugFromTitle(title, 'toys') ?? popCultureCategory(title); } if (/watches?/.test(c)) return watchBrand(title).slug; if (/jewelry|jewellery|gemstones?|diamonds?/.test(c)) return /\b(watch|wristwatch)\b/i.test(title) ? watchBrand(title).slug : /loose|unmounted|gia/i.test(title) ? 'gemstones' : 'jewelry'; if (/advertising|signs?|petroliana|breweriana|soda/.test(c)) return 'advertising'; if (/stamps?|philatel/.test(c)) return 'stamps'; if (/militaria|military collectibles|medals?/.test(c)) return /\bmedal/i.test(title) ? 'medals' : 'militaria'; if (/musical instruments?|music - instruments|guitars?/.test(c)) return 'musical_instruments'; if (/records?|vinyl|\blps?\b/.test(c)) return 'music'; if (/music memorabilia|entertainment memorabilia|movie memorabilia|movie posters?/.test(c)) return popCultureCategory(title); if (/cameras?|photography equipment/.test(c)) return 'cameras'; if (/clocks?/.test(c)) return 'clocks'; if (/books?|manuscripts?|ephemera/.test(c)) return /\bmap\b|atlas/i.test(title) ? 'maps' : /postcard/i.test(title) ? 'postcards' : 'books'; if (/maps?|atlases/.test(c)) return 'maps'; if (/postcards?/.test(c)) return 'postcards'; if (/glass(ware)?|crystal/.test(c)) return 'glass_crystal'; if (/porcelain|china|pottery|ceramics?|stoneware/.test(c)) return 'porcelain'; if (/silver|sterling/.test(c)) return 'silver'; if (/fine art|paintings?|prints?|sculptures?|^art\b|art - |artwork/.test(c)) return slugFromTitle(title, 'art') ?? 'art'; if (/fossils?|minerals?|meteorites?|natural history|rocks?/.test(c)) return /meteorite/i.test(title) ? 'meteorites' : /\b(fossil|ammonite|trilobite|tooth|skull|dinosaur)\b/i.test(title) ? 'fossils' : 'minerals'; if (/pens?|writing instruments?/.test(c)) return 'pens'; if (/lighters?/.test(c)) return 'lighters'; if (/perfume|fragrance/.test(c)) return 'perfume'; if (/pinball|arcade|slot machines?|coin-?op/.test(c)) return /slot machine/i.test(title) ? 'casino_memorabilia' : 'arcade_pinball'; if (/casino|gaming chips?/.test(c)) return 'casino_memorabilia'; if (/political/.test(c)) return 'political_memorabilia'; if (/disney/.test(c)) return 'disney_collectibles'; if (/star wars/.test(c)) return 'star_wars'; if (/board games?|puzzles?/.test(c)) return 'board_games'; if (/license plates?/.test(c)) return 'license_plates'; if (/pins?|badges?|buttons?/.test(c)) return 'pins'; if (/vintage computers?|apple/.test(c)) return /\bapple\b|macintosh/i.test(title) ? 'apple_collectibles' : 'vintage_computers'; if (/typewriters?/.test(c)) return 'typewriters'; if (/scientific instruments?/.test(c)) return 'scientific_instruments'; if (/antiques?|collectibles|decorative arts?|primitives|folk art|americana|asian antiques|oriental/.test(c)) { const sub = c.replace(/^antiques & collectibles(?: - collectibles)?/, ''); const vintageSignal = /\b(antique|vintage|victorian|edwardian|georgian|art deco|art nouveau|mid-?century|19th|18th|17th|c\.?\s?1[89]\d\d|1[89]\d\ds|primitive|folk art|cast iron)\b/i.test(title) || /antique|primitive|folk art|americana/.test(sub); if (HOUSEHOLD_SUB.test(sub) && !vintageSignal) return null; if (/\b(lighter|zippo)\b/i.test(title)) return 'lighters'; if (/\b(fountain pen|montblanc|parker 51)\b/i.test(title)) return 'pens'; if (/\b(mechanical bank|still bank|tin toy|wind-?up|pedal car|cap gun)\b/i.test(title)) return 'vintage_toys'; const bySignal = slugFromTitle(title, 'decorative'); if (bySignal && bySignal !== 'antiques') return bySignal; return vintageSignal || (bySignal === 'antiques' && !HOUSEHOLD_SUB.test(sub)) ? 'antiques' : null; } if (/automobilia|automotive memorabilia|petroliana|gas & oil/.test(c)) return 'automotive_memorabilia'; if (/wine|whisk(e)?y|spirits/.test(c)) return slugFromTitle(title, 'wine'); if (/sneakers?|streetwear|handbags?|luxury|designer/.test(c)) return slugFromTitle(title, 'fashion'); return null; }