diff --git a/src/lib/shops.ts b/src/lib/shops.ts new file mode 100644 index 0000000..4ac2070 --- /dev/null +++ b/src/lib/shops.ts @@ -0,0 +1,17 @@ +export type Shop = 'amazon' | 'idealo' | 'geizhals' + +const PATTERNS: Array<{ shop: Shop; hostMatch: RegExp }> = [ + { shop: 'amazon', hostMatch: /(^|\.)amazon\.(de|com|co\.uk|fr|it|es|nl)$/i }, + { shop: 'idealo', hostMatch: /(^|\.)idealo\.(de|com|at|fr|it|es|co\.uk)$/i }, + { shop: 'geizhals', hostMatch: /(^|\.)geizhals\.(de|at|eu)$/i }, +] + +export function detectShop(input: string): Shop | null { + let host: string + try { + host = new URL(input).hostname + } catch { + return null + } + return PATTERNS.find((p) => p.hostMatch.test(host))?.shop ?? null +} diff --git a/tests/shops.test.ts b/tests/shops.test.ts new file mode 100644 index 0000000..c4aea17 --- /dev/null +++ b/tests/shops.test.ts @@ -0,0 +1,22 @@ +import { describe, it, expect } from 'vitest' +import { detectShop } from '@/lib/shops' + +describe('detectShop', () => { + it.each([ + ['https://www.amazon.de/dp/B0C5BMMJTL', 'amazon'], + ['https://amazon.com/gp/product/B0C5BMMJTL', 'amazon'], + ['https://www.idealo.de/preisvergleich/OffersOfProduct/123456_-foo.html', 'idealo'], + ['https://geizhals.de/sony-playstation-5-a2362829.html', 'geizhals'], + ['https://www.geizhals.eu/foo', 'geizhals'], + ])('detects %s as %s', (url, expected) => { + expect(detectShop(url)).toBe(expected) + }) + + it('returns null for unknown shop', () => { + expect(detectShop('https://example.com/foo')).toBeNull() + }) + + it('returns null for invalid url', () => { + expect(detectShop('not a url')).toBeNull() + }) +}) diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..c967e0c --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'vitest/config' +import path from 'node:path' + +export default defineConfig({ + test: { + environment: 'node', + include: ['tests/**/*.test.ts'], + }, + resolve: { alias: { '@': path.resolve(__dirname, './src') } }, +})