SPB Git forge

spb/rareindex

Public
54commits 1branches 0releases
7.1 MBsize
maindefault branch
10 days agolast push
TypeScript 61.9% HTML 37.2% SQL 0.7%
2.7 KB · 41 lines typescript
Raw Blame History
1import { ShopifyStoreConnector, type ConnectorMeta, type RawRecordLike } from '@rareindex/connectors';2import type { NormalizedRecord } from '@rareindex/shared';34/**5 * Video Game Trader (videogametrader.com) — Shopify storefront read through the shared Shopify adapter6 * (collections → taxonomy mapping and title rules live in meta.json). This subclass only enriches the7 * condition block from the store's own vocabulary: titles end with " - <Platform> - Used (Complete)",8 * " - Used (Loose)", " - New" and products carry "Condition:…" tags.9 */10export function completenessFromTitle(title: string, tags: string[] = []): { completeness: string | null; conditionRaw: string | null } {11  const cond = tags.find((t) => /^Condition:/i.test(t))?.replace(/^Condition:/i, '').trim() ?? title.match(/-\s*((?:Used|New|NEW|Preowned|Pre-owned|Brand New|Sealed)[^-]*)$/)?.[1]?.trim() ?? null;12  const c = (cond ?? title).toLowerCase();13  let completeness: string | null = null;14  if (/\b(sealed|brand new|\bnew\b)/.test(c) && !/used/.test(c)) completeness = 'sealed';15  else if (/complete|cib|\(cib\)/.test(c)) completeness = 'cib';16  else if (/loose|cart(?:ridge)? only|disc only|game only/.test(c)) completeness = 'loose';17  else if (/box only|no game|manual only/.test(c)) completeness = 'box_only';18  return { completeness, conditionRaw: cond };19}2021export class VideoGameTraderConnector extends ShopifyStoreConnector {22  override async normalize(raw: RawRecordLike): Promise<NormalizedRecord[]> {23    const out = await super.normalize(raw);24    for (const r of out) {25      if (r.kind !== 'listing') continue;26      const tags = Array.isArray(r.attributes.metadata.tags) ? (r.attributes.metadata.tags as string[]) : [];27      const c = completenessFromTitle(r.rawTitle, tags);28      r.condition = { condition: r.condition.condition, conditionRaw: c.conditionRaw ?? r.condition.conditionRaw, completeness: c.completeness ?? r.condition.completeness };29      // platform tag → attributes.set when the title pattern did not catch it30      const platform = tags.find((t) => /^Platform:/i.test(t))?.replace(/^Platform:/i, '').trim();31      if (platform && !r.attributes.set) r.attributes.set = platform;32      if (platform) r.attributes.metadata.platform = platform;33      // strip the store's condition suffix from the asset name34      r.attributes.name = r.attributes.name.replace(/\s*-\s*(?:Used|New|NEW|Preowned|Pre-owned|Brand New|Sealed)\b.*$/i, '').replace(/\s*\*\s*NEW\s*$/i, '').replace(/\s*[|-]\s*[^|-]{2,40}$/, (m) => (platform && m.toLowerCase().includes(platform.toLowerCase().slice(0, 4)) ? '' : m)).trim() || r.attributes.name;35    }36    return out;37  }38}3940export default (meta: ConnectorMeta) => new VideoGameTraderConnector(meta);41