TypeScript 61.9%
HTML 37.2%
SQL 0.7%
1import * as cheerio from 'cheerio';23/** Thin HTML helpers shared by connectors (cheerio). */4export function load(html: string) {5 return cheerio.load(html);6}78export type CheerioRoot = ReturnType<typeof cheerio.load>;910export function text($el: { text(): string } | null | undefined): string | null {11 const t = $el?.text()?.replace(/\s+/g, ' ').trim();12 return t ? t : null;13}1415export function absUrl(base: string, href: string | null | undefined): string | null {16 if (!href) return null;17 try {18 return new URL(href, base).toString();19 } catch {20 return null;21 }22}2324/** Extract JSON-LD blocks of a given @type (e.g. Product, Offer) from HTML. */25export function jsonLd(html: string, type?: string): Record<string, unknown>[] {26 const $ = cheerio.load(html);27 const out: Record<string, unknown>[] = [];28 $('script[type="application/ld+json"]').each((_, el) => {29 const raw = $(el).contents().text();30 try {31 const parsed = JSON.parse(raw) as unknown;32 const items = Array.isArray(parsed) ? parsed : (parsed && typeof parsed === 'object' && '@graph' in (parsed as object) ? ((parsed as { '@graph': unknown[] })['@graph'] ?? []) : [parsed]);33 for (const it of items) {34 if (it && typeof it === 'object') {35 const t = (it as { '@type'?: string | string[] })['@type'];36 const types = Array.isArray(t) ? t : t ? [t] : [];37 if (!type || types.includes(type)) out.push(it as Record<string, unknown>);38 }39 }40 } catch {41 /* ignore malformed JSON-LD */42 }43 });44 return out;45}4647/** Extract Next.js __NEXT_DATA__ payload when present. */48export function nextData(html: string): unknown | null {49 const m = html.match(/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/);50 if (!m) return null;51 try {52 return JSON.parse(m[1]!);53 } catch {54 return null;55 }56}5758/** Extract a JS object literal assigned to a global, e.g. window.__INITIAL_STATE__ = {...}; */59export function inlineJson(html: string, marker: string): unknown | null {60 const idx = html.indexOf(marker);61 if (idx < 0) return null;62 const start = html.indexOf('{', idx);63 if (start < 0) return null;64 let depth = 0;65 let inStr: string | null = null;66 for (let i = start; i < html.length; i++) {67 const ch = html[i]!;68 if (inStr) {69 if (ch === '\\') i++;70 else if (ch === inStr) inStr = null;71 continue;72 }73 if (ch === '"' || ch === "'") inStr = ch;74 else if (ch === '{') depth++;75 else if (ch === '}') {76 depth--;77 if (depth === 0) {78 try {79 return JSON.parse(html.slice(start, i + 1));80 } catch {81 return null;82 }83 }84 }85 }86 return null;87}88