geo-checker 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +150 -14
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +150 -14
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +142 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +142 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/context.ts","../src/fetcher/static.ts","../src/fetcher/rendered.ts","../src/fetcher/robots.ts","../src/fetcher/llms-txt.ts","../src/fetcher/sitemap.ts","../src/types.ts","../src/engine.ts","../src/rules/crawler/https.ts","../src/rules/crawler/robots-reachable.ts","../src/rules/crawler/robots-ai-allow.ts","../src/rules/crawler/llms-txt-present.ts","../src/rules/crawler/llms-txt-wellformed.ts","../src/rules/crawler/llms-full-txt.ts","../src/rules/crawler/sitemap-present.ts","../src/rules/crawler/index.ts","../src/rules/structured-data/jsonld-present.ts","../src/rules/util.ts","../src/rules/structured-data/jsonld-valid-json.ts","../src/rules/structured-data/schema-type-recognized.ts","../src/rules/structured-data/required-fields.ts","../src/rules/structured-data/microdata-fallback.ts","../src/rules/structured-data/no-duplicate-types.ts","../src/rules/structured-data/sameas-entity.ts","../src/rules/structured-data/breadcrumb-valid.ts","../src/rules/structured-data/index.ts","../src/rules/citation/title.ts","../src/rules/citation/meta-description.ts","../src/rules/citation/canonical.ts","../src/rules/citation/og-tags.ts","../src/rules/citation/twitter-card.ts","../src/rules/citation/lang-attr.ts","../src/rules/citation/author-visible.ts","../src/rules/citation/dates.ts","../src/rules/citation/content-freshness.ts","../src/rules/citation/index.ts","../src/rules/content/single-h1.ts","../src/rules/content/heading-hierarchy.ts","../src/rules/content/image-alt.ts","../src/rules/content/tldr-or-faq.ts","../src/rules/content/word-count.ts","../src/rules/content/qa-structure.ts","../src/rules/content/external-citations.ts","../src/rules/content/index.ts","../src/rules/index.ts","../src/config.ts","../src/batch.ts","../src/reporters/csv.ts","../src/reporters/markdown.ts","../src/reporters/sarif.ts","../src/reporters/diff.ts","../src/index.ts","../src/reporters/json.ts","../src/reporters/cli.ts","../src/reporters/html.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, resolve as resolvePath } from 'node:path';\nimport { cac } from 'cac';\nimport kleur from 'kleur';\nimport { audit } from './index.js';\nimport { toJson } from './reporters/json.js';\nimport { toCli } from './reporters/cli.js';\nimport { toHtml } from './reporters/html.js';\nimport { toCsv } from './reporters/csv.js';\nimport { toMarkdown } from './reporters/markdown.js';\nimport { toSarif } from './reporters/sarif.js';\nimport { diffReports, formatDiffLine } from './reporters/diff.js';\nimport { findConfig } from './config.js';\nimport { runBatch, summaryToJson, urlToSlug, type BatchProgressEvent } from './batch.js';\nimport type { Category, Status, AuditReport } from './types.js';\n\nconst pkgVersion = '0.3.0';\n\nconst VALID_CATEGORIES: Category[] = ['crawler', 'structured-data', 'citation', 'content'];\n\ntype FailOn = 'fail' | 'warn';\n\ninterface CliFlags {\n json?: boolean;\n html?: string;\n out?: string;\n csv?: string;\n md?: string;\n sarif?: string;\n baseline?: string;\n config?: string;\n render?: boolean;\n category?: string;\n only?: string;\n failOn?: FailOn;\n timeout?: string | number;\n}\n\ninterface BatchFlags {\n out?: string;\n concurrency?: string | number;\n config?: string;\n render?: boolean;\n category?: string;\n only?: string;\n timeout?: string | number;\n}\n\nasync function writeReportFile(path: string, content: string): Promise<void> {\n const abs = resolvePath(path);\n await mkdir(dirname(abs), { recursive: true });\n await writeFile(abs, content, 'utf8');\n}\n\nfunction parseCategories(raw?: string): Category[] | undefined {\n if (!raw) return undefined;\n const items = raw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n const valid = items.filter((c): c is Category => (VALID_CATEGORIES as string[]).includes(c));\n const invalid = items.filter((c) => !(VALID_CATEGORIES as string[]).includes(c));\n if (invalid.length > 0) {\n throw new Error(`Unknown category: ${invalid.join(', ')}. Valid: ${VALID_CATEGORIES.join(', ')}.`);\n }\n return valid;\n}\n\nfunction parseOnly(raw?: string): string[] | undefined {\n if (!raw) return undefined;\n return raw.split(',').map((s) => s.trim()).filter(Boolean);\n}\n\nfunction worstStatus(report: AuditReport): Status {\n let worst: Status = 'pass';\n const order: Record<Status, number> = { pass: 0, skip: 0, warn: 1, fail: 2 };\n for (const cat of Object.values(report.categories)) {\n for (const r of cat.results) {\n if (order[r.status] > order[worst]) worst = r.status;\n }\n }\n return worst;\n}\n\nasync function resolveConfigPath(explicit: string | undefined): Promise<string | null> {\n if (explicit) return resolvePath(explicit);\n return findConfig(process.cwd());\n}\n\nasync function readBaseline(path: string): Promise<AuditReport> {\n const raw = await readFile(resolvePath(path), 'utf8');\n return JSON.parse(raw) as AuditReport;\n}\n\nfunction parseIntOr<T>(raw: string | number | undefined, fallback: T): number | T {\n if (raw === undefined) return fallback;\n const n = typeof raw === 'string' ? parseInt(raw, 10) : raw;\n return Number.isNaN(n) ? fallback : n;\n}\n\nconst cli = cac('geo-checker');\n\ncli\n .command('<url>', 'Audit a URL for GEO (Generative Engine Optimization) readiness')\n .option('--json', 'Output a JSON report to stdout')\n .option('--html <path>', 'Write a standalone HTML report to <path> (use - for stdout)')\n .option('--csv <path>', 'Write a flat CSV report (one row per rule result)')\n .option('--md <path>', 'Write a Markdown PR-comment summary')\n .option('--sarif <path>', 'Write a SARIF 2.1.0 report (for GitHub Code Scanning)')\n .option('--out <dir>', 'Write report.json + report.html to <dir>')\n .option('--baseline <path>', 'Compare against a prior JSON report and print deltas')\n .option('--config <path>', 'Load a geo-checker config file (overrides rule weights, disables rules, etc.)')\n .option('--render', 'Use a headless browser (requires optional playwright dependency)')\n .option('--category <names>', 'Run only the given categories (comma-separated)')\n .option('--only <ids>', 'Run only the given rule IDs (comma-separated)')\n .option('--fail-on <level>', 'Exit non-zero when a result is at or above this level (warn|fail)', {\n default: 'fail',\n })\n .option('--timeout <ms>', 'Per-request timeout in milliseconds', { default: 20000 })\n .action(async (url: string, flags: CliFlags) => {\n const categories = parseCategories(flags.category);\n const only = parseOnly(flags.only);\n const timeoutMs = parseIntOr(flags.timeout, undefined);\n const configPath = await resolveConfigPath(flags.config);\n\n const report = await audit(url, {\n ...(flags.render ? { render: true } : {}),\n ...(categories ? { categories } : {}),\n ...(only ? { only } : {}),\n ...(typeof timeoutMs === 'number' ? { timeoutMs } : {}),\n ...(configPath ? { configPath } : {}),\n });\n\n const wroteFile =\n Boolean(flags.out) ||\n (flags.html && flags.html !== '-') ||\n Boolean(flags.csv) ||\n Boolean(flags.md) ||\n Boolean(flags.sarif);\n\n if (flags.out) {\n const dir = flags.out;\n await writeReportFile(resolvePath(dir, 'report.json'), toJson(report));\n await writeReportFile(resolvePath(dir, 'report.html'), toHtml(report));\n process.stderr.write(kleur.gray(`wrote ${resolvePath(dir, 'report.json')}\\n`));\n process.stderr.write(kleur.gray(`wrote ${resolvePath(dir, 'report.html')}\\n`));\n }\n\n if (flags.html) {\n if (flags.html === '-') {\n process.stdout.write(toHtml(report));\n } else {\n await writeReportFile(flags.html, toHtml(report));\n process.stderr.write(kleur.gray(`wrote ${resolvePath(flags.html)}\\n`));\n }\n }\n\n if (flags.csv) {\n await writeReportFile(flags.csv, toCsv(report));\n process.stderr.write(kleur.gray(`wrote ${resolvePath(flags.csv)}\\n`));\n }\n\n if (flags.md) {\n await writeReportFile(flags.md, toMarkdown(report));\n process.stderr.write(kleur.gray(`wrote ${resolvePath(flags.md)}\\n`));\n }\n\n if (flags.sarif) {\n await writeReportFile(flags.sarif, toSarif(report));\n process.stderr.write(kleur.gray(`wrote ${resolvePath(flags.sarif)}\\n`));\n }\n\n if (flags.baseline) {\n try {\n const prior = await readBaseline(flags.baseline);\n const diff = diffReports(prior, report);\n process.stderr.write(kleur.bold('baseline ') + formatDiffLine(diff) + '\\n');\n } catch (err) {\n process.stderr.write(\n kleur.yellow(`! baseline comparison failed: ${err instanceof Error ? err.message : err}\\n`),\n );\n }\n }\n\n if (flags.json) {\n process.stdout.write(toJson(report) + '\\n');\n } else if (!wroteFile && flags.html !== '-') {\n process.stdout.write(toCli(report) + '\\n');\n }\n\n const worst = worstStatus(report);\n const failOn: FailOn = flags.failOn === 'warn' ? 'warn' : 'fail';\n if (failOn === 'fail' && worst === 'fail') process.exit(1);\n if (failOn === 'warn' && (worst === 'warn' || worst === 'fail')) process.exit(1);\n });\n\ncli\n .command('batch <file>', 'Audit every URL in <file> (one URL per line) and write individual reports')\n .option('--out <dir>', 'Output directory for per-URL reports and summary.json', { default: './geo-checker-batch' })\n .option('--concurrency <n>', 'Number of URLs to audit in parallel', { default: 4 })\n .option('--config <path>', 'Config file (see top-level --config)')\n .option('--render', 'Use a headless browser for each URL')\n .option('--category <names>', 'Run only the given categories (comma-separated)')\n .option('--only <ids>', 'Run only the given rule IDs (comma-separated)')\n .option('--timeout <ms>', 'Per-request timeout in milliseconds', { default: 20000 })\n .action(async (file: string, flags: BatchFlags) => {\n const raw = await readFile(resolvePath(file), 'utf8');\n const urls = raw\n .split(/\\r?\\n/)\n .map((l) => l.trim())\n .filter((l) => l && !l.startsWith('#'));\n if (urls.length === 0) {\n process.stderr.write(kleur.red('No URLs found in input file.\\n'));\n process.exit(1);\n }\n const outDir = resolvePath(flags.out ?? './geo-checker-batch');\n await mkdir(outDir, { recursive: true });\n\n const concurrency = parseIntOr(flags.concurrency, 4);\n const categories = parseCategories(flags.category);\n const only = parseOnly(flags.only);\n const timeoutMs = parseIntOr(flags.timeout, undefined);\n const configPath = await resolveConfigPath(flags.config);\n\n const onProgress = (e: BatchProgressEvent): void => {\n if (e.kind === 'start') {\n process.stderr.write(kleur.gray(`[${e.index + 1}/${e.total}] ${e.url}\\n`));\n } else if (e.kind === 'success') {\n process.stderr.write(kleur.green(` ✓ ${e.overall}/100\\n`));\n } else {\n process.stderr.write(kleur.red(` ✗ ${e.error}\\n`));\n }\n };\n\n const summary = await runBatch(urls, {\n concurrency: typeof concurrency === 'number' ? concurrency : 4,\n ...(flags.render ? { render: true } : {}),\n ...(categories ? { categories } : {}),\n ...(only ? { only } : {}),\n ...(typeof timeoutMs === 'number' ? { timeoutMs } : {}),\n ...(configPath ? { configPath } : {}),\n onProgress,\n });\n\n for (const r of summary.results) {\n if (!r.ok) continue;\n const slug = urlToSlug(r.url);\n await writeFile(resolvePath(outDir, `${slug}.json`), toJson(r.report), 'utf8');\n await writeFile(resolvePath(outDir, `${slug}.html`), toHtml(r.report), 'utf8');\n }\n await writeFile(resolvePath(outDir, 'summary.json'), summaryToJson(summary), 'utf8');\n process.stderr.write(\n kleur.bold(\n `\\nBatch done: ${summary.successes}/${summary.total} succeeded · avg ${summary.averageOverall} · written to ${outDir}\\n`,\n ),\n );\n if (summary.failures > 0) process.exit(1);\n });\n\ncli.help();\ncli.version(pkgVersion);\n\nasync function main() {\n cli.parse(process.argv, { run: false });\n await cli.runMatchedCommand();\n}\n\nmain().catch((err) => {\n console.error(kleur.red('geo-checker crashed:'), err instanceof Error ? err.message : err);\n process.exit(2);\n});\n","import { load as cheerioLoad, type CheerioAPI } from 'cheerio';\nimport type { AuditContext } from './types.js';\nimport { fetchStatic, fetchText } from './fetcher/static.js';\nimport { fetchRendered } from './fetcher/rendered.js';\nimport { parseRobots } from './fetcher/robots.js';\nimport { parseLlmsTxt } from './fetcher/llms-txt.js';\nimport { parseSitemap } from './fetcher/sitemap.js';\n\nexport interface BuildContextOptions {\n userAgent?: string;\n timeoutMs?: number;\n render?: boolean;\n}\n\nfunction extractJsonLd($: CheerioAPI): unknown[] {\n const blocks: unknown[] = [];\n $('script[type=\"application/ld+json\"]').each((_i, el) => {\n const txt = $(el).contents().text().trim();\n if (!txt) return;\n try {\n const parsed = JSON.parse(txt);\n if (Array.isArray(parsed)) blocks.push(...parsed);\n else blocks.push(parsed);\n } catch {\n blocks.push({ __parseError: true, raw: txt.slice(0, 200) });\n }\n });\n return blocks;\n}\n\nfunction detectSpa($: CheerioAPI): boolean {\n const bodyText = $('body').clone().find('script, style, noscript').remove().end().text().replace(/\\s+/g, ' ').trim();\n if (bodyText.length >= 500) return false;\n const roots = $('#__next, #root, #app, [data-reactroot], [ng-app], [data-server-rendered]');\n return roots.length > 0;\n}\n\nexport async function buildContext(url: string, opts: BuildContextOptions = {}): Promise<AuditContext> {\n const warnings: string[] = [];\n let finalUrl: string;\n let html: string;\n let headers: Record<string, string>;\n let status: number;\n let renderMode: 'static' | 'rendered';\n\n if (opts.render) {\n const page = await fetchRendered(url, opts);\n finalUrl = page.finalUrl;\n html = page.html;\n headers = page.headers;\n status = page.status;\n renderMode = 'rendered';\n } else {\n const page = await fetchStatic(url, opts);\n finalUrl = page.finalUrl;\n html = page.body;\n headers = page.headers;\n status = page.status;\n renderMode = 'static';\n }\n\n const $ = cheerioLoad(html);\n const origin = new URL(finalUrl).origin;\n\n if (renderMode === 'static' && detectSpa($)) {\n warnings.push(\n 'Site appears to be JS-rendered (sparse body + SPA root element). Re-run with --render for accurate results.',\n );\n }\n\n const [robotsRaw, llmsRaw, llmsFullRaw] = await Promise.all([\n fetchText(`${origin}/robots.txt`, opts),\n fetchText(`${origin}/llms.txt`, opts),\n fetchText(`${origin}/llms-full.txt`, opts),\n ]);\n\n let sitemapUrl: string | null = null;\n const robots = robotsRaw ? parseRobots(robotsRaw) : null;\n if (robots && robots.sitemaps.length > 0) sitemapUrl = robots.sitemaps[0] ?? null;\n if (!sitemapUrl) sitemapUrl = `${origin}/sitemap.xml`;\n\n const sitemapRaw = await fetchText(sitemapUrl, opts);\n const sitemap = sitemapRaw ? parseSitemap(sitemapRaw) : null;\n\n return {\n url,\n finalUrl,\n html,\n $,\n headers,\n status,\n robots,\n llmsTxt: llmsRaw ? parseLlmsTxt(llmsRaw) : null,\n llmsFullTxt: llmsFullRaw && llmsFullRaw.trim().length > 0 ? llmsFullRaw : null,\n sitemap,\n jsonLd: extractJsonLd($),\n renderMode,\n fetchedAt: new Date().toISOString(),\n warnings,\n };\n}\n\nexport const buildStaticContext = buildContext;\n","import { request } from 'undici';\n\nexport const DEFAULT_UA = 'geo-checker/0.1.0 (+https://github.com/BaRam-OSS/geo-checker)';\n\nexport interface StaticFetchOptions {\n userAgent?: string;\n timeoutMs?: number;\n maxRedirects?: number;\n accept?: string;\n}\n\nexport interface StaticFetchResult {\n finalUrl: string;\n status: number;\n headers: Record<string, string>;\n body: string;\n redirectCount: number;\n}\n\nfunction normalizeHeaders(input: Record<string, string | string[] | undefined>): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(input)) {\n if (v == null) continue;\n out[k.toLowerCase()] = Array.isArray(v) ? v.join(', ') : v;\n }\n return out;\n}\n\nexport async function fetchStatic(url: string, opts: StaticFetchOptions = {}): Promise<StaticFetchResult> {\n const maxRedirects = opts.maxRedirects ?? 5;\n const timeout = opts.timeoutMs ?? 20_000;\n const userAgent = opts.userAgent ?? DEFAULT_UA;\n const accept = opts.accept ?? 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8';\n\n let current = url;\n let redirects = 0;\n\n for (;;) {\n const res = await request(current, {\n method: 'GET',\n headers: {\n 'user-agent': userAgent,\n accept,\n 'accept-language': 'en,*',\n },\n bodyTimeout: timeout,\n headersTimeout: timeout,\n });\n\n const status = res.statusCode;\n const headers = normalizeHeaders(res.headers as Record<string, string | string[] | undefined>);\n\n if (status >= 300 && status < 400 && headers.location && redirects < maxRedirects) {\n redirects += 1;\n current = new URL(headers.location, current).toString();\n await res.body.dump();\n continue;\n }\n\n const body = await res.body.text();\n return { finalUrl: current, status, headers, body, redirectCount: redirects };\n }\n}\n\nexport async function fetchText(url: string, opts: StaticFetchOptions = {}): Promise<string | null> {\n try {\n const res = await fetchStatic(url, opts);\n if (res.status >= 200 && res.status < 300) return res.body;\n return null;\n } catch {\n return null;\n }\n}\n","import type * as PlaywrightNs from 'playwright';\nimport { DEFAULT_UA } from './static.js';\n\nexport interface RenderedResult {\n finalUrl: string;\n html: string;\n status: number;\n headers: Record<string, string>;\n}\n\nexport interface RenderedOptions {\n userAgent?: string;\n timeoutMs?: number;\n}\n\nexport async function fetchRendered(url: string, opts: RenderedOptions = {}): Promise<RenderedResult> {\n let playwright: typeof PlaywrightNs;\n try {\n playwright = (await import('playwright')) as typeof PlaywrightNs;\n } catch {\n throw new Error(\n 'Playwright is required for --render. Install with: npm i -D playwright && npx playwright install chromium',\n );\n }\n\n const userAgent = opts.userAgent ?? DEFAULT_UA;\n const timeout = opts.timeoutMs ?? 30_000;\n\n const browser = await playwright.chromium.launch({ headless: true });\n try {\n const ctx = await browser.newContext({ userAgent });\n const page = await ctx.newPage();\n const response = await page.goto(url, { waitUntil: 'networkidle', timeout });\n const html = await page.content();\n const finalUrl = page.url();\n const status = response?.status() ?? 200;\n const headers = response ? await response.allHeaders() : {};\n return { finalUrl, html, status, headers };\n } finally {\n await browser.close();\n }\n}\n","import type { RobotsTxt, RobotsRuleGroup } from '../types.js';\n\nexport function parseRobots(raw: string): RobotsTxt {\n const groups: RobotsRuleGroup[] = [];\n const sitemaps: string[] = [];\n let current: RobotsRuleGroup | null = null;\n\n const lines = raw.split(/\\r?\\n/);\n for (const rawLine of lines) {\n const line = rawLine.replace(/#.*$/, '').trim();\n if (!line) continue;\n const idx = line.indexOf(':');\n if (idx === -1) continue;\n const field = line.slice(0, idx).trim().toLowerCase();\n const value = line.slice(idx + 1).trim();\n\n if (field === 'user-agent') {\n if (!current || current.allow.length > 0 || current.disallow.length > 0) {\n current = { userAgent: value, allow: [], disallow: [] };\n groups.push(current);\n } else {\n current.userAgent = value;\n }\n } else if (field === 'allow' && current) {\n current.allow.push(value);\n } else if (field === 'disallow' && current) {\n current.disallow.push(value);\n } else if (field === 'sitemap') {\n sitemaps.push(value);\n }\n }\n\n return { raw, groups, sitemaps };\n}\n\nexport function matchGroup(robots: RobotsTxt, userAgent: string): RobotsRuleGroup | null {\n const lower = userAgent.toLowerCase();\n const exact = robots.groups.find((g) => g.userAgent.toLowerCase() === lower);\n if (exact) return exact;\n const wildcard = robots.groups.find((g) => g.userAgent === '*');\n return wildcard ?? null;\n}\n\nexport function isPathAllowed(group: RobotsRuleGroup | null, path: string): boolean {\n if (!group) return true;\n const matches = (pattern: string): number => {\n if (pattern === '') return -1;\n if (path.startsWith(pattern)) return pattern.length;\n return -1;\n };\n let bestAllow = -1;\n let bestDisallow = -1;\n for (const p of group.allow) bestAllow = Math.max(bestAllow, matches(p));\n for (const p of group.disallow) bestDisallow = Math.max(bestDisallow, matches(p));\n if (bestDisallow === -1) return true;\n return bestAllow >= bestDisallow;\n}\n","import type { LlmsTxt, LlmsTxtLink, LlmsTxtSection } from '../types.js';\n\nconst LINK_RE = /^\\s*-\\s*\\[([^\\]]+)\\]\\(([^)]+)\\)\\s*(?::\\s*(.+))?\\s*$/;\n\nexport function parseLlmsTxt(raw: string): LlmsTxt {\n const lines = raw.split(/\\r?\\n/);\n\n let title: string | null = null;\n let summary: string | null = null;\n const sections: LlmsTxtSection[] = [];\n let currentSection: LlmsTxtSection | null = null;\n const summaryParts: string[] = [];\n let inSummaryPhase = false;\n\n for (const line of lines) {\n if (/^#\\s+/.test(line) && title === null) {\n title = line.replace(/^#\\s+/, '').trim();\n inSummaryPhase = true;\n continue;\n }\n if (/^##\\s+/.test(line)) {\n if (inSummaryPhase && summaryParts.length > 0) {\n summary = summaryParts.join(' ').trim();\n }\n inSummaryPhase = false;\n currentSection = { title: line.replace(/^##\\s+/, '').trim(), links: [] };\n sections.push(currentSection);\n continue;\n }\n\n if (inSummaryPhase) {\n const trimmed = line.trim();\n if (trimmed.startsWith('>')) {\n summaryParts.push(trimmed.replace(/^>\\s*/, ''));\n } else if (trimmed.length > 0) {\n summaryParts.push(trimmed);\n }\n continue;\n }\n\n if (currentSection) {\n const m = LINK_RE.exec(line);\n if (m) {\n const link: LlmsTxtLink = { title: m[1]!.trim(), url: m[2]!.trim() };\n if (m[3]) link.description = m[3].trim();\n currentSection.links.push(link);\n }\n }\n }\n\n if (inSummaryPhase && summary === null && summaryParts.length > 0) {\n summary = summaryParts.join(' ').trim();\n }\n\n return { raw, title, summary, sections };\n}\n\nexport function isLlmsTxtWellFormed(parsed: LlmsTxt): { ok: boolean; reason?: string } {\n if (!parsed.title) return { ok: false, reason: 'Missing H1 project title' };\n if (parsed.sections.length === 0) return { ok: false, reason: 'No H2 sections found' };\n const totalLinks = parsed.sections.reduce((n, s) => n + s.links.length, 0);\n if (totalLinks === 0) return { ok: false, reason: 'No link items found under any section' };\n return { ok: true };\n}\n","import type { SitemapSummary } from '../types.js';\n\nconst LOC_RE = /<loc>\\s*([^<\\s]+)\\s*<\\/loc>/gi;\nconst LASTMOD_RE = /<lastmod>\\s*([^<\\s]+)\\s*<\\/lastmod>/i;\n\nexport function parseSitemap(xml: string): SitemapSummary {\n const urls: string[] = [];\n let match: RegExpExecArray | null;\n const re = new RegExp(LOC_RE.source, LOC_RE.flags);\n while ((match = re.exec(xml)) !== null) {\n const url = match[1];\n if (url) urls.push(url);\n }\n const lastmodMatch = LASTMOD_RE.exec(xml);\n const summary: SitemapSummary = { urls };\n if (lastmodMatch?.[1]) summary.lastmod = lastmodMatch[1];\n return summary;\n}\n","import type { CheerioAPI } from 'cheerio';\n\nexport type Status = 'pass' | 'warn' | 'fail' | 'skip';\n\nexport type Category = 'crawler' | 'structured-data' | 'citation' | 'content';\n\nexport interface RobotsRuleGroup {\n userAgent: string;\n allow: string[];\n disallow: string[];\n}\n\nexport interface RobotsTxt {\n raw: string;\n groups: RobotsRuleGroup[];\n sitemaps: string[];\n}\n\nexport interface LlmsTxtLink {\n title: string;\n url: string;\n description?: string;\n}\n\nexport interface LlmsTxtSection {\n title: string;\n links: LlmsTxtLink[];\n}\n\nexport interface LlmsTxt {\n raw: string;\n title: string | null;\n summary: string | null;\n sections: LlmsTxtSection[];\n}\n\nexport interface SitemapSummary {\n urls: string[];\n lastmod?: string;\n}\n\nexport interface AuditContext {\n url: string;\n finalUrl: string;\n html: string;\n $: CheerioAPI;\n headers: Record<string, string>;\n status: number;\n robots: RobotsTxt | null;\n llmsTxt: LlmsTxt | null;\n llmsFullTxt: string | null;\n sitemap: SitemapSummary | null;\n jsonLd: unknown[];\n renderMode: 'static' | 'rendered';\n fetchedAt: string;\n warnings: string[];\n}\n\nexport type Impact = 'critical' | 'high' | 'medium' | 'low';\nexport type Effort = 'low' | 'medium' | 'high';\nexport type RuleGroup = 'opportunity' | 'diagnostic' | 'info';\n\nexport interface EvidenceLocation {\n selector?: string;\n snippet?: string;\n line?: number;\n col?: number;\n}\n\nexport interface RuleResult {\n status: Status;\n score: number;\n rationale: string;\n rationale_ko?: string;\n evidence?: unknown;\n locations?: EvidenceLocation[];\n fixUrl?: string;\n fixHint?: string;\n estimatedImpact?: number;\n}\n\nexport interface Rule {\n id: string;\n stableId?: string;\n category: Category;\n group?: RuleGroup;\n weight: number;\n impact?: Impact;\n effort?: Effort;\n title: string;\n title_ko?: string;\n description: string;\n docsUrl?: string;\n run(ctx: AuditContext): Promise<RuleResult> | RuleResult;\n}\n\nexport interface RuleResultEntry extends RuleResult {\n id: string;\n stableId?: string;\n title: string;\n title_ko?: string;\n weight: number;\n group?: RuleGroup;\n impact?: Impact;\n effort?: Effort;\n docsUrl?: string;\n durationMs?: number;\n}\n\nexport interface CategoryReport {\n score: number;\n weight: number;\n results: RuleResultEntry[];\n}\n\nexport interface ReportMeta {\n toolVersion: string;\n nodeVersion: string;\n userAgent?: string;\n configPath?: string;\n}\n\nexport interface ReportTiming {\n fetchMs: number;\n auditMs: number;\n totalMs: number;\n}\n\nexport interface AuditReport {\n schemaVersion: 1;\n url: string;\n finalUrl: string;\n fetchedAt: string;\n renderMode: 'static' | 'rendered';\n overall: number;\n categories: Record<Category, CategoryReport>;\n warnings: string[];\n version: string;\n meta: ReportMeta;\n timing: ReportTiming;\n}\n\nexport interface RuleOverride {\n enabled?: boolean;\n weight?: number;\n}\n\nexport interface GeoConfig {\n extends?: 'default';\n rules?: Record<string, RuleOverride>;\n categories?: Partial<Record<Category, { weight?: number }>>;\n extraRules?: Rule[];\n}\n\nexport interface AuditOptions {\n render?: boolean;\n timeoutMs?: number;\n userAgent?: string;\n extraRules?: Rule[];\n only?: string[];\n categories?: Category[];\n config?: GeoConfig;\n configPath?: string;\n}\n\nexport function defineRule(rule: Rule): Rule {\n return rule;\n}\n\nexport const CATEGORY_WEIGHTS: Record<Category, number> = {\n crawler: 25,\n 'structured-data': 30,\n citation: 25,\n content: 20,\n};\n","import type {\n AuditContext,\n AuditReport,\n Category,\n CategoryReport,\n ReportMeta,\n ReportTiming,\n Rule,\n RuleResultEntry,\n} from './types.js';\nimport { CATEGORY_WEIGHTS } from './types.js';\n\nconst VERSION = '0.3.0';\n\nexport interface RunRulesOptions {\n only?: string[];\n categories?: Category[];\n meta?: Partial<ReportMeta>;\n fetchMs?: number;\n startedAt?: number;\n categoryWeights?: Record<Category, number>;\n}\n\nexport async function runRules(\n ctx: AuditContext,\n rules: Rule[],\n opts: RunRulesOptions = {},\n): Promise<AuditReport> {\n const auditStart = performance.now();\n const onlySet = opts.only ? new Set(opts.only) : null;\n const catSet = opts.categories ? new Set<Category>(opts.categories) : null;\n const weights = opts.categoryWeights ?? CATEGORY_WEIGHTS;\n\n const buckets: Record<Category, CategoryReport> = {\n crawler: { score: 0, weight: weights.crawler, results: [] },\n 'structured-data': { score: 0, weight: weights['structured-data'], results: [] },\n citation: { score: 0, weight: weights.citation, results: [] },\n content: { score: 0, weight: weights.content, results: [] },\n };\n\n for (const rule of rules) {\n if (onlySet && !onlySet.has(rule.id) && (!rule.stableId || !onlySet.has(rule.stableId))) continue;\n if (catSet && !catSet.has(rule.category)) continue;\n\n const ruleStart = performance.now();\n let result;\n try {\n result = await rule.run(ctx);\n } catch (err) {\n result = {\n status: 'skip' as const,\n score: 0,\n rationale: `Rule crashed: ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n const durationMs = Math.round(performance.now() - ruleStart);\n\n const entry: RuleResultEntry = {\n id: rule.id,\n title: rule.title,\n weight: rule.weight,\n ...result,\n durationMs,\n };\n if (rule.stableId !== undefined) entry.stableId = rule.stableId;\n if (rule.title_ko !== undefined) entry.title_ko = rule.title_ko;\n if (rule.group !== undefined) entry.group = rule.group;\n if (rule.impact !== undefined) entry.impact = rule.impact;\n if (rule.effort !== undefined) entry.effort = rule.effort;\n if (rule.docsUrl !== undefined) entry.docsUrl = rule.docsUrl;\n\n buckets[rule.category].results.push(entry);\n }\n\n for (const cat of Object.keys(buckets) as Category[]) {\n const b = buckets[cat];\n let weighted = 0;\n let totalWeight = 0;\n for (const r of b.results) {\n if (r.status === 'skip') continue;\n weighted += r.score * r.weight;\n totalWeight += r.weight;\n }\n b.score = totalWeight === 0 ? 0 : Math.round((weighted / totalWeight) * 100);\n }\n\n let overallWeighted = 0;\n let overallWeight = 0;\n for (const cat of Object.keys(buckets) as Category[]) {\n const b = buckets[cat];\n if (b.results.length === 0) continue;\n overallWeighted += b.score * b.weight;\n overallWeight += b.weight;\n }\n const overall = overallWeight === 0 ? 0 : Math.round(overallWeighted / overallWeight);\n\n const auditMs = Math.round(performance.now() - auditStart);\n const fetchMs = Math.max(0, Math.round(opts.fetchMs ?? 0));\n const totalMs =\n opts.startedAt !== undefined ? Math.round(performance.now() - opts.startedAt) : fetchMs + auditMs;\n\n const meta: ReportMeta = {\n toolVersion: VERSION,\n nodeVersion: process.versions.node,\n };\n if (opts.meta?.userAgent !== undefined) meta.userAgent = opts.meta.userAgent;\n if (opts.meta?.configPath !== undefined) meta.configPath = opts.meta.configPath;\n\n const timing: ReportTiming = { fetchMs, auditMs, totalMs };\n\n return {\n schemaVersion: 1,\n url: ctx.url,\n finalUrl: ctx.finalUrl,\n fetchedAt: ctx.fetchedAt,\n renderMode: ctx.renderMode,\n overall,\n categories: buckets,\n warnings: [...ctx.warnings],\n version: VERSION,\n meta,\n timing,\n };\n}\n","import { defineRule } from '../../types.js';\n\nexport const httpsRule = defineRule({\n id: 'crawler.https',\n stableId: 'crawler.https',\n category: 'crawler',\n group: 'diagnostic',\n weight: 2,\n impact: 'critical',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#crawlerhttps',\n title: 'Site is served over HTTPS',\n title_ko: '사이트가 HTTPS로 제공됨',\n description: 'AI crawlers treat HTTPS pages as more trustworthy and some skip plain HTTP entirely.',\n run(ctx) {\n const isHttps = ctx.finalUrl.startsWith('https://');\n return isHttps\n ? { status: 'pass', score: 1, rationale: 'Final URL uses HTTPS.', rationale_ko: '최종 URL이 HTTPS를 사용합니다.' }\n : {\n status: 'fail',\n score: 0,\n rationale: 'Final URL does not use HTTPS. Redirect HTTP → HTTPS site-wide.',\n rationale_ko: '최종 URL이 HTTPS를 사용하지 않습니다. 사이트 전체를 HTTP → HTTPS로 리다이렉트하세요.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const robotsReachableRule = defineRule({\n id: 'crawler.robots-reachable',\n stableId: 'crawler.robots-reachable',\n category: 'crawler',\n group: 'diagnostic',\n weight: 2,\n impact: 'low',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#crawlerrobots-reachable',\n title: 'robots.txt is reachable',\n title_ko: 'robots.txt 접근 가능 여부',\n description: 'A reachable robots.txt lets crawlers confirm their permissions; missing file is treated as allow-all but blocks explicit signalling.',\n run(ctx) {\n if (ctx.robots) {\n return { status: 'pass', score: 1, rationale: 'robots.txt returned successfully.', rationale_ko: 'robots.txt가 정상적으로 응답합니다.' };\n }\n return {\n status: 'warn',\n score: 0.3,\n rationale: 'robots.txt is missing. Add one even if empty to explicitly signal crawl policy.',\n rationale_ko: 'robots.txt가 없습니다. 크롤 정책을 명시적으로 알리려면 비어 있더라도 추가하세요.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { isPathAllowed, matchGroup } from '../../fetcher/robots.js';\n\nconst AI_BOTS = [\n // Tier 1: OpenAI\n 'GPTBot',\n 'OAI-SearchBot',\n 'ChatGPT-User',\n // Tier 1: Google / Gemini\n 'Google-Extended',\n 'Google-CloudVertexBot',\n // Tier 1: Anthropic\n 'ClaudeBot',\n 'anthropic-ai',\n 'Claude-Web',\n // Tier 1: Perplexity\n 'PerplexityBot',\n // Tier 1: Apple\n 'Applebot-Extended',\n // Tier 1: Meta\n 'Meta-ExternalAgent',\n // Tier 1: ByteDance\n 'Bytespider',\n // Tier 1: DuckDuckGo\n 'DuckAssistBot',\n // Tier 1: You.com\n 'YouBot',\n // Tier 1: Cohere\n 'cohere-ai',\n // Tier 2: Common Crawl (feeds many LLM training sets)\n 'CCBot',\n // Tier 2: Amazon\n 'Amazonbot',\n];\n\nexport const robotsAiAllowRule = defineRule({\n id: 'crawler.robots-ai-allow',\n stableId: 'crawler.robots-ai-allow',\n category: 'crawler',\n group: 'diagnostic',\n weight: 5,\n impact: 'critical',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#crawlerrobots-ai-allow',\n title: 'AI crawlers are allowed',\n title_ko: 'AI 크롤러 접근 허용 여부',\n description:\n 'Major AI search and training crawlers (17 bots incl. GPTBot, OAI-SearchBot, Google-Extended, ClaudeBot, PerplexityBot, Applebot-Extended, Meta-ExternalAgent, Bytespider, DuckAssistBot, YouBot) must be allowed to index the homepage.',\n run(ctx) {\n if (!ctx.robots) {\n return {\n status: 'warn',\n score: 0.5,\n rationale: 'robots.txt missing; AI crawlers default to allow, but explicit allow is recommended.',\n rationale_ko: 'robots.txt가 없습니다. AI 크롤러는 기본적으로 허용되지만, 명시적 허용을 권장합니다.',\n };\n }\n\n const path = new URL(ctx.finalUrl).pathname || '/';\n const blocked: string[] = [];\n const mentioned: string[] = [];\n\n for (const bot of AI_BOTS) {\n const group = matchGroup(ctx.robots, bot);\n if (group && group.userAgent.toLowerCase() === bot.toLowerCase()) {\n mentioned.push(bot);\n }\n if (!isPathAllowed(group, path)) blocked.push(bot);\n }\n\n if (blocked.length > 0) {\n return {\n status: 'fail',\n score: Math.max(0, 1 - blocked.length / AI_BOTS.length),\n rationale: `Blocked: ${blocked.join(', ')}. Remove the Disallow or add an explicit Allow for these user-agents.`,\n rationale_ko: `차단됨: ${blocked.join(', ')}. 해당 User-agent의 Disallow를 제거하거나 명시적 Allow를 추가하세요.`,\n evidence: { blocked, mentioned, totalBots: AI_BOTS.length },\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n }\n if (mentioned.length === 0) {\n return {\n status: 'warn',\n score: 0.6,\n rationale: `All ${AI_BOTS.length} AI crawlers reach the page via default rules, but none are explicitly listed. Consider explicit Allow entries.`,\n rationale_ko: `${AI_BOTS.length}개 AI 크롤러 모두 기본 규칙으로 접근 가능하지만, 명시적으로 허용된 봇이 없습니다. 명시적 Allow 항목 추가를 권장합니다.`,\n };\n }\n return {\n status: 'pass',\n score: 1,\n rationale: `All ${AI_BOTS.length} AI crawlers can reach the page; ${mentioned.length} explicitly listed.`,\n rationale_ko: `${AI_BOTS.length}개 AI 크롤러 모두 접근 가능하며, ${mentioned.length}개가 명시적으로 허용되어 있습니다.`,\n evidence: { mentioned, totalBots: AI_BOTS.length },\n };\n },\n});\n\nexport const AI_BOTS_TRACKED = AI_BOTS;\n","import { defineRule } from '../../types.js';\n\nexport const llmsTxtPresentRule = defineRule({\n id: 'crawler.llms-txt-present',\n stableId: 'crawler.llms-txt-present',\n category: 'crawler',\n group: 'opportunity',\n weight: 4,\n impact: 'medium',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#crawlerllms-txt-present',\n title: 'llms.txt is present',\n title_ko: 'llms.txt 파일 존재 여부',\n description: 'An /llms.txt file at the site root gives AI assistants a curated map of the most citation-worthy pages.',\n run(ctx) {\n if (ctx.llmsTxt) {\n return { status: 'pass', score: 1, rationale: 'llms.txt found at site root.', rationale_ko: 'llms.txt가 사이트 루트에 존재합니다.' };\n }\n return {\n status: 'warn',\n score: 0,\n rationale: 'No /llms.txt found. Add one to curate the pages AI assistants should read.',\n rationale_ko: '/llms.txt가 없습니다. AI 어시스턴트가 읽어야 할 페이지를 큐레이션하려면 추가하세요.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { isLlmsTxtWellFormed } from '../../fetcher/llms-txt.js';\n\nexport const llmsTxtWellformedRule = defineRule({\n id: 'crawler.llms-txt-wellformed',\n stableId: 'crawler.llms-txt-wellformed',\n category: 'crawler',\n group: 'opportunity',\n weight: 3,\n impact: 'medium',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#crawlerllms-txt-wellformed',\n title: 'llms.txt follows the spec',\n title_ko: 'llms.txt 스펙 준수 여부',\n description: 'Must start with an H1 project title, then a brief summary, then at least one H2 section containing link items.',\n run(ctx) {\n if (!ctx.llmsTxt) {\n return { status: 'skip', score: 0, rationale: 'No llms.txt to validate.', rationale_ko: '검증할 llms.txt가 없습니다.' };\n }\n const check = isLlmsTxtWellFormed(ctx.llmsTxt);\n if (check.ok) {\n const totalLinks = ctx.llmsTxt.sections.reduce((n, s) => n + s.links.length, 0);\n return {\n status: 'pass',\n score: 1,\n rationale: `Well-formed with ${ctx.llmsTxt.sections.length} section(s) and ${totalLinks} link(s).`,\n rationale_ko: `스펙에 맞게 작성됨 (섹션 ${ctx.llmsTxt.sections.length}개, 링크 ${totalLinks}개).`,\n };\n }\n return {\n status: 'warn',\n score: 0.3,\n rationale: `llms.txt does not fully match the spec: ${check.reason}.`,\n rationale_ko: `llms.txt가 스펙을 완전히 따르지 않습니다: ${check.reason}.`,\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const llmsFullTxtRule = defineRule({\n id: 'crawler.llms-full-txt',\n stableId: 'crawler.llms-full-txt',\n category: 'crawler',\n group: 'opportunity',\n weight: 2,\n impact: 'medium',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#crawlerllms-full-txt',\n title: 'llms-full.txt provides full-content mirror',\n title_ko: 'llms-full.txt 전체 콘텐츠 미러 제공 여부',\n description:\n 'Complement /llms.txt with /llms-full.txt containing the full body of every cited page. AI assistants can ingest it in one request instead of crawling every URL.',\n run(ctx) {\n if (ctx.llmsFullTxt && ctx.llmsFullTxt.length > 200) {\n return {\n status: 'pass',\n score: 1,\n rationale: `/llms-full.txt found (${ctx.llmsFullTxt.length.toLocaleString()} chars).`,\n rationale_ko: `/llms-full.txt가 존재합니다 (${ctx.llmsFullTxt.length.toLocaleString()}자).`,\n };\n }\n if (ctx.llmsFullTxt) {\n return {\n status: 'warn',\n score: 0.5,\n rationale: `/llms-full.txt found but very short (${ctx.llmsFullTxt.length} chars). Consider expanding with page bodies.`,\n rationale_ko: `/llms-full.txt가 있지만 너무 짧습니다 (${ctx.llmsFullTxt.length}자). 페이지 본문으로 내용을 보강하세요.`,\n fixHint: 'Mirror full article bodies into /llms-full.txt so AI assistants can quote without re-crawling.',\n };\n }\n return {\n status: 'warn',\n score: 0,\n rationale:\n 'No /llms-full.txt found. Adding one lets AI assistants ingest the full corpus in a single request.',\n rationale_ko:\n '/llms-full.txt가 없습니다. 추가하면 AI 어시스턴트가 전체 콘텐츠를 한 번의 요청으로 수집할 수 있습니다.',\n fixHint: 'Publish /llms-full.txt alongside /llms.txt with the full body text of your top pages.',\n estimatedImpact: 1,\n };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const sitemapPresentRule = defineRule({\n id: 'crawler.sitemap-present',\n stableId: 'crawler.sitemap-present',\n category: 'crawler',\n group: 'diagnostic',\n weight: 4,\n impact: 'high',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#crawlersitemap-present',\n title: 'sitemap.xml is present',\n title_ko: 'sitemap.xml 존재 여부',\n description: 'A sitemap helps AI crawlers discover and prioritise pages; many crawlers short-circuit discovery without one.',\n run(ctx) {\n if (ctx.sitemap && ctx.sitemap.urls.length > 0) {\n return {\n status: 'pass',\n score: 1,\n rationale: `Sitemap found with ${ctx.sitemap.urls.length} URL(s).`,\n rationale_ko: `사이트맵에 URL이 ${ctx.sitemap.urls.length}개 있습니다.`,\n };\n }\n return {\n status: 'warn',\n score: 0.2,\n rationale: 'No sitemap.xml found (checked /sitemap.xml and Sitemap: directive in robots.txt).',\n rationale_ko: 'sitemap.xml이 없습니다 (/sitemap.xml 및 robots.txt의 Sitemap: 지시어를 확인했습니다).',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { httpsRule } from './https.js';\nimport { robotsReachableRule } from './robots-reachable.js';\nimport { robotsAiAllowRule } from './robots-ai-allow.js';\nimport { llmsTxtPresentRule } from './llms-txt-present.js';\nimport { llmsTxtWellformedRule } from './llms-txt-wellformed.js';\nimport { llmsFullTxtRule } from './llms-full-txt.js';\nimport { sitemapPresentRule } from './sitemap-present.js';\n\nexport const crawlerRules = [\n httpsRule,\n robotsReachableRule,\n robotsAiAllowRule,\n llmsTxtPresentRule,\n llmsTxtWellformedRule,\n llmsFullTxtRule,\n sitemapPresentRule,\n];\n","import { defineRule } from '../../types.js';\n\nexport const jsonLdPresentRule = defineRule({\n id: 'sd.jsonld-present',\n stableId: 'sd.jsonld-present',\n category: 'structured-data',\n group: 'diagnostic',\n weight: 5,\n impact: 'critical',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#sdjsonld-present',\n title: 'JSON-LD structured data is present',\n title_ko: 'JSON-LD 구조화 데이터 존재 여부',\n description: 'At least one <script type=\"application/ld+json\"> block is the primary way AI engines map your page to an entity.',\n run(ctx) {\n if (ctx.jsonLd.length > 0) {\n return { status: 'pass', score: 1, rationale: `Found ${ctx.jsonLd.length} JSON-LD block(s).`, rationale_ko: `JSON-LD 블록이 ${ctx.jsonLd.length}개 있습니다.` };\n }\n return {\n status: 'fail',\n score: 0,\n rationale: 'No JSON-LD blocks found. Add schema.org structured data.',\n rationale_ko: 'JSON-LD 블록이 없습니다. schema.org 구조화 데이터를 추가하세요.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","export const KNOWN_SCHEMA_TYPES = [\n 'Article',\n 'NewsArticle',\n 'BlogPosting',\n 'FAQPage',\n 'HowTo',\n 'Organization',\n 'Person',\n 'BreadcrumbList',\n 'Product',\n 'WebSite',\n 'WebPage',\n];\n\nexport const REQUIRED_FIELDS: Record<string, string[]> = {\n Article: ['headline', 'author', 'datePublished'],\n NewsArticle: ['headline', 'author', 'datePublished'],\n BlogPosting: ['headline', 'author', 'datePublished'],\n FAQPage: ['mainEntity'],\n HowTo: ['name', 'step'],\n Product: ['name', 'offers'],\n Organization: ['name'],\n Person: ['name'],\n BreadcrumbList: ['itemListElement'],\n};\n\nexport function getTypes(node: unknown): string[] {\n if (!node || typeof node !== 'object') return [];\n const t = (node as { '@type'?: unknown })['@type'];\n if (typeof t === 'string') return [t];\n if (Array.isArray(t)) return t.filter((x): x is string => typeof x === 'string');\n return [];\n}\n\nexport function flattenJsonLd(blocks: unknown[]): unknown[] {\n const out: unknown[] = [];\n const visit = (node: unknown) => {\n if (!node || typeof node !== 'object') return;\n if (Array.isArray(node)) {\n for (const item of node) visit(item);\n return;\n }\n out.push(node);\n const graph = (node as { '@graph'?: unknown })['@graph'];\n if (Array.isArray(graph)) for (const item of graph) visit(item);\n };\n for (const b of blocks) visit(b);\n return out;\n}\n\nexport function hasParseError(blocks: unknown[]): boolean {\n return blocks.some((b) => b && typeof b === 'object' && (b as { __parseError?: boolean }).__parseError);\n}\n\nexport function hasField(node: unknown, field: string): boolean {\n if (!node || typeof node !== 'object') return false;\n const v = (node as Record<string, unknown>)[field];\n if (v == null) return false;\n if (typeof v === 'string') return v.trim().length > 0;\n if (Array.isArray(v)) return v.length > 0;\n return true;\n}\n","import { defineRule } from '../../types.js';\nimport { hasParseError } from '../util.js';\n\nexport const jsonLdValidJsonRule = defineRule({\n id: 'sd.jsonld-valid-json',\n stableId: 'sd.jsonld-valid-json',\n category: 'structured-data',\n group: 'diagnostic',\n weight: 3,\n impact: 'high',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#sdjsonld-valid-json',\n title: 'JSON-LD blocks parse as valid JSON',\n title_ko: 'JSON-LD 블록의 JSON 유효성',\n description: 'Malformed JSON in an ld+json block is silently ignored by most consumers — a costly silent failure.',\n run(ctx) {\n if (ctx.jsonLd.length === 0) {\n return { status: 'skip', score: 0, rationale: 'No JSON-LD to validate.', rationale_ko: '검증할 JSON-LD가 없습니다.' };\n }\n if (hasParseError(ctx.jsonLd)) {\n return {\n status: 'fail',\n score: 0,\n rationale: 'One or more JSON-LD blocks failed to parse.',\n rationale_ko: 'JSON-LD 블록 하나 이상을 파싱하지 못했습니다.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n }\n return { status: 'pass', score: 1, rationale: 'All JSON-LD blocks parse cleanly.', rationale_ko: '모든 JSON-LD 블록이 올바르게 파싱됩니다.' };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { flattenJsonLd, getTypes, KNOWN_SCHEMA_TYPES } from '../util.js';\n\nexport const schemaTypeRecognizedRule = defineRule({\n id: 'sd.schema-type-recognized',\n stableId: 'sd.schema-type-recognized',\n category: 'structured-data',\n group: 'diagnostic',\n weight: 4,\n impact: 'high',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#sdschema-type-recognized',\n title: 'Schema.org @type is a recognised kind',\n title_ko: 'Schema.org @type 인식 가능 여부',\n description: 'AI engines match pages against well-known types (Article, Product, FAQPage...). Obscure types weaken the signal.',\n run(ctx) {\n if (ctx.jsonLd.length === 0) {\n return { status: 'skip', score: 0, rationale: 'No JSON-LD to analyse.', rationale_ko: '분석할 JSON-LD가 없습니다.' };\n }\n const nodes = flattenJsonLd(ctx.jsonLd);\n const recognized = new Set<string>();\n const seenTypes = new Set<string>();\n for (const node of nodes) {\n for (const t of getTypes(node)) {\n seenTypes.add(t);\n if (KNOWN_SCHEMA_TYPES.includes(t)) recognized.add(t);\n }\n }\n if (recognized.size > 0) {\n return {\n status: 'pass',\n score: 1,\n rationale: `Recognised: ${[...recognized].join(', ')}.`,\n rationale_ko: `인식된 타입: ${[...recognized].join(', ')}.`,\n evidence: { recognized: [...recognized], all: [...seenTypes] },\n };\n }\n return {\n status: 'warn',\n score: 0.3,\n rationale: `No recognised schema.org types. Saw: ${[...seenTypes].join(', ') || '(none)'}.`,\n rationale_ko: `인식 가능한 schema.org 타입이 없습니다. 발견된 타입: ${[...seenTypes].join(', ') || '(없음)'}.`,\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { flattenJsonLd, getTypes, hasField, REQUIRED_FIELDS } from '../util.js';\n\nexport const requiredFieldsRule = defineRule({\n id: 'sd.required-fields',\n stableId: 'sd.required-fields',\n category: 'structured-data',\n group: 'opportunity',\n weight: 6,\n impact: 'high',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#sdrequired-fields',\n title: 'Required fields for recognised types are set',\n title_ko: '인식된 타입의 필수 필드 충족 여부',\n description: 'Article needs headline/author/datePublished, FAQPage needs mainEntity, Product needs offers, etc.',\n run(ctx) {\n if (ctx.jsonLd.length === 0) {\n return { status: 'skip', score: 0, rationale: 'No JSON-LD to analyse.', rationale_ko: '분석할 JSON-LD가 없습니다.' };\n }\n const nodes = flattenJsonLd(ctx.jsonLd);\n const missing: Array<{ type: string; field: string }> = [];\n const checked: string[] = [];\n for (const node of nodes) {\n for (const t of getTypes(node)) {\n const required = REQUIRED_FIELDS[t];\n if (!required) continue;\n checked.push(t);\n for (const f of required) {\n if (!hasField(node, f)) missing.push({ type: t, field: f });\n }\n }\n }\n if (checked.length === 0) {\n return {\n status: 'skip',\n score: 0,\n rationale: 'No types with known required fields were found.',\n rationale_ko: '필수 필드가 정의된 타입이 없습니다.',\n };\n }\n if (missing.length === 0) {\n return {\n status: 'pass',\n score: 1,\n rationale: `Required fields set on ${checked.length} node(s).`,\n rationale_ko: `${checked.length}개 노드의 필수 필드가 모두 충족됩니다.`,\n };\n }\n const msg = missing.map((m) => `${m.type}.${m.field}`).join(', ');\n return {\n status: 'fail',\n score: Math.max(0, 1 - missing.length / (checked.length * 2)),\n rationale: `Missing required fields: ${msg}.`,\n rationale_ko: `누락된 필수 필드: ${msg}.`,\n evidence: missing,\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const microdataFallbackRule = defineRule({\n id: 'sd.microdata-fallback',\n stableId: 'sd.microdata-fallback',\n category: 'structured-data',\n group: 'diagnostic',\n weight: 2,\n impact: 'medium',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#sdmicrodata-fallback',\n title: 'Microdata or RDFa fallback when JSON-LD is missing',\n title_ko: 'JSON-LD 없을 때 Microdata/RDFa 대체 여부',\n description: 'If JSON-LD is absent, inline microdata (itemscope/itemtype) or RDFa still gives some structured signal.',\n run(ctx) {\n if (ctx.jsonLd.length > 0) {\n return { status: 'skip', score: 0, rationale: 'JSON-LD is present; fallback not needed.', rationale_ko: 'JSON-LD가 있으므로 대체 수단이 필요하지 않습니다.' };\n }\n const microdata = ctx.$('[itemscope][itemtype]').length;\n const rdfa = ctx.$('[typeof][vocab], [typeof][property]').length;\n if (microdata > 0 || rdfa > 0) {\n return {\n status: 'pass',\n score: 1,\n rationale: `Found ${microdata} microdata and ${rdfa} RDFa nodes.`,\n rationale_ko: `Microdata ${microdata}개, RDFa ${rdfa}개 발견됩니다.`,\n };\n }\n return {\n status: 'fail',\n score: 0,\n rationale: 'No structured data at all (no JSON-LD, no microdata, no RDFa).',\n rationale_ko: '구조화 데이터가 전혀 없습니다 (JSON-LD, Microdata, RDFa 모두 없음).',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { flattenJsonLd, getTypes } from '../util.js';\n\nconst UNIQUE_TYPES = new Set(['Article', 'NewsArticle', 'BlogPosting', 'Product', 'Organization']);\n\nexport const noDuplicateTypesRule = defineRule({\n id: 'sd.no-duplicate-types',\n stableId: 'sd.no-duplicate-types',\n category: 'structured-data',\n group: 'diagnostic',\n weight: 2,\n impact: 'medium',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#sdno-duplicate-types',\n title: 'No conflicting duplicate @types',\n title_ko: '@type 중복 충돌 없음',\n description: 'Multiple competing entities of the same primary type (e.g. two Articles) confuse the engine about which one represents the page.',\n run(ctx) {\n if (ctx.jsonLd.length === 0) {\n return { status: 'skip', score: 0, rationale: 'No JSON-LD to analyse.', rationale_ko: '분석할 JSON-LD가 없습니다.' };\n }\n const counts = new Map<string, number>();\n for (const node of flattenJsonLd(ctx.jsonLd)) {\n for (const t of getTypes(node)) {\n if (UNIQUE_TYPES.has(t)) counts.set(t, (counts.get(t) ?? 0) + 1);\n }\n }\n const dupes = [...counts.entries()].filter(([, n]) => n > 1);\n if (dupes.length === 0) {\n return { status: 'pass', score: 1, rationale: 'No duplicate primary types.', rationale_ko: '중복된 기본 타입이 없습니다.' };\n }\n return {\n status: 'warn',\n score: 0.4,\n rationale: `Duplicate primary types: ${dupes.map(([t, n]) => `${t}×${n}`).join(', ')}.`,\n rationale_ko: `중복된 기본 타입: ${dupes.map(([t, n]) => `${t}×${n}`).join(', ')}.`,\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { flattenJsonLd, getTypes } from '../util.js';\n\nconst ENTITY_TYPES = ['Organization', 'Person', 'LocalBusiness', 'Brand', 'Corporation'];\nconst TRUSTED_HOSTS = [\n 'wikipedia.org',\n 'wikidata.org',\n 'linkedin.com',\n 'twitter.com',\n 'x.com',\n 'github.com',\n 'crunchbase.com',\n 'facebook.com',\n 'youtube.com',\n 'instagram.com',\n];\n\nfunction extractSameAs(node: unknown): string[] {\n if (!node || typeof node !== 'object') return [];\n const v = (node as { sameAs?: unknown }).sameAs;\n if (typeof v === 'string') return [v];\n if (Array.isArray(v)) return v.filter((x): x is string => typeof x === 'string');\n return [];\n}\n\nfunction trustedCount(urls: string[]): number {\n let n = 0;\n for (const u of urls) {\n try {\n const host = new URL(u).hostname.toLowerCase();\n if (TRUSTED_HOSTS.some((h) => host === h || host.endsWith('.' + h))) n++;\n } catch {\n /* ignore malformed */\n }\n }\n return n;\n}\n\nexport const sameAsEntityRule = defineRule({\n id: 'sd.sameas-entity',\n stableId: 'sd.sameas-entity',\n category: 'structured-data',\n group: 'opportunity',\n weight: 3,\n impact: 'high',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#sdsameas-entity',\n title: 'Entity nodes link the knowledge graph via sameAs',\n title_ko: 'sameAs로 지식 그래프 연결 여부',\n description:\n 'Organization/Person nodes should declare a sameAs[] array linking to Wikipedia/Wikidata/LinkedIn so AI engines can resolve the entity in their knowledge graph (E-E-A-T signal).',\n run(ctx) {\n if (ctx.jsonLd.length === 0) {\n return { status: 'skip', score: 0, rationale: 'No JSON-LD to analyse.', rationale_ko: '분석할 JSON-LD가 없습니다.' };\n }\n const nodes = flattenJsonLd(ctx.jsonLd);\n const entities = nodes.filter((n) => getTypes(n).some((t) => ENTITY_TYPES.includes(t)));\n if (entities.length === 0) {\n return {\n status: 'skip',\n score: 0,\n rationale: 'No Organization/Person/LocalBusiness/Brand entity to link.',\n rationale_ko: '연결할 Organization/Person/LocalBusiness/Brand 엔티티가 없습니다.',\n };\n }\n let bestScore = 0;\n let bestEvidence: { type: string; sameAs: string[]; trusted: number } | null = null;\n for (const e of entities) {\n const sameAs = extractSameAs(e);\n const trusted = trustedCount(sameAs);\n const types = getTypes(e);\n let score = 0;\n if (sameAs.length === 0) score = 0;\n else if (trusted === 0) score = 0.4;\n else if (trusted === 1) score = 0.7;\n else score = 1;\n if (score > bestScore) {\n bestScore = score;\n bestEvidence = { type: types[0] ?? 'Entity', sameAs, trusted };\n }\n }\n if (bestScore >= 1) {\n return {\n status: 'pass',\n score: 1,\n rationale: `Entity links ${bestEvidence!.trusted} trusted knowledge-graph hosts via sameAs.`,\n rationale_ko: `엔티티가 sameAs로 신뢰할 수 있는 지식 그래프 사이트 ${bestEvidence!.trusted}개에 연결되어 있습니다.`,\n evidence: bestEvidence,\n };\n }\n if (bestScore >= 0.7) {\n return {\n status: 'pass',\n score: bestScore,\n rationale: `Entity has 1 trusted sameAs link. Add Wikipedia/Wikidata for stronger E-E-A-T.`,\n rationale_ko: '신뢰할 수 있는 sameAs 링크가 1개 있습니다. E-E-A-T 강화를 위해 Wikipedia/Wikidata를 추가하세요.',\n evidence: bestEvidence,\n estimatedImpact: 1,\n };\n }\n if (bestScore > 0) {\n return {\n status: 'warn',\n score: bestScore,\n rationale: 'Entity declares sameAs but no trusted knowledge-graph hosts (Wikipedia/Wikidata/LinkedIn).',\n rationale_ko: 'sameAs가 선언되어 있지만 신뢰할 수 있는 지식 그래프 호스트(Wikipedia/Wikidata/LinkedIn)가 없습니다.',\n evidence: bestEvidence,\n fixHint: 'Add Wikipedia/Wikidata/LinkedIn URLs to your Organization sameAs[].',\n estimatedImpact: 2,\n };\n }\n return {\n status: 'warn',\n score: 0,\n rationale: `${entities.length} entity node(s) found but none declare sameAs links.`,\n rationale_ko: `엔티티 노드가 ${entities.length}개 있지만 sameAs 링크가 없습니다.`,\n fixHint: 'Add sameAs:[\"https://en.wikipedia.org/wiki/...\", \"https://www.linkedin.com/company/...\"] to your Organization JSON-LD.',\n estimatedImpact: 3,\n };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { flattenJsonLd, getTypes, hasField } from '../util.js';\n\ninterface ItemListIssue {\n index: number;\n missing: string[];\n}\n\nfunction validateItemList(node: unknown): ItemListIssue[] {\n if (!node || typeof node !== 'object') return [];\n const items = (node as { itemListElement?: unknown }).itemListElement;\n if (!Array.isArray(items) || items.length === 0) return [{ index: -1, missing: ['itemListElement'] }];\n const issues: ItemListIssue[] = [];\n items.forEach((item, i) => {\n const missing: string[] = [];\n if (!hasField(item, 'position')) missing.push('position');\n if (!hasField(item, 'name') && !hasField(item, 'item')) missing.push('name');\n if (!hasField(item, 'item') && !hasField(item, 'name')) missing.push('item');\n if (missing.length > 0) issues.push({ index: i, missing });\n });\n return issues;\n}\n\nexport const breadcrumbValidRule = defineRule({\n id: 'sd.breadcrumb-valid',\n stableId: 'sd.breadcrumb-valid',\n category: 'structured-data',\n group: 'opportunity',\n weight: 2,\n impact: 'medium',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#sdbreadcrumb-valid',\n title: 'BreadcrumbList items declare position, name, and item',\n title_ko: 'BreadcrumbList 항목의 필수 필드 충족 여부',\n description:\n 'When BreadcrumbList JSON-LD is present, every itemListElement should set position (1-indexed), name, and item (URL) — otherwise AI engines cannot reconstruct the path.',\n run(ctx) {\n if (ctx.jsonLd.length === 0) {\n return { status: 'skip', score: 0, rationale: 'No JSON-LD to analyse.', rationale_ko: '분석할 JSON-LD가 없습니다.' };\n }\n const nodes = flattenJsonLd(ctx.jsonLd);\n const breadcrumbs = nodes.filter((n) => getTypes(n).includes('BreadcrumbList'));\n if (breadcrumbs.length === 0) {\n return { status: 'skip', score: 0, rationale: 'No BreadcrumbList present.', rationale_ko: 'BreadcrumbList가 없습니다.' };\n }\n const allIssues: ItemListIssue[] = [];\n let totalItems = 0;\n for (const bc of breadcrumbs) {\n const items = (bc as { itemListElement?: unknown }).itemListElement;\n if (Array.isArray(items)) totalItems += items.length;\n allIssues.push(...validateItemList(bc));\n }\n if (allIssues.length === 0) {\n return {\n status: 'pass',\n score: 1,\n rationale: `BreadcrumbList(s) valid (${totalItems} items).`,\n rationale_ko: `BreadcrumbList가 유효합니다 (항목 ${totalItems}개).`,\n };\n }\n const fatalCount = allIssues.length;\n const denom = Math.max(1, totalItems);\n const score = Math.max(0, 1 - fatalCount / denom);\n return {\n status: score < 0.5 ? 'fail' : 'warn',\n score,\n rationale: `${fatalCount} breadcrumb item(s) missing required fields.`,\n rationale_ko: `breadcrumb 항목 ${fatalCount}개에 필수 필드가 없습니다.`,\n evidence: allIssues.slice(0, 5),\n fixHint: 'Each itemListElement needs { \"@type\": \"ListItem\", position: N, name, item }.',\n estimatedImpact: Math.round(2 * (1 - score)),\n };\n },\n});\n","import { jsonLdPresentRule } from './jsonld-present.js';\nimport { jsonLdValidJsonRule } from './jsonld-valid-json.js';\nimport { schemaTypeRecognizedRule } from './schema-type-recognized.js';\nimport { requiredFieldsRule } from './required-fields.js';\nimport { microdataFallbackRule } from './microdata-fallback.js';\nimport { noDuplicateTypesRule } from './no-duplicate-types.js';\nimport { sameAsEntityRule } from './sameas-entity.js';\nimport { breadcrumbValidRule } from './breadcrumb-valid.js';\n\nexport const structuredDataRules = [\n jsonLdPresentRule,\n jsonLdValidJsonRule,\n schemaTypeRecognizedRule,\n requiredFieldsRule,\n microdataFallbackRule,\n noDuplicateTypesRule,\n sameAsEntityRule,\n breadcrumbValidRule,\n];\n","import { defineRule } from '../../types.js';\n\nexport const titleRule = defineRule({\n id: 'cit.title',\n stableId: 'cit.title',\n category: 'citation',\n group: 'diagnostic',\n weight: 2,\n impact: 'critical',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#cittitle',\n title: '<title> is set with a reasonable length',\n title_ko: '<title> 태그 적정 길이 설정 여부',\n description: 'The document title is the single most-cited piece of text and should be 10–70 characters.',\n run(ctx) {\n const title = ctx.$('head > title').first().text().trim();\n if (!title) {\n return {\n status: 'fail',\n score: 0,\n rationale: 'Page has no <title>.',\n rationale_ko: '페이지에 <title>이 없습니다.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n }\n if (title.length < 10) {\n return {\n status: 'warn',\n score: 0.4,\n rationale: `Title is only ${title.length} chars; consider a more descriptive one.`,\n rationale_ko: `제목이 ${title.length}자밖에 안 됩니다. 더 구체적으로 작성하세요.`,\n };\n }\n if (title.length > 70) {\n return {\n status: 'warn',\n score: 0.6,\n rationale: `Title is ${title.length} chars; search UIs commonly truncate after ~70.`,\n rationale_ko: `제목이 ${title.length}자입니다. 검색 UI에서 70자 이후는 잘릴 수 있습니다.`,\n };\n }\n return { status: 'pass', score: 1, rationale: `Title length ${title.length} is within range.`, rationale_ko: `제목 길이 ${title.length}자로 적절합니다.` };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const metaDescriptionRule = defineRule({\n id: 'cit.meta-description',\n stableId: 'cit.meta-description',\n category: 'citation',\n group: 'opportunity',\n weight: 2,\n impact: 'high',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#citmeta-description',\n title: 'meta description is set (50–160 chars)',\n title_ko: 'meta description 설정 여부 (50–160자)',\n description: 'AI snippets often quote the meta description verbatim; aim for 50–160 chars.',\n run(ctx) {\n const desc = ctx.$('head meta[name=\"description\"]').attr('content')?.trim() ?? '';\n if (!desc) {\n return {\n status: 'warn',\n score: 0,\n rationale: 'No meta description set.',\n rationale_ko: 'meta description이 없습니다.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n }\n if (desc.length < 50) {\n return { status: 'warn', score: 0.5, rationale: `Only ${desc.length} chars; aim for 50+.`, rationale_ko: `${desc.length}자밖에 안 됩니다. 50자 이상을 목표로 하세요.` };\n }\n if (desc.length > 160) {\n return { status: 'warn', score: 0.7, rationale: `${desc.length} chars; may be truncated after 160.`, rationale_ko: `${desc.length}자입니다. 160자 이후는 잘릴 수 있습니다.` };\n }\n return { status: 'pass', score: 1, rationale: `Description length ${desc.length} is within range.`, rationale_ko: `설명 길이 ${desc.length}자로 적절합니다.` };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const canonicalRule = defineRule({\n id: 'cit.canonical',\n stableId: 'cit.canonical',\n category: 'citation',\n group: 'diagnostic',\n weight: 3,\n impact: 'high',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#citcanonical',\n title: 'Canonical URL is declared',\n title_ko: 'Canonical URL 선언 여부',\n description: 'rel=\"canonical\" tells crawlers which URL is the source of truth, preventing duplicate-citation confusion.',\n run(ctx) {\n const href = ctx.$('head link[rel=\"canonical\"]').attr('href')?.trim();\n if (!href) {\n return {\n status: 'warn',\n score: 0,\n rationale: 'No <link rel=\"canonical\"> found.',\n rationale_ko: '<link rel=\"canonical\">이 없습니다.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n }\n try {\n const abs = new URL(href, ctx.finalUrl).toString();\n return { status: 'pass', score: 1, rationale: `Canonical URL: ${abs}.`, rationale_ko: `Canonical URL: ${abs}.` };\n } catch {\n return { status: 'fail', score: 0, rationale: `Canonical href is not a valid URL: ${href}`, rationale_ko: `Canonical href가 유효한 URL이 아닙니다: ${href}` };\n }\n },\n});\n","import { defineRule } from '../../types.js';\n\nconst REQUIRED = ['og:title', 'og:type', 'og:url', 'og:image'] as const;\n\nexport const ogTagsRule = defineRule({\n id: 'cit.og-tags',\n stableId: 'cit.og-tags',\n category: 'citation',\n group: 'opportunity',\n weight: 3,\n impact: 'high',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#citog-tags',\n title: 'Open Graph tags are set',\n title_ko: 'Open Graph 태그 설정 여부',\n description: 'og:title/type/url/image power rich previews on AI chat, social, and messaging.',\n run(ctx) {\n const missing: string[] = [];\n for (const prop of REQUIRED) {\n const val = ctx.$(`head meta[property=\"${prop}\"]`).attr('content')?.trim();\n if (!val) missing.push(prop);\n }\n if (missing.length === 0) {\n return { status: 'pass', score: 1, rationale: 'All required OG tags present.', rationale_ko: '필수 OG 태그가 모두 있습니다.' };\n }\n const ratio = 1 - missing.length / REQUIRED.length;\n return {\n status: missing.length === REQUIRED.length ? 'fail' : 'warn',\n score: ratio,\n rationale: `Missing: ${missing.join(', ')}.`,\n rationale_ko: `누락된 태그: ${missing.join(', ')}.`,\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const twitterCardRule = defineRule({\n id: 'cit.twitter-card',\n stableId: 'cit.twitter-card',\n category: 'citation',\n group: 'opportunity',\n weight: 2,\n impact: 'low',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#cittwitter-card',\n title: 'Twitter Card metadata is set',\n title_ko: 'Twitter Card 메타데이터 설정 여부',\n description: 'twitter:card + twitter:title give better previews on X/Twitter and some AI surfaces that reuse the tags.',\n run(ctx) {\n const card = ctx.$('head meta[name=\"twitter:card\"]').attr('content')?.trim();\n const title = ctx.$('head meta[name=\"twitter:title\"]').attr('content')?.trim();\n if (card && title) {\n return { status: 'pass', score: 1, rationale: `Card type: ${card}.`, rationale_ko: `카드 유형: ${card}.` };\n }\n if (card || title) {\n return { status: 'warn', score: 0.5, rationale: 'Partial twitter:* metadata; add the missing tag.', rationale_ko: 'twitter:* 메타데이터가 일부만 있습니다. 누락된 태그를 추가하세요.' };\n }\n return {\n status: 'warn',\n score: 0,\n rationale: 'No twitter:card metadata.',\n rationale_ko: 'twitter:card 메타데이터가 없습니다.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const langAttrRule = defineRule({\n id: 'cit.lang-attr',\n stableId: 'cit.lang-attr',\n category: 'citation',\n group: 'diagnostic',\n weight: 2,\n impact: 'medium',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#citlang-attr',\n title: '<html lang> is set',\n title_ko: '<html lang> 속성 설정 여부',\n description: 'A lang attribute helps AI engines route the page to the right-language search surface (and helps screen readers).',\n run(ctx) {\n const lang = ctx.$('html').attr('lang')?.trim();\n if (!lang) {\n return {\n status: 'warn',\n score: 0,\n rationale: 'No lang attribute on <html>.',\n rationale_ko: '<html>에 lang 속성이 없습니다.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n }\n return { status: 'pass', score: 1, rationale: `lang=\"${lang}\".`, rationale_ko: `lang=\"${lang}\".` };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { flattenJsonLd, hasField } from '../util.js';\n\nexport const authorVisibleRule = defineRule({\n id: 'cit.author-visible',\n stableId: 'cit.author-visible',\n category: 'citation',\n group: 'opportunity',\n weight: 4,\n impact: 'high',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#citauthor-visible',\n title: 'Author is declared',\n title_ko: '작성자 정보 선언 여부',\n description: 'AI engines prefer citing content with an identifiable author; expose one via JSON-LD, meta[name=author], rel=author, or a .author class.',\n run(ctx) {\n for (const node of flattenJsonLd(ctx.jsonLd)) {\n if (hasField(node, 'author')) {\n return { status: 'pass', score: 1, rationale: 'Author found in JSON-LD.', rationale_ko: 'JSON-LD에서 작성자 정보를 찾았습니다.' };\n }\n }\n const metaAuthor = ctx.$('head meta[name=\"author\"]').attr('content')?.trim();\n if (metaAuthor) return { status: 'pass', score: 1, rationale: `meta[name=author] = \"${metaAuthor}\".`, rationale_ko: `meta[name=author] = \"${metaAuthor}\".` };\n if (ctx.$('[rel=\"author\"]').length > 0) {\n return { status: 'pass', score: 1, rationale: 'rel=\"author\" link found.', rationale_ko: 'rel=\"author\" 링크를 찾았습니다.' };\n }\n if (ctx.$('.author, [class*=\"author\"], [itemprop=\"author\"]').length > 0) {\n return { status: 'pass', score: 0.8, rationale: 'Author-ish DOM selector found (weaker signal).', rationale_ko: '작성자 관련 DOM 선택자가 있습니다 (신호 강도 낮음).' };\n }\n return {\n status: 'warn',\n score: 0,\n rationale: 'No author signal found (JSON-LD, meta, rel, or .author).',\n rationale_ko: '작성자 정보가 없습니다 (JSON-LD, meta, rel, .author 모두 없음).',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { flattenJsonLd, hasField } from '../util.js';\n\nexport const datesRule = defineRule({\n id: 'cit.dates',\n stableId: 'cit.dates',\n category: 'citation',\n group: 'opportunity',\n weight: 5,\n impact: 'high',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#citdates',\n title: 'Publish / modified date is present',\n title_ko: '발행일 / 수정일 존재 여부',\n description: 'AI engines rank recent pages higher; expose datePublished via JSON-LD, <time datetime>, or article:published_time meta.',\n run(ctx) {\n for (const node of flattenJsonLd(ctx.jsonLd)) {\n if (hasField(node, 'datePublished')) {\n return { status: 'pass', score: 1, rationale: 'datePublished found in JSON-LD.', rationale_ko: 'JSON-LD에서 datePublished를 찾았습니다.' };\n }\n }\n const articleTime = ctx.$('head meta[property=\"article:published_time\"]').attr('content')?.trim();\n if (articleTime) {\n return { status: 'pass', score: 1, rationale: `article:published_time = ${articleTime}.`, rationale_ko: `article:published_time = ${articleTime}.` };\n }\n const timeEl = ctx.$('time[datetime]').first().attr('datetime')?.trim();\n if (timeEl) {\n return { status: 'pass', score: 0.8, rationale: `<time datetime=\"${timeEl}\"> found.`, rationale_ko: `<time datetime=\"${timeEl}\">를 찾았습니다.` };\n }\n return {\n status: 'warn',\n score: 0,\n rationale: 'No publish date found (JSON-LD, meta article:published_time, or <time datetime>).',\n rationale_ko: '발행일이 없습니다 (JSON-LD, meta article:published_time, <time datetime> 모두 없음).',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { flattenJsonLd, getTypes } from '../util.js';\n\nconst ARTICLE_TYPES = new Set(['Article', 'NewsArticle', 'BlogPosting', 'Report', 'TechArticle']);\nconst ONE_DAY = 24 * 60 * 60 * 1000;\n\nfunction pickDate(node: unknown, field: string): string | undefined {\n if (!node || typeof node !== 'object') return undefined;\n const v = (node as Record<string, unknown>)[field];\n return typeof v === 'string' && v.trim() ? v.trim() : undefined;\n}\n\nfunction parseDateMs(s: string): number | null {\n const t = Date.parse(s);\n return Number.isNaN(t) ? null : t;\n}\n\nexport const contentFreshnessRule = defineRule({\n id: 'cit.content-freshness',\n stableId: 'cit.content-freshness',\n category: 'citation',\n group: 'opportunity',\n weight: 3,\n impact: 'high',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#citcontent-freshness',\n title: 'Article content is fresh (dateModified within 1 year)',\n title_ko: '콘텐츠 최신성 (dateModified 1년 이내)',\n description:\n 'AI engines down-rank stale content. Surface a recent dateModified (≤365 days) on Article-like pages so retrieval rankings stay strong.',\n run(ctx) {\n const nodes = flattenJsonLd(ctx.jsonLd);\n const articles = nodes.filter((n) => getTypes(n).some((t) => ARTICLE_TYPES.has(t)));\n if (articles.length === 0) {\n return {\n status: 'skip',\n score: 0,\n rationale: 'No Article/BlogPosting/NewsArticle JSON-LD; freshness signal not applicable.',\n rationale_ko: 'Article/BlogPosting/NewsArticle JSON-LD가 없어 최신성 신호를 확인할 수 없습니다.',\n };\n }\n let bestMs: number | null = null;\n let usedField: 'dateModified' | 'datePublished' | null = null;\n for (const a of articles) {\n const mod = pickDate(a, 'dateModified');\n const pub = pickDate(a, 'datePublished');\n const candidate = mod ?? pub;\n if (!candidate) continue;\n const ms = parseDateMs(candidate);\n if (ms === null) continue;\n if (bestMs === null || ms > bestMs) {\n bestMs = ms;\n usedField = mod ? 'dateModified' : 'datePublished';\n }\n }\n if (bestMs === null) {\n return {\n status: 'warn',\n score: 0,\n rationale: 'Article has no parseable dateModified or datePublished.',\n rationale_ko: 'Article JSON-LD에 파싱 가능한 dateModified 또는 datePublished가 없습니다.',\n fixHint: 'Add ISO-8601 dateModified and datePublished to your Article JSON-LD.',\n estimatedImpact: 3,\n };\n }\n const ageDays = Math.round((Date.now() - bestMs) / ONE_DAY);\n if (ageDays <= 365) {\n return {\n status: 'pass',\n score: 1,\n rationale: `${usedField} within the last year (~${ageDays} day${ageDays === 1 ? '' : 's'} ago).`,\n rationale_ko: `${usedField}이 1년 이내입니다 (약 ${ageDays}일 전).`,\n evidence: { ageDays, field: usedField },\n };\n }\n if (ageDays <= 730) {\n return {\n status: 'warn',\n score: 0.6,\n rationale: `${usedField} is ${ageDays} days old. Refresh within a year for best AI ranking.`,\n rationale_ko: `${usedField}이 ${ageDays}일 됐습니다. AI 순위를 유지하려면 1년 이내로 갱신하세요.`,\n evidence: { ageDays, field: usedField },\n estimatedImpact: 2,\n };\n }\n return {\n status: 'warn',\n score: 0.2,\n rationale: `${usedField} is ${ageDays} days old (>2 years). AI engines treat this as stale.`,\n rationale_ko: `${usedField}이 ${ageDays}일 됐습니다 (2년 초과). AI 엔진이 오래된 콘텐츠로 간주합니다.`,\n evidence: { ageDays, field: usedField },\n fixHint: 'Update content and bump dateModified to today\\'s date.',\n estimatedImpact: 3,\n };\n },\n});\n","import { titleRule } from './title.js';\nimport { metaDescriptionRule } from './meta-description.js';\nimport { canonicalRule } from './canonical.js';\nimport { ogTagsRule } from './og-tags.js';\nimport { twitterCardRule } from './twitter-card.js';\nimport { langAttrRule } from './lang-attr.js';\nimport { authorVisibleRule } from './author-visible.js';\nimport { datesRule } from './dates.js';\nimport { contentFreshnessRule } from './content-freshness.js';\n\nexport const citationRules = [\n titleRule,\n metaDescriptionRule,\n canonicalRule,\n ogTagsRule,\n twitterCardRule,\n langAttrRule,\n authorVisibleRule,\n datesRule,\n contentFreshnessRule,\n];\n","import { defineRule } from '../../types.js';\n\nexport const singleH1Rule = defineRule({\n id: 'cnt.single-h1',\n stableId: 'cnt.single-h1',\n category: 'content',\n group: 'diagnostic',\n weight: 3,\n impact: 'high',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#cntsingle-h1',\n title: 'Exactly one <h1>',\n title_ko: '<h1> 태그 1개 여부',\n description: 'A single H1 tells AI engines the primary topic of the page without ambiguity.',\n run(ctx) {\n const n = ctx.$('h1').length;\n if (n === 1) return { status: 'pass', score: 1, rationale: 'Exactly one <h1>.', rationale_ko: '<h1>이 정확히 1개입니다.' };\n if (n === 0) {\n return {\n status: 'fail',\n score: 0,\n rationale: 'No <h1> on the page.',\n rationale_ko: '페이지에 <h1>이 없습니다.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules/cnt.single-h1.md',\n };\n }\n return {\n status: 'warn',\n score: Math.max(0.3, 1 / n),\n rationale: `Found ${n} <h1> tags; prefer one primary heading.`,\n rationale_ko: `<h1>이 ${n}개 있습니다. 대표 제목 1개만 사용하세요.`,\n };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const headingHierarchyRule = defineRule({\n id: 'cnt.heading-hierarchy',\n stableId: 'cnt.heading-hierarchy',\n category: 'content',\n group: 'diagnostic',\n weight: 3,\n impact: 'medium',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#cntheading-hierarchy',\n title: 'Heading levels do not skip',\n title_ko: '제목 단계 순서 준수 여부',\n description: 'Going from H2 directly to H4 breaks the outline AI engines use to segment content.',\n run(ctx) {\n const levels: number[] = [];\n ctx.$('h1, h2, h3, h4, h5, h6').each((_i, el) => {\n const name = (el as { tagName?: string }).tagName?.toLowerCase() ?? 'h1';\n const m = /^h([1-6])$/.exec(name);\n if (m?.[1]) levels.push(parseInt(m[1], 10));\n });\n if (levels.length === 0) {\n return { status: 'skip', score: 0, rationale: 'No headings found.', rationale_ko: '제목 태그가 없습니다.' };\n }\n const skips: Array<{ from: number; to: number }> = [];\n for (let i = 1; i < levels.length; i++) {\n const prev = levels[i - 1]!;\n const curr = levels[i]!;\n if (curr > prev + 1) skips.push({ from: prev, to: curr });\n }\n if (skips.length === 0) {\n return { status: 'pass', score: 1, rationale: 'No heading-level skips.', rationale_ko: '제목 단계가 순서대로 사용됩니다.' };\n }\n return {\n status: 'warn',\n score: Math.max(0.3, 1 - skips.length / levels.length),\n rationale: `${skips.length} heading skip(s) detected (e.g. h${skips[0]!.from}→h${skips[0]!.to}).`,\n rationale_ko: `제목 단계 건너뜀이 ${skips.length}개 감지됩니다 (예: h${skips[0]!.from}→h${skips[0]!.to}).`,\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const imageAltRule = defineRule({\n id: 'cnt.image-alt',\n stableId: 'cnt.image-alt',\n category: 'content',\n group: 'opportunity',\n weight: 3,\n impact: 'medium',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#cntimage-alt',\n title: '≥80% of <img> have alt text',\n title_ko: '<img>의 80% 이상 alt 텍스트 보유 여부',\n description: 'Alt text gives AI engines a textual anchor for visual content and improves accessibility.',\n run(ctx) {\n const imgs = ctx.$('img');\n const total = imgs.length;\n if (total === 0) return { status: 'skip', score: 0, rationale: 'No <img> on the page.', rationale_ko: '페이지에 <img>가 없습니다.' };\n\n let withAlt = 0;\n imgs.each((_i, el) => {\n const alt = ctx.$(el).attr('alt');\n if (typeof alt === 'string' && alt.trim().length > 0) withAlt += 1;\n });\n const ratio = withAlt / total;\n if (ratio >= 0.8) {\n return { status: 'pass', score: 1, rationale: `${withAlt}/${total} images have alt (${Math.round(ratio * 100)}%).`, rationale_ko: `이미지 ${total}개 중 ${withAlt}개에 alt가 있습니다 (${Math.round(ratio * 100)}%).` };\n }\n return {\n status: 'warn',\n score: ratio,\n rationale: `Only ${withAlt}/${total} images have alt text (${Math.round(ratio * 100)}%). Aim for ≥80%.`,\n rationale_ko: `이미지 ${total}개 중 ${withAlt}개만 alt 텍스트가 있습니다 (${Math.round(ratio * 100)}%). 80% 이상을 목표로 하세요.`,\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { flattenJsonLd, getTypes } from '../util.js';\n\nexport const tldrOrFaqRule = defineRule({\n id: 'cnt.tldr-or-faq',\n stableId: 'cnt.tldr-or-faq',\n category: 'content',\n group: 'opportunity',\n weight: 5,\n impact: 'high',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#cnttldr-or-faq',\n title: 'TL;DR summary or FAQ block',\n title_ko: 'TL;DR 요약 또는 FAQ 블록 존재 여부',\n description: 'AI engines strongly prefer content with a quotable summary or FAQ — it makes the page \"citation-ready\".',\n run(ctx) {\n for (const node of flattenJsonLd(ctx.jsonLd)) {\n if (getTypes(node).includes('FAQPage')) {\n return { status: 'pass', score: 1, rationale: 'FAQPage schema present.', rationale_ko: 'FAQPage 스키마가 있습니다.' };\n }\n }\n const sel = [\n 'section[id*=\"tldr\" i]',\n 'section[id*=\"summary\" i]',\n 'section[id*=\"faq\" i]',\n '.tldr',\n '.summary',\n '.faq',\n '[data-tldr]',\n ].join(', ');\n if (ctx.$(sel).length > 0) {\n return { status: 'pass', score: 0.85, rationale: 'TL;DR / summary / FAQ region detected by selector.', rationale_ko: 'TL;DR / 요약 / FAQ 영역이 감지됩니다.' };\n }\n return {\n status: 'warn',\n score: 0,\n rationale: 'No TL;DR / summary / FAQ found; add one to boost AI citation odds.',\n rationale_ko: 'TL;DR / 요약 / FAQ가 없습니다. AI 인용 가능성을 높이려면 추가하세요.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const wordCountRule = defineRule({\n id: 'cnt.word-count',\n stableId: 'cnt.word-count',\n category: 'content',\n group: 'opportunity',\n weight: 2,\n impact: 'high',\n effort: 'high',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#cntword-count',\n title: 'Page has enough body text',\n title_ko: '충분한 본문 텍스트 여부',\n description: 'Thin pages (under ~100 words) are rarely cited by AI engines. Aim for ≥300 words of meaningful body copy.',\n run(ctx) {\n const $ = ctx.$;\n const clone = $('body').clone();\n clone.find('script, style, noscript, nav, header, footer, aside').remove();\n const text = clone.text().replace(/\\s+/g, ' ').trim();\n const words = text ? text.split(' ').length : 0;\n if (words >= 300) return { status: 'pass', score: 1, rationale: `${words} words of body text.`, rationale_ko: `본문 텍스트가 ${words}단어 있습니다.` };\n if (words >= 100) return { status: 'warn', score: 0.5, rationale: `Only ${words} words; aim for 300+.`, rationale_ko: `${words}단어밖에 없습니다. 300단어 이상을 목표로 하세요.` };\n return {\n status: 'fail',\n score: 0,\n rationale: `Only ${words} words; too thin to be cited.`,\n rationale_ko: `${words}단어밖에 없습니다. AI 엔진이 인용하기엔 너무 적습니다.`,\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { flattenJsonLd, getTypes } from '../util.js';\n\nconst QUESTION_LEADERS = [\n // English interrogatives\n 'how',\n 'what',\n 'why',\n 'when',\n 'where',\n 'who',\n 'which',\n 'is',\n 'are',\n 'can',\n 'should',\n 'do',\n 'does',\n // Korean interrogatives (어떻게, 왜, 무엇, 언제, 어디, 누가, 어느, 왜냐하면)\n '어떻게',\n '왜',\n '무엇',\n '뭐',\n '뭔',\n '언제',\n '어디',\n '누가',\n '어느',\n '얼마',\n];\n\nfunction isQuestionHeading(text: string): boolean {\n const t = text.trim();\n if (!t) return false;\n if (t.endsWith('?') || t.endsWith('?')) return true;\n const first = t.split(/[\\s,.:]+/, 1)[0]?.toLowerCase() ?? '';\n return QUESTION_LEADERS.includes(first);\n}\n\nexport const qaStructureRule = defineRule({\n id: 'cnt.qa-structure',\n stableId: 'cnt.qa-structure',\n category: 'content',\n group: 'opportunity',\n weight: 3,\n impact: 'high',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#cntqa-structure',\n title: 'Content uses Q&A structure for answer extraction',\n title_ko: '답변 추출을 위한 Q&A 구조 사용 여부',\n description:\n 'Question-style H2/H3 headings (or FAQPage JSON-LD) help AI engines extract direct answers. Pages with ≥2 question headings are far more likely to be cited.',\n run(ctx) {\n for (const node of flattenJsonLd(ctx.jsonLd)) {\n if (getTypes(node).includes('FAQPage')) {\n return { status: 'pass', score: 1, rationale: 'FAQPage JSON-LD provides explicit Q&A.', rationale_ko: 'FAQPage JSON-LD로 명시적인 Q&A 구조가 있습니다.' };\n }\n }\n const questionHeadings: string[] = [];\n ctx.$('h2, h3').each((_i, el) => {\n const text = ctx.$(el).text();\n if (isQuestionHeading(text)) questionHeadings.push(text.trim().slice(0, 80));\n });\n if (questionHeadings.length >= 2) {\n return {\n status: 'pass',\n score: 1,\n rationale: `${questionHeadings.length} question-style headings detected.`,\n rationale_ko: `질문형 제목이 ${questionHeadings.length}개 감지됩니다.`,\n evidence: { headings: questionHeadings.slice(0, 5) },\n };\n }\n if (questionHeadings.length === 1) {\n return {\n status: 'warn',\n score: 0.6,\n rationale: '1 question-style heading. Add a second to strengthen answer extraction.',\n rationale_ko: '질문형 제목이 1개입니다. 답변 추출 강화를 위해 하나 더 추가하세요.',\n evidence: { headings: questionHeadings },\n estimatedImpact: 1,\n };\n }\n return {\n status: 'warn',\n score: 0,\n rationale: 'No question-style H2/H3 headings or FAQPage JSON-LD found.',\n rationale_ko: '질문형 H2/H3 제목이나 FAQPage JSON-LD가 없습니다.',\n fixHint: 'Reframe at least 2 H2 headings as questions (\"How do I…?\", \"What is…?\") or add FAQPage JSON-LD.',\n estimatedImpact: 3,\n };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const externalCitationsRule = defineRule({\n id: 'cnt.external-citations',\n stableId: 'cnt.external-citations',\n category: 'content',\n group: 'opportunity',\n weight: 2,\n impact: 'medium',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#cntexternal-citations',\n title: 'Content cites external sources',\n title_ko: '외부 출처 인용 여부',\n description:\n 'Outbound links to authoritative external sources are an E-E-A-T trust signal. AI engines treat well-cited pages as more credible.',\n run(ctx) {\n let host: string;\n try {\n host = new URL(ctx.finalUrl).hostname.toLowerCase();\n } catch {\n return { status: 'skip', score: 0, rationale: 'Invalid finalUrl.', rationale_ko: '유효하지 않은 finalUrl입니다.' };\n }\n const seen = new Set<string>();\n ctx.$('main a[href], article a[href], body a[href]').each((_i, el) => {\n const href = ctx.$(el).attr('href');\n if (!href || href.startsWith('#') || href.startsWith('mailto:') || href.startsWith('tel:')) return;\n const rel = (ctx.$(el).attr('rel') ?? '').toLowerCase();\n if (rel.includes('nofollow') || rel.includes('sponsored')) return;\n let linkHost: string;\n try {\n linkHost = new URL(href, ctx.finalUrl).hostname.toLowerCase();\n } catch {\n return;\n }\n if (!linkHost) return;\n if (linkHost === host) return;\n if (linkHost.endsWith('.' + host) || host.endsWith('.' + linkHost)) return;\n seen.add(linkHost);\n });\n const count = seen.size;\n if (count >= 3) {\n return {\n status: 'pass',\n score: 1,\n rationale: `${count} distinct external host(s) cited (excluding nofollow).`,\n rationale_ko: `외부 사이트 ${count}개를 인용합니다 (nofollow 제외).`,\n evidence: { hosts: [...seen].slice(0, 8) },\n };\n }\n if (count >= 1) {\n return {\n status: 'pass',\n score: 0.7,\n rationale: `${count} external host(s) cited. Aim for ≥3 for stronger E-E-A-T.`,\n rationale_ko: `외부 사이트 ${count}개를 인용합니다. E-E-A-T 강화를 위해 3개 이상을 목표로 하세요.`,\n evidence: { hosts: [...seen] },\n estimatedImpact: 1,\n };\n }\n return {\n status: 'warn',\n score: 0,\n rationale: 'No external follow citations found in main content.',\n rationale_ko: '본문에 외부 출처 링크가 없습니다.',\n fixHint: 'Cite at least one authoritative external source (research paper, official docs, news outlet).',\n estimatedImpact: 2,\n };\n },\n});\n","import { singleH1Rule } from './single-h1.js';\nimport { headingHierarchyRule } from './heading-hierarchy.js';\nimport { imageAltRule } from './image-alt.js';\nimport { tldrOrFaqRule } from './tldr-or-faq.js';\nimport { wordCountRule } from './word-count.js';\nimport { qaStructureRule } from './qa-structure.js';\nimport { externalCitationsRule } from './external-citations.js';\n\nexport const contentRules = [\n singleH1Rule,\n headingHierarchyRule,\n imageAltRule,\n tldrOrFaqRule,\n wordCountRule,\n qaStructureRule,\n externalCitationsRule,\n];\n","import type { Rule } from '../types.js';\nimport { crawlerRules } from './crawler/index.js';\nimport { structuredDataRules } from './structured-data/index.js';\nimport { citationRules } from './citation/index.js';\nimport { contentRules } from './content/index.js';\n\nexport const defaultRules: Rule[] = [\n ...crawlerRules,\n ...structuredDataRules,\n ...citationRules,\n ...contentRules,\n];\n\nexport { crawlerRules, structuredDataRules, citationRules, contentRules };\n","import { readFile, stat } from 'node:fs/promises';\nimport { pathToFileURL } from 'node:url';\nimport { resolve } from 'node:path';\nimport type { Category, GeoConfig, Rule } from './types.js';\nimport { CATEGORY_WEIGHTS } from './types.js';\n\nconst CANDIDATE_NAMES = ['geo-checker.config.json', 'geo-checker.config.mjs', 'geo-checker.config.js'];\n\nexport interface LoadedConfig {\n config: GeoConfig;\n path: string | null;\n}\n\nasync function fileExists(p: string): Promise<boolean> {\n try {\n const s = await stat(p);\n return s.isFile();\n } catch {\n return false;\n }\n}\n\nexport async function findConfig(cwd: string): Promise<string | null> {\n for (const name of CANDIDATE_NAMES) {\n const p = resolve(cwd, name);\n if (await fileExists(p)) return p;\n }\n return null;\n}\n\nexport async function loadConfig(explicitPath: string | null, cwd: string = process.cwd()): Promise<LoadedConfig> {\n const path = explicitPath ? resolve(cwd, explicitPath) : await findConfig(cwd);\n if (!path) return { config: {}, path: null };\n if (!(await fileExists(path))) {\n throw new Error(`Config file not found: ${path}`);\n }\n if (path.endsWith('.json')) {\n const raw = await readFile(path, 'utf8');\n return { config: JSON.parse(raw) as GeoConfig, path };\n }\n const url = pathToFileURL(path).href;\n const mod = (await import(url)) as { default?: GeoConfig } & GeoConfig;\n const config = (mod.default ?? mod) as GeoConfig;\n return { config, path };\n}\n\nexport interface ApplyResult {\n rules: Rule[];\n categoryWeights: Record<Category, number>;\n}\n\nexport function applyConfig(defaultRules: Rule[], config: GeoConfig | undefined): ApplyResult {\n const categoryWeights: Record<Category, number> = { ...CATEGORY_WEIGHTS };\n if (!config) return { rules: defaultRules, categoryWeights };\n\n const merged = [...defaultRules, ...(config.extraRules ?? [])];\n const ruleOverrides = config.rules ?? {};\n\n const rules = merged\n .map((r) => {\n const key = r.stableId ?? r.id;\n const o = ruleOverrides[key] ?? ruleOverrides[r.id];\n if (!o) return r;\n if (o.enabled === false) return null;\n if (typeof o.weight === 'number' && o.weight > 0) {\n return { ...r, weight: o.weight };\n }\n return r;\n })\n .filter((r): r is Rule => r !== null);\n\n if (config.categories) {\n for (const [cat, override] of Object.entries(config.categories)) {\n if (override?.weight && override.weight > 0) {\n categoryWeights[cat as Category] = override.weight;\n }\n }\n }\n\n return { rules, categoryWeights };\n}\n","import type { AuditOptions, AuditReport } from './types.js';\nimport { audit } from './index.js';\n\nexport interface BatchOptions extends AuditOptions {\n concurrency?: number;\n onProgress?: (event: BatchProgressEvent) => void;\n}\n\nexport interface BatchSuccess {\n url: string;\n report: AuditReport;\n}\n\nexport interface BatchFailure {\n url: string;\n error: string;\n}\n\nexport type BatchResult = ({ ok: true } & BatchSuccess) | ({ ok: false } & BatchFailure);\n\nexport interface BatchSummary {\n total: number;\n successes: number;\n failures: number;\n averageOverall: number;\n worstOverall: number | null;\n bestOverall: number | null;\n results: BatchResult[];\n}\n\nexport type BatchProgressEvent =\n | { kind: 'start'; url: string; index: number; total: number }\n | { kind: 'success'; url: string; overall: number; index: number; total: number }\n | { kind: 'failure'; url: string; error: string; index: number; total: number };\n\nexport async function runBatch(urls: string[], options: BatchOptions = {}): Promise<BatchSummary> {\n const concurrency = Math.max(1, options.concurrency ?? 4);\n const results: BatchResult[] = new Array(urls.length);\n const onProgress = options.onProgress;\n const auditOpts: AuditOptions = { ...options };\n delete (auditOpts as BatchOptions).concurrency;\n delete (auditOpts as BatchOptions).onProgress;\n\n let cursor = 0;\n async function worker(): Promise<void> {\n for (;;) {\n const i = cursor++;\n if (i >= urls.length) return;\n const url = urls[i]!;\n onProgress?.({ kind: 'start', url, index: i, total: urls.length });\n try {\n const report = await audit(url, auditOpts);\n results[i] = { ok: true, url, report };\n onProgress?.({ kind: 'success', url, overall: report.overall, index: i, total: urls.length });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n results[i] = { ok: false, url, error: message };\n onProgress?.({ kind: 'failure', url, error: message, index: i, total: urls.length });\n }\n }\n }\n\n await Promise.all(Array.from({ length: Math.min(concurrency, urls.length) }, worker));\n\n const successes = results.filter((r): r is BatchResult & { ok: true } => r.ok);\n const failures = results.filter((r): r is BatchResult & { ok: false } => !r.ok);\n const overalls = successes.map((s) => s.report.overall);\n const averageOverall =\n overalls.length === 0 ? 0 : Math.round(overalls.reduce((a, b) => a + b, 0) / overalls.length);\n\n return {\n total: urls.length,\n successes: successes.length,\n failures: failures.length,\n averageOverall,\n worstOverall: overalls.length === 0 ? null : Math.min(...overalls),\n bestOverall: overalls.length === 0 ? null : Math.max(...overalls),\n results,\n };\n}\n\nexport function summaryToJson(summary: BatchSummary): string {\n return JSON.stringify(\n {\n total: summary.total,\n successes: summary.successes,\n failures: summary.failures,\n averageOverall: summary.averageOverall,\n worstOverall: summary.worstOverall,\n bestOverall: summary.bestOverall,\n results: summary.results.map((r) =>\n r.ok\n ? {\n ok: true,\n url: r.url,\n overall: r.report.overall,\n categories: Object.fromEntries(\n Object.entries(r.report.categories).map(([k, v]) => [k, v.score]),\n ),\n }\n : { ok: false, url: r.url, error: r.error },\n ),\n },\n null,\n 2,\n );\n}\n\nexport function urlToSlug(url: string): string {\n try {\n const u = new URL(url);\n const base = (u.hostname + u.pathname).replace(/\\/+$/, '');\n const slug = base.replace(/[^a-zA-Z0-9.-]+/g, '_').replace(/^_+|_+$/g, '');\n return slug || 'page';\n } catch {\n return url.replace(/[^a-zA-Z0-9.-]+/g, '_').slice(0, 80) || 'page';\n }\n}\n","import type { AuditReport, Category } from '../types.js';\n\nconst COLS = [\n 'url',\n 'category',\n 'id',\n 'stableId',\n 'title',\n 'status',\n 'score',\n 'weight',\n 'group',\n 'impact',\n 'effort',\n 'estimatedImpact',\n 'durationMs',\n 'rationale',\n 'docsUrl',\n] as const;\n\nfunction escape(v: unknown): string {\n if (v === undefined || v === null) return '';\n const s = String(v);\n if (/[\",\\n\\r]/.test(s)) return `\"${s.replace(/\"/g, '\"\"')}\"`;\n return s;\n}\n\nexport function toCsv(report: AuditReport): string {\n const rows: string[] = [COLS.join(',')];\n for (const cat of Object.keys(report.categories) as Category[]) {\n for (const r of report.categories[cat].results) {\n rows.push(\n [\n report.finalUrl,\n cat,\n r.id,\n r.stableId ?? '',\n r.title,\n r.status,\n r.score,\n r.weight,\n r.group ?? '',\n r.impact ?? '',\n r.effort ?? '',\n r.estimatedImpact ?? '',\n r.durationMs ?? '',\n r.rationale,\n r.docsUrl ?? '',\n ]\n .map(escape)\n .join(','),\n );\n }\n }\n return rows.join('\\n') + '\\n';\n}\n","import type { AuditReport, Category, Status } from '../types.js';\n\nconst CATEGORY_LABELS: Record<Category, string> = {\n crawler: 'AI Crawler Access',\n 'structured-data': 'Structured Data',\n citation: 'Citation Signals',\n content: 'Content Structure',\n};\n\nfunction scoreBadge(score: number): string {\n const color = score >= 85 ? 'brightgreen' : score >= 60 ? 'yellow' : 'red';\n return ``;\n}\n\nfunction statusEmoji(s: Status): string {\n switch (s) {\n case 'pass':\n return '✅';\n case 'warn':\n return '⚠️';\n case 'fail':\n return '❌';\n default:\n return '⏭️';\n }\n}\n\nfunction escapeMd(s: string): string {\n return s.replace(/\\|/g, '\\\\|').replace(/\\r?\\n/g, ' ');\n}\n\nexport function toMarkdown(report: AuditReport): string {\n const lines: string[] = [];\n lines.push(`## geo-checker · ${report.finalUrl}`);\n lines.push('');\n lines.push(`**Overall:** ${scoreBadge(report.overall)}`);\n lines.push('');\n lines.push('| Category | Score |');\n lines.push('| --- | --- |');\n for (const cat of Object.keys(report.categories) as Category[]) {\n const b = report.categories[cat];\n if (b.results.length === 0) continue;\n lines.push(`| ${CATEGORY_LABELS[cat]} | ${scoreBadge(b.score)} |`);\n }\n lines.push('');\n const failing = Object.values(report.categories)\n .flatMap((c) => c.results)\n .filter((r) => r.status === 'fail' || r.status === 'warn')\n .sort((a, b) => (b.estimatedImpact ?? 0) - (a.estimatedImpact ?? 0));\n if (failing.length > 0) {\n lines.push('### Issues to address');\n lines.push('');\n lines.push('| | Rule | Impact | Hint |');\n lines.push('| --- | --- | --- | --- |');\n for (const r of failing) {\n const idLink = r.docsUrl ? `[${r.stableId ?? r.id}](${r.docsUrl})` : (r.stableId ?? r.id);\n const impact = r.impact ? `\\`${r.impact}\\`` : '';\n const hint = escapeMd(r.fixHint ?? r.rationale);\n lines.push(`| ${statusEmoji(r.status)} | ${idLink} | ${impact} | ${hint} |`);\n }\n lines.push('');\n } else {\n lines.push('All audited rules pass. ✅');\n lines.push('');\n }\n if (report.warnings.length > 0) {\n lines.push('> ' + report.warnings.map(escapeMd).join(' \\n> '));\n lines.push('');\n }\n lines.push(\n `<sub>geo-checker v${report.version} · ${report.renderMode} · fetched ${report.fetchedAt} · ${report.timing.totalMs}ms</sub>`,\n );\n lines.push('');\n return lines.join('\\n');\n}\n","import type { AuditReport, RuleResultEntry, Status } from '../types.js';\n\ninterface SarifLocation {\n physicalLocation: {\n artifactLocation: { uri: string };\n region?: { startLine?: number; startColumn?: number; snippet?: { text: string } };\n };\n}\n\ninterface SarifResult {\n ruleId: string;\n level: 'error' | 'warning' | 'note' | 'none';\n message: { text: string };\n locations: SarifLocation[];\n properties?: { score: number; weight: number; impact?: string; effort?: string; estimatedImpact?: number };\n}\n\ninterface SarifRule {\n id: string;\n name: string;\n shortDescription: { text: string };\n fullDescription: { text: string };\n helpUri?: string;\n defaultConfiguration: { level: 'error' | 'warning' | 'note' };\n properties: { category: string; weight: number; impact?: string; effort?: string };\n}\n\nfunction statusToLevel(s: Status): 'error' | 'warning' | 'note' | 'none' {\n if (s === 'fail') return 'error';\n if (s === 'warn') return 'warning';\n if (s === 'skip') return 'none';\n return 'note';\n}\n\nfunction buildLocations(uri: string, r: RuleResultEntry): SarifLocation[] {\n const locs = r.locations ?? [];\n if (locs.length === 0) {\n return [{ physicalLocation: { artifactLocation: { uri } } }];\n }\n return locs.map((l) => {\n const loc: SarifLocation = { physicalLocation: { artifactLocation: { uri } } };\n if (l.line !== undefined || l.col !== undefined || l.snippet) {\n loc.physicalLocation.region = {};\n if (l.line !== undefined) loc.physicalLocation.region.startLine = l.line;\n if (l.col !== undefined) loc.physicalLocation.region.startColumn = l.col;\n if (l.snippet) loc.physicalLocation.region.snippet = { text: l.snippet };\n }\n return loc;\n });\n}\n\nexport function toSarif(report: AuditReport): string {\n const allResults = Object.values(report.categories).flatMap((c) => c.results);\n const seenRules = new Map<string, SarifRule>();\n const sarifResults: SarifResult[] = [];\n\n for (const r of allResults) {\n const id = r.stableId ?? r.id;\n if (!seenRules.has(id)) {\n const rule: SarifRule = {\n id,\n name: r.title,\n shortDescription: { text: r.title },\n fullDescription: { text: r.rationale },\n defaultConfiguration: { level: statusToLevel(r.status) === 'note' ? 'note' : statusToLevel(r.status) === 'error' ? 'error' : 'warning' },\n properties: {\n category: categoryOf(report, r.id),\n weight: r.weight,\n ...(r.impact ? { impact: r.impact } : {}),\n ...(r.effort ? { effort: r.effort } : {}),\n },\n };\n if (r.docsUrl) rule.helpUri = r.docsUrl;\n seenRules.set(id, rule);\n }\n if (r.status === 'fail' || r.status === 'warn') {\n const sr: SarifResult = {\n ruleId: id,\n level: statusToLevel(r.status),\n message: { text: r.fixHint ? `${r.rationale} — ${r.fixHint}` : r.rationale },\n locations: buildLocations(report.finalUrl, r),\n properties: {\n score: r.score,\n weight: r.weight,\n ...(r.impact ? { impact: r.impact } : {}),\n ...(r.effort ? { effort: r.effort } : {}),\n ...(r.estimatedImpact !== undefined ? { estimatedImpact: r.estimatedImpact } : {}),\n },\n };\n sarifResults.push(sr);\n }\n }\n\n const sarif = {\n $schema: 'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json',\n version: '2.1.0',\n runs: [\n {\n tool: {\n driver: {\n name: 'geo-checker',\n version: report.version,\n informationUri: 'https://github.com/BaRam-OSS/geo-checker',\n rules: [...seenRules.values()],\n },\n },\n results: sarifResults,\n invocations: [\n {\n executionSuccessful: true,\n startTimeUtc: report.fetchedAt,\n },\n ],\n },\n ],\n };\n return JSON.stringify(sarif, null, 2);\n}\n\nfunction categoryOf(report: AuditReport, ruleId: string): string {\n for (const [cat, bucket] of Object.entries(report.categories)) {\n if (bucket.results.some((r) => r.id === ruleId)) return cat;\n }\n return 'unknown';\n}\n","import type { AuditReport, Category, RuleResultEntry } from '../types.js';\n\nexport interface RuleDelta {\n id: string;\n stableId?: string;\n category: Category;\n before: RuleResultEntry['status'];\n after: RuleResultEntry['status'];\n scoreDelta: number;\n}\n\nexport interface CategoryDelta {\n category: Category;\n before: number;\n after: number;\n delta: number;\n}\n\nexport interface ReportDiff {\n before: { url: string; overall: number; version: string; fetchedAt: string };\n after: { url: string; overall: number; version: string; fetchedAt: string };\n overallDelta: number;\n categories: CategoryDelta[];\n regressions: RuleDelta[];\n fixes: RuleDelta[];\n newFailures: RuleDelta[];\n}\n\nconst SEVERITY: Record<RuleResultEntry['status'], number> = { skip: 0, pass: 1, warn: 2, fail: 3 };\n\nfunction indexResults(report: AuditReport): Map<string, { entry: RuleResultEntry; category: Category }> {\n const map = new Map<string, { entry: RuleResultEntry; category: Category }>();\n for (const cat of Object.keys(report.categories) as Category[]) {\n for (const r of report.categories[cat].results) {\n const key = r.stableId ?? r.id;\n map.set(key, { entry: r, category: cat });\n }\n }\n return map;\n}\n\nexport function diffReports(before: AuditReport, after: AuditReport): ReportDiff {\n const beforeMap = indexResults(before);\n const afterMap = indexResults(after);\n\n const regressions: RuleDelta[] = [];\n const fixes: RuleDelta[] = [];\n const newFailures: RuleDelta[] = [];\n\n for (const [key, b] of beforeMap) {\n const a = afterMap.get(key);\n if (!a) continue;\n const before = b.entry.status;\n const after = a.entry.status;\n if (SEVERITY[after] > SEVERITY[before]) {\n regressions.push({\n id: a.entry.id,\n ...(a.entry.stableId !== undefined ? { stableId: a.entry.stableId } : {}),\n category: a.category,\n before,\n after,\n scoreDelta: a.entry.score - b.entry.score,\n });\n } else if (SEVERITY[after] < SEVERITY[before] && (before === 'fail' || before === 'warn')) {\n fixes.push({\n id: a.entry.id,\n ...(a.entry.stableId !== undefined ? { stableId: a.entry.stableId } : {}),\n category: a.category,\n before,\n after,\n scoreDelta: a.entry.score - b.entry.score,\n });\n }\n }\n\n for (const [key, a] of afterMap) {\n if (beforeMap.has(key)) continue;\n if (a.entry.status === 'fail' || a.entry.status === 'warn') {\n newFailures.push({\n id: a.entry.id,\n ...(a.entry.stableId !== undefined ? { stableId: a.entry.stableId } : {}),\n category: a.category,\n before: 'skip',\n after: a.entry.status,\n scoreDelta: a.entry.score,\n });\n }\n }\n\n const categories: CategoryDelta[] = (Object.keys(after.categories) as Category[]).map((c) => ({\n category: c,\n before: before.categories[c]?.score ?? 0,\n after: after.categories[c].score,\n delta: after.categories[c].score - (before.categories[c]?.score ?? 0),\n }));\n\n return {\n before: { url: before.finalUrl, overall: before.overall, version: before.version, fetchedAt: before.fetchedAt },\n after: { url: after.finalUrl, overall: after.overall, version: after.version, fetchedAt: after.fetchedAt },\n overallDelta: after.overall - before.overall,\n categories,\n regressions,\n fixes,\n newFailures,\n };\n}\n\nconst ARROW_UP = '↑';\nconst ARROW_DOWN = '↓';\nconst ARROW_FLAT = '·';\n\nfunction arrow(d: number): string {\n if (d > 0) return ARROW_UP;\n if (d < 0) return ARROW_DOWN;\n return ARROW_FLAT;\n}\n\nexport function formatDiffLine(diff: ReportDiff): string {\n const overall = `overall ${arrow(diff.overallDelta)} ${diff.overallDelta >= 0 ? '+' : ''}${diff.overallDelta}`;\n const cats = diff.categories\n .filter((c) => c.delta !== 0)\n .map((c) => `${c.category} ${arrow(c.delta)} ${c.delta >= 0 ? '+' : ''}${c.delta}`)\n .join(' · ');\n const reg = diff.regressions.length;\n const fix = diff.fixes.length;\n const nu = diff.newFailures.length;\n const tail = [\n reg > 0 ? `🆕 ${reg} regression${reg > 1 ? 's' : ''}` : '',\n nu > 0 ? `+${nu} new fail${nu > 1 ? 's' : ''}` : '',\n fix > 0 ? `✅ ${fix} fixed` : '',\n ]\n .filter(Boolean)\n .join(' · ');\n return [overall, cats, tail].filter(Boolean).join(' · ');\n}\n","import type { AuditOptions, AuditReport } from './types.js';\nimport { buildContext } from './context.js';\nimport { runRules } from './engine.js';\nimport { defaultRules } from './rules/index.js';\nimport { applyConfig, loadConfig } from './config.js';\n\nexport { defineRule, CATEGORY_WEIGHTS } from './types.js';\nexport { defaultRules } from './rules/index.js';\nexport { runBatch, summaryToJson, urlToSlug } from './batch.js';\nexport type { BatchOptions, BatchResult, BatchSuccess, BatchFailure, BatchSummary, BatchProgressEvent } from './batch.js';\nexport { toCsv } from './reporters/csv.js';\nexport { toMarkdown } from './reporters/markdown.js';\nexport { toSarif } from './reporters/sarif.js';\nexport { diffReports, formatDiffLine } from './reporters/diff.js';\nexport type { ReportDiff, RuleDelta, CategoryDelta } from './reporters/diff.js';\nexport { loadConfig, findConfig, applyConfig } from './config.js';\nexport type {\n Status,\n Category,\n Rule,\n RuleResult,\n AuditContext,\n AuditOptions,\n AuditReport,\n CategoryReport,\n RobotsTxt,\n RobotsRuleGroup,\n LlmsTxt,\n LlmsTxtLink,\n LlmsTxtSection,\n SitemapSummary,\n GeoConfig,\n RuleOverride,\n} from './types.js';\n\nexport async function audit(url: string, options: AuditOptions = {}): Promise<AuditReport> {\n const startedAt = performance.now();\n\n let config = options.config;\n let configPath = options.configPath ?? null;\n if (!config && configPath) {\n const loaded = await loadConfig(configPath);\n config = loaded.config;\n configPath = loaded.path;\n }\n\n const ctx = await buildContext(url, {\n ...(options.render ? { render: true } : {}),\n ...(options.userAgent !== undefined ? { userAgent: options.userAgent } : {}),\n ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n });\n const fetchMs = Math.round(performance.now() - startedAt);\n\n const baseRules = [...defaultRules, ...(options.extraRules ?? [])];\n const { rules, categoryWeights } = applyConfig(baseRules, config);\n\n const meta: { userAgent?: string; configPath?: string } = {};\n if (options.userAgent !== undefined) meta.userAgent = options.userAgent;\n if (configPath) meta.configPath = configPath;\n\n return runRules(ctx, rules, {\n ...(options.only ? { only: options.only } : {}),\n ...(options.categories ? { categories: options.categories } : {}),\n ...(Object.keys(meta).length > 0 ? { meta } : {}),\n categoryWeights,\n fetchMs,\n startedAt,\n });\n}\n","import type { AuditReport } from '../types.js';\n\nexport function toJson(report: AuditReport, pretty = true): string {\n return pretty ? JSON.stringify(report, null, 2) : JSON.stringify(report);\n}\n","import kleur from 'kleur';\nimport Table from 'cli-table3';\nimport type { AuditReport, Category, Impact, Status } from '../types.js';\n\nconst CATEGORY_LABELS: Record<Category, string> = {\n crawler: 'AI Crawler Access',\n 'structured-data': 'Structured Data',\n citation: 'Citation Signals',\n content: 'Content Structure',\n};\n\nfunction colorScore(score: number): string {\n if (score >= 85) return kleur.green().bold(`${score}`);\n if (score >= 60) return kleur.yellow().bold(`${score}`);\n return kleur.red().bold(`${score}`);\n}\n\nfunction statusBadge(status: Status): string {\n switch (status) {\n case 'pass':\n return kleur.green('pass');\n case 'warn':\n return kleur.yellow('warn');\n case 'fail':\n return kleur.red('fail');\n default:\n return kleur.gray('skip');\n }\n}\n\nfunction impactChip(impact?: Impact): string {\n if (!impact) return '';\n switch (impact) {\n case 'critical':\n return kleur.red().bold('[crit]');\n case 'high':\n return kleur.red('[high]');\n case 'medium':\n return kleur.yellow('[med]');\n case 'low':\n return kleur.gray('[low]');\n }\n}\n\nfunction renderNote(rationale: string, impact?: Impact, estimatedImpact?: number): string {\n const parts: string[] = [];\n const chip = impactChip(impact);\n if (chip) parts.push(chip);\n if (estimatedImpact !== undefined && estimatedImpact > 0) {\n parts.push(kleur.cyan(`+${estimatedImpact}`));\n }\n parts.push(rationale);\n return parts.join(' ');\n}\n\nfunction bar(score: number, width = 20): string {\n const filled = Math.round((score / 100) * width);\n const empty = width - filled;\n const color = score >= 85 ? kleur.green : score >= 60 ? kleur.yellow : kleur.red;\n return color('█'.repeat(filled)) + kleur.gray('░'.repeat(empty));\n}\n\nexport function toCli(report: AuditReport): string {\n const lines: string[] = [];\n lines.push('');\n lines.push(\n kleur.bold('geo-checker') +\n kleur.gray(' · ') +\n report.finalUrl +\n kleur.gray(` (${report.renderMode})`),\n );\n lines.push(\n kleur.gray('fetched ') +\n report.fetchedAt +\n kleur.gray(' · v') +\n report.version +\n kleur.gray(\n ` · fetch ${report.timing.fetchMs}ms, audit ${report.timing.auditMs}ms, total ${report.timing.totalMs}ms`,\n ),\n );\n lines.push('');\n lines.push(kleur.bold('Overall ') + colorScore(report.overall) + kleur.gray(' / 100'));\n lines.push('');\n\n for (const w of report.warnings) {\n lines.push(kleur.yellow('! ') + w);\n }\n if (report.warnings.length > 0) lines.push('');\n\n for (const cat of Object.keys(report.categories) as Category[]) {\n const b = report.categories[cat];\n if (b.results.length === 0) continue;\n lines.push(\n ` ${kleur.bold(CATEGORY_LABELS[cat].padEnd(20))} ${bar(b.score)} ${colorScore(b.score).padStart(3)}/100`,\n );\n const table = new Table({\n head: [kleur.gray('status'), kleur.gray('rule'), kleur.gray('note')],\n colWidths: [7, 34, 70],\n wordWrap: true,\n style: { head: [], border: ['grey'] },\n });\n for (const r of b.results) {\n table.push([statusBadge(r.status), r.id, renderNote(r.rationale, r.impact, r.estimatedImpact)]);\n }\n lines.push(\n table\n .toString()\n .split('\\n')\n .map((l) => ' ' + l)\n .join('\\n'),\n );\n lines.push('');\n }\n\n const fixUrls = Object.values(report.categories)\n .flatMap((c) => c.results)\n .filter((r) => (r.status === 'fail' || r.status === 'warn') && r.fixUrl)\n .map((r) => ` - ${r.id}: ${r.fixUrl}`);\n if (fixUrls.length > 0) {\n lines.push(kleur.bold('How to fix:'));\n lines.push(...fixUrls);\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n","import type {\n AuditReport,\n Category,\n EvidenceLocation,\n Impact,\n RuleResultEntry,\n Status,\n} from '../types.js';\n\nconst CATEGORY_LABELS: Record<Category, string> = {\n crawler: 'AI Crawler Access',\n 'structured-data': 'Structured Data',\n citation: 'Citation Signals',\n content: 'Content Structure',\n};\n\nconst IMPACT_ORDER: Record<Impact, number> = {\n critical: 4,\n high: 3,\n medium: 2,\n low: 1,\n};\n\nfunction esc(s: unknown): string {\n if (s === null || s === undefined) return '';\n return String(s)\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\nfunction scoreClass(score: number): 'good' | 'avg' | 'poor' {\n if (score >= 85) return 'good';\n if (score >= 60) return 'avg';\n return 'poor';\n}\n\nfunction ring(score: number, label: string, size = 128): string {\n const r = size / 2 - 8;\n const c = 2 * Math.PI * r;\n const offset = c * (1 - score / 100);\n const cls = scoreClass(score);\n return `<div class=\"ring ring-${cls}\">\n <svg viewBox=\"0 0 ${size} ${size}\" width=\"${size}\" height=\"${size}\" aria-hidden=\"true\">\n <circle cx=\"${size / 2}\" cy=\"${size / 2}\" r=\"${r}\" class=\"ring-track\" />\n <circle cx=\"${size / 2}\" cy=\"${size / 2}\" r=\"${r}\" class=\"ring-value\"\n stroke-dasharray=\"${c.toFixed(2)}\" stroke-dashoffset=\"${offset.toFixed(2)}\" />\n </svg>\n <div class=\"ring-num\">${score}</div>\n <div class=\"ring-label\">${esc(label)}</div>\n </div>`;\n}\n\nfunction statusChip(status: Status): string {\n return `<span class=\"chip chip-${status}\">${status}</span>`;\n}\n\nfunction impactChip(impact?: Impact): string {\n if (!impact) return '';\n return `<span class=\"chip chip-impact chip-impact-${impact}\">impact: ${impact}</span>`;\n}\n\nfunction effortChip(effort?: string): string {\n if (!effort) return '';\n return `<span class=\"chip chip-effort\">effort: ${esc(effort)}</span>`;\n}\n\nfunction locationBlock(locations?: EvidenceLocation[]): string {\n if (!locations || locations.length === 0) return '';\n const items = locations\n .map((loc) => {\n const parts: string[] = [];\n if (loc.selector) parts.push(`<code class=\"sel\">${esc(loc.selector)}</code>`);\n if (loc.line !== undefined) parts.push(`line ${loc.line}${loc.col !== undefined ? `:${loc.col}` : ''}`);\n const head = parts.length > 0 ? `<div class=\"loc-head\">${parts.join(' · ')}</div>` : '';\n const snippet = loc.snippet ? `<pre class=\"snippet\">${esc(loc.snippet)}</pre>` : '';\n return `<li class=\"loc\">${head}${snippet}</li>`;\n })\n .join('');\n return `<ul class=\"locations\">${items}</ul>`;\n}\n\nfunction auditRow(r: RuleResultEntry): string {\n const impact = impactChip(r.impact);\n const effort = effortChip(r.effort);\n const est =\n r.estimatedImpact !== undefined\n ? `<span class=\"chip chip-est\">est +${r.estimatedImpact}</span>`\n : '';\n const docs = r.docsUrl\n ? `<a class=\"docs\" href=\"${esc(r.docsUrl)}\" target=\"_blank\" rel=\"noopener\">docs ↗</a>`\n : '';\n const fixHint = r.fixHint ? `<div class=\"fix-hint\">${esc(r.fixHint)}</div>` : '';\n const id = esc(r.stableId ?? r.id);\n const score = Math.round(r.score * 100);\n return `<div class=\"audit audit-${r.status}\" data-stable-id=\"${id}\">\n <div class=\"audit-head\">\n ${statusChip(r.status)}\n <span class=\"audit-title\">${esc(r.title)}</span>\n <span class=\"audit-score\">${score}</span>\n ${impact}${effort}${est}\n ${docs}\n </div>\n <div class=\"audit-id\"><code>${id}</code> · weight ${r.weight}${r.durationMs !== undefined ? ` · ${r.durationMs}ms` : ''}</div>\n <div class=\"audit-rationale\">${esc(r.rationale)}</div>\n ${fixHint}\n ${locationBlock(r.locations)}\n </div>`;\n}\n\nfunction partitionResults(report: AuditReport): {\n opportunities: RuleResultEntry[];\n diagnostics: Record<Category, RuleResultEntry[]>;\n passed: Record<Category, RuleResultEntry[]>;\n} {\n const opportunities: RuleResultEntry[] = [];\n const diagnostics: Record<Category, RuleResultEntry[]> = {\n crawler: [],\n 'structured-data': [],\n citation: [],\n content: [],\n };\n const passed: Record<Category, RuleResultEntry[]> = {\n crawler: [],\n 'structured-data': [],\n citation: [],\n content: [],\n };\n for (const cat of Object.keys(report.categories) as Category[]) {\n for (const r of report.categories[cat].results) {\n if (r.status === 'pass') {\n passed[cat].push(r);\n } else if (r.group === 'opportunity') {\n opportunities.push(r);\n } else {\n diagnostics[cat].push(r);\n }\n }\n }\n\n opportunities.sort((a, b) => {\n const ai = a.estimatedImpact ?? (1 - a.score) * a.weight;\n const bi = b.estimatedImpact ?? (1 - b.score) * b.weight;\n if (bi !== ai) return bi - ai;\n const aw = IMPACT_ORDER[a.impact ?? 'low'];\n const bw = IMPACT_ORDER[b.impact ?? 'low'];\n return bw - aw;\n });\n\n return { opportunities, diagnostics, passed };\n}\n\nfunction renderOpportunities(list: RuleResultEntry[]): string {\n if (list.length === 0) return '';\n return `<section class=\"section\">\n <h2>Opportunities <span class=\"count\">${list.length}</span></h2>\n <p class=\"section-hint\">Highest-leverage fixes first — sorted by estimated points recovered.</p>\n <div class=\"audits\">${list.map(auditRow).join('')}</div>\n </section>`;\n}\n\nfunction renderDiagnostics(groups: Record<Category, RuleResultEntry[]>): string {\n const total = Object.values(groups).reduce((n, arr) => n + arr.length, 0);\n if (total === 0) return '';\n const blocks = (Object.keys(groups) as Category[])\n .filter((c) => groups[c].length > 0)\n .map(\n (c) => `<div class=\"cat-block\">\n <h3>${esc(CATEGORY_LABELS[c])} <span class=\"count\">${groups[c].length}</span></h3>\n <div class=\"audits\">${groups[c].map(auditRow).join('')}</div>\n </div>`,\n )\n .join('');\n return `<section class=\"section\">\n <h2>Diagnostics <span class=\"count\">${total}</span></h2>\n <p class=\"section-hint\">More information about what's wrong, grouped by category.</p>\n ${blocks}\n </section>`;\n}\n\nfunction renderPassed(groups: Record<Category, RuleResultEntry[]>): string {\n const total = Object.values(groups).reduce((n, arr) => n + arr.length, 0);\n if (total === 0) return '';\n const blocks = (Object.keys(groups) as Category[])\n .filter((c) => groups[c].length > 0)\n .map(\n (c) => `<div class=\"cat-block\">\n <h3>${esc(CATEGORY_LABELS[c])} <span class=\"count\">${groups[c].length}</span></h3>\n <div class=\"audits\">${groups[c].map(auditRow).join('')}</div>\n </div>`,\n )\n .join('');\n return `<section class=\"section\">\n <details>\n <summary><h2 class=\"inline\">Passed audits <span class=\"count\">${total}</span></h2></summary>\n ${blocks}\n </details>\n </section>`;\n}\n\nfunction renderWarnings(warnings: string[]): string {\n if (warnings.length === 0) return '';\n const items = warnings.map((w) => `<li>${esc(w)}</li>`).join('');\n return `<section class=\"warnings\"><ul>${items}</ul></section>`;\n}\n\nfunction renderRings(report: AuditReport): string {\n const catRings = (Object.keys(report.categories) as Category[])\n .filter((c) => report.categories[c].results.length > 0)\n .map((c) => ring(report.categories[c].score, CATEGORY_LABELS[c], 96))\n .join('');\n return `<section class=\"rings\">\n <div class=\"rings-overall\">${ring(report.overall, 'Overall', 160)}</div>\n <div class=\"rings-cats\">${catRings}</div>\n </section>`;\n}\n\nfunction renderJsonBlock(report: AuditReport): string {\n const json = JSON.stringify(report, null, 2).replace(/<\\/script/g, '<\\\\/script');\n return `<section class=\"section\">\n <details>\n <summary><h2 class=\"inline\">Report JSON</h2></summary>\n <p class=\"section-hint\">The raw report, as emitted by <code>--json</code>.</p>\n <pre class=\"json-blob\" id=\"geo-json\">${esc(JSON.stringify(report, null, 2))}</pre>\n </details>\n <script type=\"application/json\" id=\"geo-report-data\">${json}</script>\n </section>`;\n}\n\nconst STYLES = `\n:root {\n color-scheme: light dark;\n --bg: #0b0d10;\n --panel: #141820;\n --panel-2: #1b2029;\n --border: #252b36;\n --fg: #e7ecf3;\n --fg-dim: #9aa6b2;\n --good: #17c27b;\n --avg: #f5b042;\n --poor: #ef476f;\n --accent: #5e9df8;\n --snippet: #0f1218;\n}\n@media (prefers-color-scheme: light) {\n :root {\n --bg: #fafbfc;\n --panel: #ffffff;\n --panel-2: #f3f5f9;\n --border: #e3e7ee;\n --fg: #1a222c;\n --fg-dim: #5a6572;\n --snippet: #f4f6fa;\n }\n}\n* { box-sizing: border-box; }\nhtml, body { margin: 0; padding: 0; }\nbody {\n font: 14px/1.55 ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif;\n background: var(--bg);\n color: var(--fg);\n}\n.wrap { max-width: 1100px; margin: 0 auto; padding: 32px 24px 64px; }\nheader.hdr {\n display: flex; justify-content: space-between; align-items: flex-start; gap: 16px;\n padding-bottom: 24px; border-bottom: 1px solid var(--border);\n}\n.hdr-main h1 { font-size: 20px; margin: 0 0 6px; letter-spacing: -0.01em; }\n.hdr-main h1 .brand { color: var(--fg-dim); font-weight: 500; }\n.url { word-break: break-all; color: var(--fg); }\n.hdr-meta { color: var(--fg-dim); font-size: 12px; margin-top: 8px; display: flex; gap: 14px; flex-wrap: wrap; }\n.hdr-meta code { background: var(--panel-2); padding: 1px 6px; border-radius: 4px; }\n.hdr-actions { display: flex; gap: 8px; }\n.btn {\n background: var(--panel); color: var(--fg); border: 1px solid var(--border);\n padding: 6px 12px; border-radius: 6px; font: inherit; cursor: pointer;\n}\n.btn:hover { border-color: var(--accent); color: var(--accent); }\n\n.rings {\n display: grid; grid-template-columns: auto 1fr; gap: 32px; align-items: center;\n margin: 28px 0 32px; padding: 24px; border-radius: 12px; background: var(--panel);\n border: 1px solid var(--border);\n}\n.rings-cats { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 16px; }\n.ring { display: grid; justify-items: center; gap: 4px; position: relative; }\n.ring svg { transform: rotate(-90deg); }\n.ring-track { fill: none; stroke: var(--panel-2); stroke-width: 8; }\n.ring-value { fill: none; stroke-width: 8; stroke-linecap: round; transition: stroke-dashoffset .5s ease; }\n.ring-good .ring-value { stroke: var(--good); }\n.ring-avg .ring-value { stroke: var(--avg); }\n.ring-poor .ring-value { stroke: var(--poor); }\n.ring-num {\n position: absolute; top: 50%; left: 50%; transform: translate(-50%, -65%);\n font-weight: 700; font-size: 28px; letter-spacing: -0.02em;\n}\n.rings-overall .ring-num { font-size: 44px; }\n.ring-label { color: var(--fg-dim); font-size: 12px; }\n\n.warnings {\n background: color-mix(in srgb, var(--avg) 12%, transparent);\n border: 1px solid color-mix(in srgb, var(--avg) 40%, var(--border));\n border-radius: 8px; padding: 12px 16px; margin-bottom: 24px;\n}\n.warnings ul { margin: 0; padding-left: 20px; }\n\n.section { margin: 28px 0; }\n.section h2 { font-size: 18px; margin: 0 0 6px; letter-spacing: -0.01em; }\n.section .section-hint { color: var(--fg-dim); font-size: 13px; margin: 0 0 14px; }\n.section h2.inline { display: inline-block; margin: 0; cursor: pointer; }\ndetails > summary { list-style: none; cursor: pointer; }\ndetails > summary::-webkit-details-marker { display: none; }\ndetails > summary::before { content: \"▸ \"; color: var(--fg-dim); }\ndetails[open] > summary::before { content: \"▾ \"; }\n\n.count {\n display: inline-block; background: var(--panel-2); color: var(--fg-dim);\n font-size: 11px; padding: 1px 8px; border-radius: 999px; margin-left: 6px; vertical-align: middle;\n}\n\n.cat-block { margin: 14px 0; }\n.cat-block h3 { font-size: 14px; color: var(--fg-dim); font-weight: 600; margin: 18px 0 8px; }\n\n.audits { display: grid; gap: 10px; }\n.audit {\n background: var(--panel); border: 1px solid var(--border); border-radius: 10px;\n padding: 12px 14px;\n}\n.audit-fail { border-left: 3px solid var(--poor); }\n.audit-warn { border-left: 3px solid var(--avg); }\n.audit-skip { opacity: 0.7; }\n.audit-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }\n.audit-title { font-weight: 600; flex: 1 1 auto; min-width: 0; }\n.audit-score { color: var(--fg-dim); font-variant-numeric: tabular-nums; font-size: 12px; }\n.audit-id { color: var(--fg-dim); font-size: 11px; margin-top: 4px; }\n.audit-id code { background: transparent; color: var(--fg-dim); }\n.audit-rationale { margin-top: 8px; color: var(--fg); }\n.fix-hint { margin-top: 6px; color: var(--accent); font-size: 13px; }\n.docs { color: var(--accent); text-decoration: none; font-size: 12px; margin-left: auto; }\n.docs:hover { text-decoration: underline; }\n\n.chip {\n display: inline-block; font-size: 11px; padding: 1px 8px; border-radius: 999px;\n border: 1px solid var(--border); background: var(--panel-2); color: var(--fg-dim);\n text-transform: lowercase; letter-spacing: 0.02em;\n}\n.chip-pass { color: var(--good); border-color: color-mix(in srgb, var(--good) 40%, var(--border)); }\n.chip-warn { color: var(--avg); border-color: color-mix(in srgb, var(--avg) 40%, var(--border)); }\n.chip-fail { color: var(--poor); border-color: color-mix(in srgb, var(--poor) 40%, var(--border)); }\n.chip-impact-critical, .chip-impact-high { color: var(--poor); border-color: color-mix(in srgb, var(--poor) 40%, var(--border)); }\n.chip-impact-medium { color: var(--avg); border-color: color-mix(in srgb, var(--avg) 40%, var(--border)); }\n.chip-est { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 40%, var(--border)); }\n\n.locations { list-style: none; padding: 0; margin: 10px 0 0; display: grid; gap: 6px; }\n.loc { border: 1px solid var(--border); border-radius: 6px; padding: 6px 8px; background: var(--panel-2); }\n.loc-head { color: var(--fg-dim); font-size: 12px; }\n.loc-head .sel { background: transparent; color: var(--accent); padding: 0; }\n.snippet, .json-blob {\n font-family: ui-monospace, \"SF Mono\", Menlo, Consolas, monospace; font-size: 12px;\n background: var(--snippet); padding: 10px 12px; border-radius: 6px;\n white-space: pre-wrap; word-break: break-word; margin: 6px 0 0; max-height: 320px; overflow: auto;\n}\n.json-blob { max-height: 480px; }\n\nfooter.ftr {\n margin-top: 48px; padding-top: 16px; border-top: 1px solid var(--border);\n color: var(--fg-dim); font-size: 12px; display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap;\n}\n`;\n\nconst SCRIPT = `\n(function () {\n var btn = document.getElementById('copy-json');\n var data = document.getElementById('geo-report-data');\n if (!btn || !data) return;\n btn.addEventListener('click', function () {\n var payload = data.textContent || '';\n if (navigator.clipboard && navigator.clipboard.writeText) {\n navigator.clipboard.writeText(payload).then(function () {\n btn.textContent = 'Copied ✓';\n setTimeout(function () { btn.textContent = 'Copy JSON'; }, 1200);\n }).catch(function () { fallback(); });\n } else { fallback(); }\n function fallback() {\n var ta = document.createElement('textarea');\n ta.value = payload; document.body.appendChild(ta);\n ta.select(); try { document.execCommand('copy'); } catch (e) {}\n document.body.removeChild(ta);\n btn.textContent = 'Copied ✓';\n setTimeout(function () { btn.textContent = 'Copy JSON'; }, 1200);\n }\n });\n})();\n`;\n\nexport function toHtml(report: AuditReport): string {\n const { opportunities, diagnostics, passed } = partitionResults(report);\n const title = `geo-checker · ${esc(report.finalUrl)}`;\n const timingLine = `fetch ${report.timing.fetchMs}ms · audit ${report.timing.auditMs}ms · total ${report.timing.totalMs}ms`;\n\n const body = `<div class=\"wrap\">\n <header class=\"hdr\">\n <div class=\"hdr-main\">\n <h1><span class=\"brand\">geo-checker</span> · <span class=\"url\">${esc(report.finalUrl)}</span></h1>\n <div class=\"hdr-meta\">\n <span>mode: <code>${esc(report.renderMode)}</code></span>\n <span>fetched: <code>${esc(report.fetchedAt)}</code></span>\n <span>tool: <code>v${esc(report.meta.toolVersion)}</code></span>\n <span>node: <code>${esc(report.meta.nodeVersion)}</code></span>\n <span>${timingLine}</span>\n </div>\n </div>\n <div class=\"hdr-actions\">\n <button class=\"btn\" id=\"copy-json\" type=\"button\">Copy JSON</button>\n </div>\n </header>\n\n ${renderRings(report)}\n ${renderWarnings(report.warnings)}\n ${renderOpportunities(opportunities)}\n ${renderDiagnostics(diagnostics)}\n ${renderPassed(passed)}\n ${renderJsonBlock(report)}\n\n <footer class=\"ftr\">\n <span>Generated by geo-checker v${esc(report.meta.toolVersion)}</span>\n <span>Schema v${report.schemaVersion}</span>\n </footer>\n </div>`;\n\n return `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n<meta name=\"generator\" content=\"geo-checker v${esc(report.meta.toolVersion)}\" />\n<title>${title}</title>\n<style>${STYLES}</style>\n</head>\n<body>\n${body}\n<script>${SCRIPT}</script>\n</body>\n</html>\n`;\n}\n"],"mappings":"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","names":["import_promises","import_node_path","import_kleur","cheerioLoad","defaultRules","before","after","CATEGORY_LABELS","kleur","Table","CATEGORY_LABELS","impactChip","resolvePath","kleur"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/context.ts","../src/fetcher/static.ts","../src/fetcher/rendered.ts","../src/fetcher/robots.ts","../src/fetcher/llms-txt.ts","../src/fetcher/sitemap.ts","../src/types.ts","../src/engine.ts","../src/rules/crawler/https.ts","../src/rules/crawler/robots-reachable.ts","../src/rules/crawler/robots-ai-allow.ts","../src/rules/crawler/llms-txt-present.ts","../src/rules/crawler/llms-txt-wellformed.ts","../src/rules/crawler/llms-full-txt.ts","../src/rules/crawler/sitemap-present.ts","../src/rules/crawler/index.ts","../src/rules/structured-data/jsonld-present.ts","../src/rules/util.ts","../src/rules/structured-data/jsonld-valid-json.ts","../src/rules/structured-data/schema-type-recognized.ts","../src/rules/structured-data/required-fields.ts","../src/rules/structured-data/microdata-fallback.ts","../src/rules/structured-data/no-duplicate-types.ts","../src/rules/structured-data/sameas-entity.ts","../src/rules/structured-data/breadcrumb-valid.ts","../src/rules/structured-data/index.ts","../src/rules/citation/title.ts","../src/rules/citation/meta-description.ts","../src/rules/citation/canonical.ts","../src/rules/citation/og-tags.ts","../src/rules/citation/twitter-card.ts","../src/rules/citation/lang-attr.ts","../src/rules/citation/author-visible.ts","../src/rules/citation/dates.ts","../src/rules/citation/content-freshness.ts","../src/rules/citation/index.ts","../src/rules/content/single-h1.ts","../src/rules/content/heading-hierarchy.ts","../src/rules/content/image-alt.ts","../src/rules/content/tldr-or-faq.ts","../src/rules/content/word-count.ts","../src/rules/content/qa-structure.ts","../src/rules/content/external-citations.ts","../src/rules/content/index.ts","../src/rules/aeo/skill-md.ts","../src/rules/aeo/agent-permissions.ts","../src/rules/aeo/token-length.ts","../src/rules/aeo/index.ts","../src/rules/index.ts","../src/config.ts","../src/batch.ts","../src/reporters/csv.ts","../src/reporters/markdown.ts","../src/reporters/sarif.ts","../src/reporters/diff.ts","../src/index.ts","../src/reporters/json.ts","../src/reporters/cli.ts","../src/reporters/html.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, resolve as resolvePath } from 'node:path';\nimport { cac } from 'cac';\nimport kleur from 'kleur';\nimport { audit } from './index.js';\nimport { toJson } from './reporters/json.js';\nimport { toCli } from './reporters/cli.js';\nimport { toHtml } from './reporters/html.js';\nimport { toCsv } from './reporters/csv.js';\nimport { toMarkdown } from './reporters/markdown.js';\nimport { toSarif } from './reporters/sarif.js';\nimport { diffReports, formatDiffLine } from './reporters/diff.js';\nimport { findConfig } from './config.js';\nimport { runBatch, summaryToJson, urlToSlug, type BatchProgressEvent } from './batch.js';\nimport type { Category, Status, AuditReport } from './types.js';\n\nconst pkgVersion = '0.3.0';\n\nconst VALID_CATEGORIES: Category[] = ['crawler', 'structured-data', 'citation', 'content'];\n\ntype FailOn = 'fail' | 'warn';\n\ninterface CliFlags {\n json?: boolean;\n html?: string;\n out?: string;\n csv?: string;\n md?: string;\n sarif?: string;\n baseline?: string;\n config?: string;\n render?: boolean;\n category?: string;\n only?: string;\n failOn?: FailOn;\n timeout?: string | number;\n}\n\ninterface BatchFlags {\n out?: string;\n concurrency?: string | number;\n config?: string;\n render?: boolean;\n category?: string;\n only?: string;\n timeout?: string | number;\n}\n\nasync function writeReportFile(path: string, content: string): Promise<void> {\n const abs = resolvePath(path);\n await mkdir(dirname(abs), { recursive: true });\n await writeFile(abs, content, 'utf8');\n}\n\nfunction parseCategories(raw?: string): Category[] | undefined {\n if (!raw) return undefined;\n const items = raw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n const valid = items.filter((c): c is Category => (VALID_CATEGORIES as string[]).includes(c));\n const invalid = items.filter((c) => !(VALID_CATEGORIES as string[]).includes(c));\n if (invalid.length > 0) {\n throw new Error(`Unknown category: ${invalid.join(', ')}. Valid: ${VALID_CATEGORIES.join(', ')}.`);\n }\n return valid;\n}\n\nfunction parseOnly(raw?: string): string[] | undefined {\n if (!raw) return undefined;\n return raw.split(',').map((s) => s.trim()).filter(Boolean);\n}\n\nfunction worstStatus(report: AuditReport): Status {\n let worst: Status = 'pass';\n const order: Record<Status, number> = { pass: 0, skip: 0, warn: 1, fail: 2 };\n for (const cat of Object.values(report.categories)) {\n for (const r of cat.results) {\n if (order[r.status] > order[worst]) worst = r.status;\n }\n }\n return worst;\n}\n\nasync function resolveConfigPath(explicit: string | undefined): Promise<string | null> {\n if (explicit) return resolvePath(explicit);\n return findConfig(process.cwd());\n}\n\nasync function readBaseline(path: string): Promise<AuditReport> {\n const raw = await readFile(resolvePath(path), 'utf8');\n return JSON.parse(raw) as AuditReport;\n}\n\nfunction parseIntOr<T>(raw: string | number | undefined, fallback: T): number | T {\n if (raw === undefined) return fallback;\n const n = typeof raw === 'string' ? parseInt(raw, 10) : raw;\n return Number.isNaN(n) ? fallback : n;\n}\n\nconst cli = cac('geo-checker');\n\ncli\n .command('<url>', 'Audit a URL for GEO (Generative Engine Optimization) readiness')\n .option('--json', 'Output a JSON report to stdout')\n .option('--html <path>', 'Write a standalone HTML report to <path> (use - for stdout)')\n .option('--csv <path>', 'Write a flat CSV report (one row per rule result)')\n .option('--md <path>', 'Write a Markdown PR-comment summary')\n .option('--sarif <path>', 'Write a SARIF 2.1.0 report (for GitHub Code Scanning)')\n .option('--out <dir>', 'Write report.json + report.html to <dir>')\n .option('--baseline <path>', 'Compare against a prior JSON report and print deltas')\n .option('--config <path>', 'Load a geo-checker config file (overrides rule weights, disables rules, etc.)')\n .option('--render', 'Use a headless browser (requires optional playwright dependency)')\n .option('--category <names>', 'Run only the given categories (comma-separated)')\n .option('--only <ids>', 'Run only the given rule IDs (comma-separated)')\n .option('--fail-on <level>', 'Exit non-zero when a result is at or above this level (warn|fail)', {\n default: 'fail',\n })\n .option('--timeout <ms>', 'Per-request timeout in milliseconds', { default: 20000 })\n .action(async (url: string, flags: CliFlags) => {\n const categories = parseCategories(flags.category);\n const only = parseOnly(flags.only);\n const timeoutMs = parseIntOr(flags.timeout, undefined);\n const configPath = await resolveConfigPath(flags.config);\n\n const report = await audit(url, {\n ...(flags.render ? { render: true } : {}),\n ...(categories ? { categories } : {}),\n ...(only ? { only } : {}),\n ...(typeof timeoutMs === 'number' ? { timeoutMs } : {}),\n ...(configPath ? { configPath } : {}),\n });\n\n const wroteFile =\n Boolean(flags.out) ||\n (flags.html && flags.html !== '-') ||\n Boolean(flags.csv) ||\n Boolean(flags.md) ||\n Boolean(flags.sarif);\n\n if (flags.out) {\n const dir = flags.out;\n await writeReportFile(resolvePath(dir, 'report.json'), toJson(report));\n await writeReportFile(resolvePath(dir, 'report.html'), toHtml(report));\n process.stderr.write(kleur.gray(`wrote ${resolvePath(dir, 'report.json')}\\n`));\n process.stderr.write(kleur.gray(`wrote ${resolvePath(dir, 'report.html')}\\n`));\n }\n\n if (flags.html) {\n if (flags.html === '-') {\n process.stdout.write(toHtml(report));\n } else {\n await writeReportFile(flags.html, toHtml(report));\n process.stderr.write(kleur.gray(`wrote ${resolvePath(flags.html)}\\n`));\n }\n }\n\n if (flags.csv) {\n await writeReportFile(flags.csv, toCsv(report));\n process.stderr.write(kleur.gray(`wrote ${resolvePath(flags.csv)}\\n`));\n }\n\n if (flags.md) {\n await writeReportFile(flags.md, toMarkdown(report));\n process.stderr.write(kleur.gray(`wrote ${resolvePath(flags.md)}\\n`));\n }\n\n if (flags.sarif) {\n await writeReportFile(flags.sarif, toSarif(report));\n process.stderr.write(kleur.gray(`wrote ${resolvePath(flags.sarif)}\\n`));\n }\n\n if (flags.baseline) {\n try {\n const prior = await readBaseline(flags.baseline);\n const diff = diffReports(prior, report);\n process.stderr.write(kleur.bold('baseline ') + formatDiffLine(diff) + '\\n');\n } catch (err) {\n process.stderr.write(\n kleur.yellow(`! baseline comparison failed: ${err instanceof Error ? err.message : err}\\n`),\n );\n }\n }\n\n if (flags.json) {\n process.stdout.write(toJson(report) + '\\n');\n } else if (!wroteFile && flags.html !== '-') {\n process.stdout.write(toCli(report) + '\\n');\n }\n\n const worst = worstStatus(report);\n const failOn: FailOn = flags.failOn === 'warn' ? 'warn' : 'fail';\n if (failOn === 'fail' && worst === 'fail') process.exit(1);\n if (failOn === 'warn' && (worst === 'warn' || worst === 'fail')) process.exit(1);\n });\n\ncli\n .command('batch <file>', 'Audit every URL in <file> (one URL per line) and write individual reports')\n .option('--out <dir>', 'Output directory for per-URL reports and summary.json', { default: './geo-checker-batch' })\n .option('--concurrency <n>', 'Number of URLs to audit in parallel', { default: 4 })\n .option('--config <path>', 'Config file (see top-level --config)')\n .option('--render', 'Use a headless browser for each URL')\n .option('--category <names>', 'Run only the given categories (comma-separated)')\n .option('--only <ids>', 'Run only the given rule IDs (comma-separated)')\n .option('--timeout <ms>', 'Per-request timeout in milliseconds', { default: 20000 })\n .action(async (file: string, flags: BatchFlags) => {\n const raw = await readFile(resolvePath(file), 'utf8');\n const urls = raw\n .split(/\\r?\\n/)\n .map((l) => l.trim())\n .filter((l) => l && !l.startsWith('#'));\n if (urls.length === 0) {\n process.stderr.write(kleur.red('No URLs found in input file.\\n'));\n process.exit(1);\n }\n const outDir = resolvePath(flags.out ?? './geo-checker-batch');\n await mkdir(outDir, { recursive: true });\n\n const concurrency = parseIntOr(flags.concurrency, 4);\n const categories = parseCategories(flags.category);\n const only = parseOnly(flags.only);\n const timeoutMs = parseIntOr(flags.timeout, undefined);\n const configPath = await resolveConfigPath(flags.config);\n\n const onProgress = (e: BatchProgressEvent): void => {\n if (e.kind === 'start') {\n process.stderr.write(kleur.gray(`[${e.index + 1}/${e.total}] ${e.url}\\n`));\n } else if (e.kind === 'success') {\n process.stderr.write(kleur.green(` ✓ ${e.overall}/100\\n`));\n } else {\n process.stderr.write(kleur.red(` ✗ ${e.error}\\n`));\n }\n };\n\n const summary = await runBatch(urls, {\n concurrency: typeof concurrency === 'number' ? concurrency : 4,\n ...(flags.render ? { render: true } : {}),\n ...(categories ? { categories } : {}),\n ...(only ? { only } : {}),\n ...(typeof timeoutMs === 'number' ? { timeoutMs } : {}),\n ...(configPath ? { configPath } : {}),\n onProgress,\n });\n\n for (const r of summary.results) {\n if (!r.ok) continue;\n const slug = urlToSlug(r.url);\n await writeFile(resolvePath(outDir, `${slug}.json`), toJson(r.report), 'utf8');\n await writeFile(resolvePath(outDir, `${slug}.html`), toHtml(r.report), 'utf8');\n }\n await writeFile(resolvePath(outDir, 'summary.json'), summaryToJson(summary), 'utf8');\n process.stderr.write(\n kleur.bold(\n `\\nBatch done: ${summary.successes}/${summary.total} succeeded · avg ${summary.averageOverall} · written to ${outDir}\\n`,\n ),\n );\n if (summary.failures > 0) process.exit(1);\n });\n\ncli.help();\ncli.version(pkgVersion);\n\nasync function main() {\n cli.parse(process.argv, { run: false });\n await cli.runMatchedCommand();\n}\n\nmain().catch((err) => {\n console.error(kleur.red('geo-checker crashed:'), err instanceof Error ? err.message : err);\n process.exit(2);\n});\n","import { load as cheerioLoad, type CheerioAPI } from 'cheerio';\nimport type { AuditContext } from './types.js';\nimport { fetchStatic, fetchText } from './fetcher/static.js';\nimport { fetchRendered } from './fetcher/rendered.js';\nimport { parseRobots } from './fetcher/robots.js';\nimport { parseLlmsTxt } from './fetcher/llms-txt.js';\nimport { parseSitemap } from './fetcher/sitemap.js';\n\nexport interface BuildContextOptions {\n userAgent?: string;\n timeoutMs?: number;\n render?: boolean;\n}\n\nfunction extractJsonLd($: CheerioAPI): unknown[] {\n const blocks: unknown[] = [];\n $('script[type=\"application/ld+json\"]').each((_i, el) => {\n const txt = $(el).contents().text().trim();\n if (!txt) return;\n try {\n const parsed = JSON.parse(txt);\n if (Array.isArray(parsed)) blocks.push(...parsed);\n else blocks.push(parsed);\n } catch {\n blocks.push({ __parseError: true, raw: txt.slice(0, 200) });\n }\n });\n return blocks;\n}\n\nfunction detectSpa($: CheerioAPI): boolean {\n const bodyText = $('body').clone().find('script, style, noscript').remove().end().text().replace(/\\s+/g, ' ').trim();\n if (bodyText.length >= 500) return false;\n const roots = $('#__next, #root, #app, [data-reactroot], [ng-app], [data-server-rendered]');\n return roots.length > 0;\n}\n\nexport async function buildContext(url: string, opts: BuildContextOptions = {}): Promise<AuditContext> {\n const warnings: string[] = [];\n let finalUrl: string;\n let html: string;\n let headers: Record<string, string>;\n let status: number;\n let renderMode: 'static' | 'rendered';\n\n if (opts.render) {\n const page = await fetchRendered(url, opts);\n finalUrl = page.finalUrl;\n html = page.html;\n headers = page.headers;\n status = page.status;\n renderMode = 'rendered';\n } else {\n const page = await fetchStatic(url, opts);\n finalUrl = page.finalUrl;\n html = page.body;\n headers = page.headers;\n status = page.status;\n renderMode = 'static';\n }\n\n const $ = cheerioLoad(html);\n const origin = new URL(finalUrl).origin;\n\n if (renderMode === 'static' && detectSpa($)) {\n warnings.push(\n 'Site appears to be JS-rendered (sparse body + SPA root element). Re-run with --render for accurate results.',\n );\n }\n\n const [robotsRaw, llmsRaw, llmsFullRaw, skillMdRaw, agentPermissionsRaw] = await Promise.all([\n fetchText(`${origin}/robots.txt`, opts),\n fetchText(`${origin}/llms.txt`, opts),\n fetchText(`${origin}/llms-full.txt`, opts),\n fetchText(`${origin}/skill.md`, opts),\n fetchText(`${origin}/agent-permissions.json`, opts),\n ]);\n\n let sitemapUrl: string | null = null;\n const robots = robotsRaw ? parseRobots(robotsRaw) : null;\n if (robots && robots.sitemaps.length > 0) sitemapUrl = robots.sitemaps[0] ?? null;\n if (!sitemapUrl) sitemapUrl = `${origin}/sitemap.xml`;\n\n const sitemapRaw = await fetchText(sitemapUrl, opts);\n const sitemap = sitemapRaw ? parseSitemap(sitemapRaw) : null;\n\n let agentPermissions: unknown | null = null;\n if (agentPermissionsRaw && agentPermissionsRaw.trim().length > 0) {\n try { agentPermissions = JSON.parse(agentPermissionsRaw); } catch { /* invalid JSON */ }\n }\n\n return {\n url,\n finalUrl,\n html,\n $,\n headers,\n status,\n robots,\n llmsTxt: llmsRaw ? parseLlmsTxt(llmsRaw) : null,\n llmsFullTxt: llmsFullRaw && llmsFullRaw.trim().length > 0 ? llmsFullRaw : null,\n sitemap,\n jsonLd: extractJsonLd($),\n renderMode,\n fetchedAt: new Date().toISOString(),\n warnings,\n skillMd: skillMdRaw && skillMdRaw.trim().length > 0 ? skillMdRaw : null,\n agentPermissions,\n };\n}\n\nexport const buildStaticContext = buildContext;\n","import { request } from 'undici';\n\nexport const DEFAULT_UA = 'geo-checker/0.1.0 (+https://github.com/BaRam-OSS/geo-checker)';\n\nexport interface StaticFetchOptions {\n userAgent?: string;\n timeoutMs?: number;\n maxRedirects?: number;\n accept?: string;\n}\n\nexport interface StaticFetchResult {\n finalUrl: string;\n status: number;\n headers: Record<string, string>;\n body: string;\n redirectCount: number;\n}\n\nfunction normalizeHeaders(input: Record<string, string | string[] | undefined>): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(input)) {\n if (v == null) continue;\n out[k.toLowerCase()] = Array.isArray(v) ? v.join(', ') : v;\n }\n return out;\n}\n\nexport async function fetchStatic(url: string, opts: StaticFetchOptions = {}): Promise<StaticFetchResult> {\n const maxRedirects = opts.maxRedirects ?? 5;\n const timeout = opts.timeoutMs ?? 20_000;\n const userAgent = opts.userAgent ?? DEFAULT_UA;\n const accept = opts.accept ?? 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8';\n\n let current = url;\n let redirects = 0;\n\n for (;;) {\n const res = await request(current, {\n method: 'GET',\n headers: {\n 'user-agent': userAgent,\n accept,\n 'accept-language': 'en,*',\n },\n bodyTimeout: timeout,\n headersTimeout: timeout,\n });\n\n const status = res.statusCode;\n const headers = normalizeHeaders(res.headers as Record<string, string | string[] | undefined>);\n\n if (status >= 300 && status < 400 && headers.location && redirects < maxRedirects) {\n redirects += 1;\n current = new URL(headers.location, current).toString();\n await res.body.dump();\n continue;\n }\n\n const body = await res.body.text();\n return { finalUrl: current, status, headers, body, redirectCount: redirects };\n }\n}\n\nexport async function fetchText(url: string, opts: StaticFetchOptions = {}): Promise<string | null> {\n try {\n const res = await fetchStatic(url, opts);\n if (res.status >= 200 && res.status < 300) return res.body;\n return null;\n } catch {\n return null;\n }\n}\n","import type * as PlaywrightNs from 'playwright';\nimport { DEFAULT_UA } from './static.js';\n\nexport interface RenderedResult {\n finalUrl: string;\n html: string;\n status: number;\n headers: Record<string, string>;\n}\n\nexport interface RenderedOptions {\n userAgent?: string;\n timeoutMs?: number;\n}\n\nexport async function fetchRendered(url: string, opts: RenderedOptions = {}): Promise<RenderedResult> {\n let playwright: typeof PlaywrightNs;\n try {\n playwright = (await import('playwright')) as typeof PlaywrightNs;\n } catch {\n throw new Error(\n 'Playwright is required for --render. Install with: npm i -D playwright && npx playwright install chromium',\n );\n }\n\n const userAgent = opts.userAgent ?? DEFAULT_UA;\n const timeout = opts.timeoutMs ?? 30_000;\n\n const browser = await playwright.chromium.launch({ headless: true });\n try {\n const ctx = await browser.newContext({ userAgent });\n const page = await ctx.newPage();\n const response = await page.goto(url, { waitUntil: 'networkidle', timeout });\n const html = await page.content();\n const finalUrl = page.url();\n const status = response?.status() ?? 200;\n const headers = response ? await response.allHeaders() : {};\n return { finalUrl, html, status, headers };\n } finally {\n await browser.close();\n }\n}\n","import type { RobotsTxt, RobotsRuleGroup } from '../types.js';\n\nexport function parseRobots(raw: string): RobotsTxt {\n const groups: RobotsRuleGroup[] = [];\n const sitemaps: string[] = [];\n let current: RobotsRuleGroup | null = null;\n\n const lines = raw.split(/\\r?\\n/);\n for (const rawLine of lines) {\n const line = rawLine.replace(/#.*$/, '').trim();\n if (!line) continue;\n const idx = line.indexOf(':');\n if (idx === -1) continue;\n const field = line.slice(0, idx).trim().toLowerCase();\n const value = line.slice(idx + 1).trim();\n\n if (field === 'user-agent') {\n if (!current || current.allow.length > 0 || current.disallow.length > 0) {\n current = { userAgent: value, allow: [], disallow: [] };\n groups.push(current);\n } else {\n current.userAgent = value;\n }\n } else if (field === 'allow' && current) {\n current.allow.push(value);\n } else if (field === 'disallow' && current) {\n current.disallow.push(value);\n } else if (field === 'sitemap') {\n sitemaps.push(value);\n }\n }\n\n return { raw, groups, sitemaps };\n}\n\nexport function matchGroup(robots: RobotsTxt, userAgent: string): RobotsRuleGroup | null {\n const lower = userAgent.toLowerCase();\n const exact = robots.groups.find((g) => g.userAgent.toLowerCase() === lower);\n if (exact) return exact;\n const wildcard = robots.groups.find((g) => g.userAgent === '*');\n return wildcard ?? null;\n}\n\nexport function isPathAllowed(group: RobotsRuleGroup | null, path: string): boolean {\n if (!group) return true;\n const matches = (pattern: string): number => {\n if (pattern === '') return -1;\n if (path.startsWith(pattern)) return pattern.length;\n return -1;\n };\n let bestAllow = -1;\n let bestDisallow = -1;\n for (const p of group.allow) bestAllow = Math.max(bestAllow, matches(p));\n for (const p of group.disallow) bestDisallow = Math.max(bestDisallow, matches(p));\n if (bestDisallow === -1) return true;\n return bestAllow >= bestDisallow;\n}\n","import type { LlmsTxt, LlmsTxtLink, LlmsTxtSection } from '../types.js';\n\nconst LINK_RE = /^\\s*-\\s*\\[([^\\]]+)\\]\\(([^)]+)\\)\\s*(?::\\s*(.+))?\\s*$/;\n\nexport function parseLlmsTxt(raw: string): LlmsTxt {\n const lines = raw.split(/\\r?\\n/);\n\n let title: string | null = null;\n let summary: string | null = null;\n const sections: LlmsTxtSection[] = [];\n let currentSection: LlmsTxtSection | null = null;\n const summaryParts: string[] = [];\n let inSummaryPhase = false;\n\n for (const line of lines) {\n if (/^#\\s+/.test(line) && title === null) {\n title = line.replace(/^#\\s+/, '').trim();\n inSummaryPhase = true;\n continue;\n }\n if (/^##\\s+/.test(line)) {\n if (inSummaryPhase && summaryParts.length > 0) {\n summary = summaryParts.join(' ').trim();\n }\n inSummaryPhase = false;\n currentSection = { title: line.replace(/^##\\s+/, '').trim(), links: [] };\n sections.push(currentSection);\n continue;\n }\n\n if (inSummaryPhase) {\n const trimmed = line.trim();\n if (trimmed.startsWith('>')) {\n summaryParts.push(trimmed.replace(/^>\\s*/, ''));\n } else if (trimmed.length > 0) {\n summaryParts.push(trimmed);\n }\n continue;\n }\n\n if (currentSection) {\n const m = LINK_RE.exec(line);\n if (m) {\n const link: LlmsTxtLink = { title: m[1]!.trim(), url: m[2]!.trim() };\n if (m[3]) link.description = m[3].trim();\n currentSection.links.push(link);\n }\n }\n }\n\n if (inSummaryPhase && summary === null && summaryParts.length > 0) {\n summary = summaryParts.join(' ').trim();\n }\n\n return { raw, title, summary, sections };\n}\n\nexport function isLlmsTxtWellFormed(parsed: LlmsTxt): { ok: boolean; reason?: string } {\n if (!parsed.title) return { ok: false, reason: 'Missing H1 project title' };\n if (parsed.sections.length === 0) return { ok: false, reason: 'No H2 sections found' };\n const totalLinks = parsed.sections.reduce((n, s) => n + s.links.length, 0);\n if (totalLinks === 0) return { ok: false, reason: 'No link items found under any section' };\n return { ok: true };\n}\n","import type { SitemapSummary } from '../types.js';\n\nconst LOC_RE = /<loc>\\s*([^<\\s]+)\\s*<\\/loc>/gi;\nconst LASTMOD_RE = /<lastmod>\\s*([^<\\s]+)\\s*<\\/lastmod>/i;\n\nexport function parseSitemap(xml: string): SitemapSummary {\n const urls: string[] = [];\n let match: RegExpExecArray | null;\n const re = new RegExp(LOC_RE.source, LOC_RE.flags);\n while ((match = re.exec(xml)) !== null) {\n const url = match[1];\n if (url) urls.push(url);\n }\n const lastmodMatch = LASTMOD_RE.exec(xml);\n const summary: SitemapSummary = { urls };\n if (lastmodMatch?.[1]) summary.lastmod = lastmodMatch[1];\n return summary;\n}\n","import type { CheerioAPI } from 'cheerio';\n\nexport type Status = 'pass' | 'warn' | 'fail' | 'skip';\n\nexport type Category = 'crawler' | 'structured-data' | 'citation' | 'content' | 'aeo';\n\nexport interface RobotsRuleGroup {\n userAgent: string;\n allow: string[];\n disallow: string[];\n}\n\nexport interface RobotsTxt {\n raw: string;\n groups: RobotsRuleGroup[];\n sitemaps: string[];\n}\n\nexport interface LlmsTxtLink {\n title: string;\n url: string;\n description?: string;\n}\n\nexport interface LlmsTxtSection {\n title: string;\n links: LlmsTxtLink[];\n}\n\nexport interface LlmsTxt {\n raw: string;\n title: string | null;\n summary: string | null;\n sections: LlmsTxtSection[];\n}\n\nexport interface SitemapSummary {\n urls: string[];\n lastmod?: string;\n}\n\nexport interface AuditContext {\n url: string;\n finalUrl: string;\n html: string;\n $: CheerioAPI;\n headers: Record<string, string>;\n status: number;\n robots: RobotsTxt | null;\n llmsTxt: LlmsTxt | null;\n llmsFullTxt: string | null;\n sitemap: SitemapSummary | null;\n jsonLd: unknown[];\n renderMode: 'static' | 'rendered';\n fetchedAt: string;\n warnings: string[];\n skillMd: string | null;\n agentPermissions: unknown | null;\n}\n\nexport type Impact = 'critical' | 'high' | 'medium' | 'low';\nexport type Effort = 'low' | 'medium' | 'high';\nexport type RuleGroup = 'opportunity' | 'diagnostic' | 'info';\n\nexport interface EvidenceLocation {\n selector?: string;\n snippet?: string;\n line?: number;\n col?: number;\n}\n\nexport interface RuleResult {\n status: Status;\n score: number;\n rationale: string;\n rationale_ko?: string;\n evidence?: unknown;\n locations?: EvidenceLocation[];\n fixUrl?: string;\n fixHint?: string;\n estimatedImpact?: number;\n}\n\nexport interface Rule {\n id: string;\n stableId?: string;\n category: Category;\n group?: RuleGroup;\n weight: number;\n impact?: Impact;\n effort?: Effort;\n title: string;\n title_ko?: string;\n description: string;\n docsUrl?: string;\n run(ctx: AuditContext): Promise<RuleResult> | RuleResult;\n}\n\nexport interface RuleResultEntry extends RuleResult {\n id: string;\n stableId?: string;\n title: string;\n title_ko?: string;\n weight: number;\n group?: RuleGroup;\n impact?: Impact;\n effort?: Effort;\n docsUrl?: string;\n durationMs?: number;\n}\n\nexport interface CategoryReport {\n score: number;\n weight: number;\n results: RuleResultEntry[];\n}\n\nexport interface ReportMeta {\n toolVersion: string;\n nodeVersion: string;\n userAgent?: string;\n configPath?: string;\n}\n\nexport interface ReportTiming {\n fetchMs: number;\n auditMs: number;\n totalMs: number;\n}\n\nexport interface AuditReport {\n schemaVersion: 1;\n url: string;\n finalUrl: string;\n fetchedAt: string;\n renderMode: 'static' | 'rendered';\n overall: number;\n categories: Record<Category, CategoryReport>;\n warnings: string[];\n version: string;\n meta: ReportMeta;\n timing: ReportTiming;\n}\n\nexport interface RuleOverride {\n enabled?: boolean;\n weight?: number;\n}\n\nexport interface GeoConfig {\n extends?: 'default';\n rules?: Record<string, RuleOverride>;\n categories?: Partial<Record<Category, { weight?: number }>>;\n extraRules?: Rule[];\n}\n\nexport interface AuditOptions {\n render?: boolean;\n timeoutMs?: number;\n userAgent?: string;\n extraRules?: Rule[];\n only?: string[];\n categories?: Category[];\n config?: GeoConfig;\n configPath?: string;\n}\n\nexport function defineRule(rule: Rule): Rule {\n return rule;\n}\n\nexport const CATEGORY_WEIGHTS: Record<Category, number> = {\n crawler: 20,\n 'structured-data': 25,\n citation: 20,\n content: 15,\n aeo: 20,\n};\n","import type {\n AuditContext,\n AuditReport,\n Category,\n CategoryReport,\n ReportMeta,\n ReportTiming,\n Rule,\n RuleResultEntry,\n} from './types.js';\nimport { CATEGORY_WEIGHTS } from './types.js';\n\nconst VERSION = '0.3.0';\n\nexport interface RunRulesOptions {\n only?: string[];\n categories?: Category[];\n meta?: Partial<ReportMeta>;\n fetchMs?: number;\n startedAt?: number;\n categoryWeights?: Record<Category, number>;\n}\n\nexport async function runRules(\n ctx: AuditContext,\n rules: Rule[],\n opts: RunRulesOptions = {},\n): Promise<AuditReport> {\n const auditStart = performance.now();\n const onlySet = opts.only ? new Set(opts.only) : null;\n const catSet = opts.categories ? new Set<Category>(opts.categories) : null;\n const weights = opts.categoryWeights ?? CATEGORY_WEIGHTS;\n\n const buckets: Record<Category, CategoryReport> = {\n crawler: { score: 0, weight: weights.crawler, results: [] },\n 'structured-data': { score: 0, weight: weights['structured-data'], results: [] },\n citation: { score: 0, weight: weights.citation, results: [] },\n content: { score: 0, weight: weights.content, results: [] },\n aeo: { score: 0, weight: weights.aeo, results: [] },\n };\n\n for (const rule of rules) {\n if (onlySet && !onlySet.has(rule.id) && (!rule.stableId || !onlySet.has(rule.stableId))) continue;\n if (catSet && !catSet.has(rule.category)) continue;\n\n const ruleStart = performance.now();\n let result;\n try {\n result = await rule.run(ctx);\n } catch (err) {\n result = {\n status: 'skip' as const,\n score: 0,\n rationale: `Rule crashed: ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n const durationMs = Math.round(performance.now() - ruleStart);\n\n const entry: RuleResultEntry = {\n id: rule.id,\n title: rule.title,\n weight: rule.weight,\n ...result,\n durationMs,\n };\n if (rule.stableId !== undefined) entry.stableId = rule.stableId;\n if (rule.title_ko !== undefined) entry.title_ko = rule.title_ko;\n if (rule.group !== undefined) entry.group = rule.group;\n if (rule.impact !== undefined) entry.impact = rule.impact;\n if (rule.effort !== undefined) entry.effort = rule.effort;\n if (rule.docsUrl !== undefined) entry.docsUrl = rule.docsUrl;\n\n buckets[rule.category].results.push(entry);\n }\n\n for (const cat of Object.keys(buckets) as Category[]) {\n const b = buckets[cat];\n let weighted = 0;\n let totalWeight = 0;\n for (const r of b.results) {\n if (r.status === 'skip') continue;\n weighted += r.score * r.weight;\n totalWeight += r.weight;\n }\n b.score = totalWeight === 0 ? 0 : Math.round((weighted / totalWeight) * 100);\n }\n\n let overallWeighted = 0;\n let overallWeight = 0;\n for (const cat of Object.keys(buckets) as Category[]) {\n const b = buckets[cat];\n if (b.results.length === 0) continue;\n overallWeighted += b.score * b.weight;\n overallWeight += b.weight;\n }\n const overall = overallWeight === 0 ? 0 : Math.round(overallWeighted / overallWeight);\n\n const auditMs = Math.round(performance.now() - auditStart);\n const fetchMs = Math.max(0, Math.round(opts.fetchMs ?? 0));\n const totalMs =\n opts.startedAt !== undefined ? Math.round(performance.now() - opts.startedAt) : fetchMs + auditMs;\n\n const meta: ReportMeta = {\n toolVersion: VERSION,\n nodeVersion: process.versions.node,\n };\n if (opts.meta?.userAgent !== undefined) meta.userAgent = opts.meta.userAgent;\n if (opts.meta?.configPath !== undefined) meta.configPath = opts.meta.configPath;\n\n const timing: ReportTiming = { fetchMs, auditMs, totalMs };\n\n return {\n schemaVersion: 1,\n url: ctx.url,\n finalUrl: ctx.finalUrl,\n fetchedAt: ctx.fetchedAt,\n renderMode: ctx.renderMode,\n overall,\n categories: buckets,\n warnings: [...ctx.warnings],\n version: VERSION,\n meta,\n timing,\n };\n}\n","import { defineRule } from '../../types.js';\n\nexport const httpsRule = defineRule({\n id: 'crawler.https',\n stableId: 'crawler.https',\n category: 'crawler',\n group: 'diagnostic',\n weight: 2,\n impact: 'critical',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#crawlerhttps',\n title: 'Site is served over HTTPS',\n title_ko: '사이트가 HTTPS로 제공됨',\n description: 'AI crawlers treat HTTPS pages as more trustworthy and some skip plain HTTP entirely.',\n run(ctx) {\n const isHttps = ctx.finalUrl.startsWith('https://');\n return isHttps\n ? { status: 'pass', score: 1, rationale: 'Final URL uses HTTPS.', rationale_ko: '최종 URL이 HTTPS를 사용합니다.' }\n : {\n status: 'fail',\n score: 0,\n rationale: 'Final URL does not use HTTPS. Redirect HTTP → HTTPS site-wide.',\n rationale_ko: '최종 URL이 HTTPS를 사용하지 않습니다. 사이트 전체를 HTTP → HTTPS로 리다이렉트하세요.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const robotsReachableRule = defineRule({\n id: 'crawler.robots-reachable',\n stableId: 'crawler.robots-reachable',\n category: 'crawler',\n group: 'diagnostic',\n weight: 2,\n impact: 'low',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#crawlerrobots-reachable',\n title: 'robots.txt is reachable',\n title_ko: 'robots.txt 접근 가능 여부',\n description: 'A reachable robots.txt lets crawlers confirm their permissions; missing file is treated as allow-all but blocks explicit signalling.',\n run(ctx) {\n if (ctx.robots) {\n return { status: 'pass', score: 1, rationale: 'robots.txt returned successfully.', rationale_ko: 'robots.txt가 정상적으로 응답합니다.' };\n }\n return {\n status: 'warn',\n score: 0.3,\n rationale: 'robots.txt is missing. Add one even if empty to explicitly signal crawl policy.',\n rationale_ko: 'robots.txt가 없습니다. 크롤 정책을 명시적으로 알리려면 비어 있더라도 추가하세요.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { isPathAllowed, matchGroup } from '../../fetcher/robots.js';\n\nconst AI_BOTS = [\n // Tier 1: OpenAI\n 'GPTBot',\n 'OAI-SearchBot',\n 'ChatGPT-User',\n // Tier 1: Google / Gemini\n 'Google-Extended',\n 'Google-CloudVertexBot',\n // Tier 1: Anthropic\n 'ClaudeBot',\n 'anthropic-ai',\n 'Claude-Web',\n // Tier 1: Perplexity\n 'PerplexityBot',\n // Tier 1: Apple\n 'Applebot-Extended',\n // Tier 1: Meta\n 'Meta-ExternalAgent',\n // Tier 1: ByteDance\n 'Bytespider',\n // Tier 1: DuckDuckGo\n 'DuckAssistBot',\n // Tier 1: You.com\n 'YouBot',\n // Tier 1: Cohere\n 'cohere-ai',\n // Tier 2: Common Crawl (feeds many LLM training sets)\n 'CCBot',\n // Tier 2: Amazon\n 'Amazonbot',\n];\n\nexport const robotsAiAllowRule = defineRule({\n id: 'crawler.robots-ai-allow',\n stableId: 'crawler.robots-ai-allow',\n category: 'crawler',\n group: 'diagnostic',\n weight: 5,\n impact: 'critical',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#crawlerrobots-ai-allow',\n title: 'AI crawlers are allowed',\n title_ko: 'AI 크롤러 접근 허용 여부',\n description:\n 'Major AI search and training crawlers (17 bots incl. GPTBot, OAI-SearchBot, Google-Extended, ClaudeBot, PerplexityBot, Applebot-Extended, Meta-ExternalAgent, Bytespider, DuckAssistBot, YouBot) must be allowed to index the homepage.',\n run(ctx) {\n if (!ctx.robots) {\n return {\n status: 'warn',\n score: 0.5,\n rationale: 'robots.txt missing; AI crawlers default to allow, but explicit allow is recommended.',\n rationale_ko: 'robots.txt가 없습니다. AI 크롤러는 기본적으로 허용되지만, 명시적 허용을 권장합니다.',\n };\n }\n\n const path = new URL(ctx.finalUrl).pathname || '/';\n const blocked: string[] = [];\n const mentioned: string[] = [];\n\n for (const bot of AI_BOTS) {\n const group = matchGroup(ctx.robots, bot);\n if (group && group.userAgent.toLowerCase() === bot.toLowerCase()) {\n mentioned.push(bot);\n }\n if (!isPathAllowed(group, path)) blocked.push(bot);\n }\n\n if (blocked.length > 0) {\n return {\n status: 'fail',\n score: Math.max(0, 1 - blocked.length / AI_BOTS.length),\n rationale: `Blocked: ${blocked.join(', ')}. Remove the Disallow or add an explicit Allow for these user-agents.`,\n rationale_ko: `차단됨: ${blocked.join(', ')}. 해당 User-agent의 Disallow를 제거하거나 명시적 Allow를 추가하세요.`,\n evidence: { blocked, mentioned, totalBots: AI_BOTS.length },\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n }\n if (mentioned.length === 0) {\n return {\n status: 'warn',\n score: 0.6,\n rationale: `All ${AI_BOTS.length} AI crawlers reach the page via default rules, but none are explicitly listed. Consider explicit Allow entries.`,\n rationale_ko: `${AI_BOTS.length}개 AI 크롤러 모두 기본 규칙으로 접근 가능하지만, 명시적으로 허용된 봇이 없습니다. 명시적 Allow 항목 추가를 권장합니다.`,\n };\n }\n return {\n status: 'pass',\n score: 1,\n rationale: `All ${AI_BOTS.length} AI crawlers can reach the page; ${mentioned.length} explicitly listed.`,\n rationale_ko: `${AI_BOTS.length}개 AI 크롤러 모두 접근 가능하며, ${mentioned.length}개가 명시적으로 허용되어 있습니다.`,\n evidence: { mentioned, totalBots: AI_BOTS.length },\n };\n },\n});\n\nexport const AI_BOTS_TRACKED = AI_BOTS;\n","import { defineRule } from '../../types.js';\n\nexport const llmsTxtPresentRule = defineRule({\n id: 'crawler.llms-txt-present',\n stableId: 'crawler.llms-txt-present',\n category: 'crawler',\n group: 'opportunity',\n weight: 4,\n impact: 'medium',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#crawlerllms-txt-present',\n title: 'llms.txt is present',\n title_ko: 'llms.txt 파일 존재 여부',\n description: 'An /llms.txt file at the site root gives AI assistants a curated map of the most citation-worthy pages.',\n run(ctx) {\n if (ctx.llmsTxt) {\n return { status: 'pass', score: 1, rationale: 'llms.txt found at site root.', rationale_ko: 'llms.txt가 사이트 루트에 존재합니다.' };\n }\n return {\n status: 'warn',\n score: 0,\n rationale: 'No /llms.txt found. Add one to curate the pages AI assistants should read.',\n rationale_ko: '/llms.txt가 없습니다. AI 어시스턴트가 읽어야 할 페이지를 큐레이션하려면 추가하세요.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { isLlmsTxtWellFormed } from '../../fetcher/llms-txt.js';\n\nexport const llmsTxtWellformedRule = defineRule({\n id: 'crawler.llms-txt-wellformed',\n stableId: 'crawler.llms-txt-wellformed',\n category: 'crawler',\n group: 'opportunity',\n weight: 3,\n impact: 'medium',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#crawlerllms-txt-wellformed',\n title: 'llms.txt follows the spec',\n title_ko: 'llms.txt 스펙 준수 여부',\n description: 'Must start with an H1 project title, then a brief summary, then at least one H2 section containing link items.',\n run(ctx) {\n if (!ctx.llmsTxt) {\n return { status: 'skip', score: 0, rationale: 'No llms.txt to validate.', rationale_ko: '검증할 llms.txt가 없습니다.' };\n }\n const check = isLlmsTxtWellFormed(ctx.llmsTxt);\n if (check.ok) {\n const totalLinks = ctx.llmsTxt.sections.reduce((n, s) => n + s.links.length, 0);\n return {\n status: 'pass',\n score: 1,\n rationale: `Well-formed with ${ctx.llmsTxt.sections.length} section(s) and ${totalLinks} link(s).`,\n rationale_ko: `스펙에 맞게 작성됨 (섹션 ${ctx.llmsTxt.sections.length}개, 링크 ${totalLinks}개).`,\n };\n }\n return {\n status: 'warn',\n score: 0.3,\n rationale: `llms.txt does not fully match the spec: ${check.reason}.`,\n rationale_ko: `llms.txt가 스펙을 완전히 따르지 않습니다: ${check.reason}.`,\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const llmsFullTxtRule = defineRule({\n id: 'crawler.llms-full-txt',\n stableId: 'crawler.llms-full-txt',\n category: 'crawler',\n group: 'opportunity',\n weight: 2,\n impact: 'medium',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#crawlerllms-full-txt',\n title: 'llms-full.txt provides full-content mirror',\n title_ko: 'llms-full.txt 전체 콘텐츠 미러 제공 여부',\n description:\n 'Complement /llms.txt with /llms-full.txt containing the full body of every cited page. AI assistants can ingest it in one request instead of crawling every URL.',\n run(ctx) {\n if (ctx.llmsFullTxt && ctx.llmsFullTxt.length > 200) {\n return {\n status: 'pass',\n score: 1,\n rationale: `/llms-full.txt found (${ctx.llmsFullTxt.length.toLocaleString()} chars).`,\n rationale_ko: `/llms-full.txt가 존재합니다 (${ctx.llmsFullTxt.length.toLocaleString()}자).`,\n };\n }\n if (ctx.llmsFullTxt) {\n return {\n status: 'warn',\n score: 0.5,\n rationale: `/llms-full.txt found but very short (${ctx.llmsFullTxt.length} chars). Consider expanding with page bodies.`,\n rationale_ko: `/llms-full.txt가 있지만 너무 짧습니다 (${ctx.llmsFullTxt.length}자). 페이지 본문으로 내용을 보강하세요.`,\n fixHint: 'Mirror full article bodies into /llms-full.txt so AI assistants can quote without re-crawling.',\n };\n }\n return {\n status: 'warn',\n score: 0,\n rationale:\n 'No /llms-full.txt found. Adding one lets AI assistants ingest the full corpus in a single request.',\n rationale_ko:\n '/llms-full.txt가 없습니다. 추가하면 AI 어시스턴트가 전체 콘텐츠를 한 번의 요청으로 수집할 수 있습니다.',\n fixHint: 'Publish /llms-full.txt alongside /llms.txt with the full body text of your top pages.',\n estimatedImpact: 1,\n };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const sitemapPresentRule = defineRule({\n id: 'crawler.sitemap-present',\n stableId: 'crawler.sitemap-present',\n category: 'crawler',\n group: 'diagnostic',\n weight: 4,\n impact: 'high',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#crawlersitemap-present',\n title: 'sitemap.xml is present',\n title_ko: 'sitemap.xml 존재 여부',\n description: 'A sitemap helps AI crawlers discover and prioritise pages; many crawlers short-circuit discovery without one.',\n run(ctx) {\n if (ctx.sitemap && ctx.sitemap.urls.length > 0) {\n return {\n status: 'pass',\n score: 1,\n rationale: `Sitemap found with ${ctx.sitemap.urls.length} URL(s).`,\n rationale_ko: `사이트맵에 URL이 ${ctx.sitemap.urls.length}개 있습니다.`,\n };\n }\n return {\n status: 'warn',\n score: 0.2,\n rationale: 'No sitemap.xml found (checked /sitemap.xml and Sitemap: directive in robots.txt).',\n rationale_ko: 'sitemap.xml이 없습니다 (/sitemap.xml 및 robots.txt의 Sitemap: 지시어를 확인했습니다).',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { httpsRule } from './https.js';\nimport { robotsReachableRule } from './robots-reachable.js';\nimport { robotsAiAllowRule } from './robots-ai-allow.js';\nimport { llmsTxtPresentRule } from './llms-txt-present.js';\nimport { llmsTxtWellformedRule } from './llms-txt-wellformed.js';\nimport { llmsFullTxtRule } from './llms-full-txt.js';\nimport { sitemapPresentRule } from './sitemap-present.js';\n\nexport const crawlerRules = [\n httpsRule,\n robotsReachableRule,\n robotsAiAllowRule,\n llmsTxtPresentRule,\n llmsTxtWellformedRule,\n llmsFullTxtRule,\n sitemapPresentRule,\n];\n","import { defineRule } from '../../types.js';\n\nexport const jsonLdPresentRule = defineRule({\n id: 'sd.jsonld-present',\n stableId: 'sd.jsonld-present',\n category: 'structured-data',\n group: 'diagnostic',\n weight: 5,\n impact: 'critical',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#sdjsonld-present',\n title: 'JSON-LD structured data is present',\n title_ko: 'JSON-LD 구조화 데이터 존재 여부',\n description: 'At least one <script type=\"application/ld+json\"> block is the primary way AI engines map your page to an entity.',\n run(ctx) {\n if (ctx.jsonLd.length > 0) {\n return { status: 'pass', score: 1, rationale: `Found ${ctx.jsonLd.length} JSON-LD block(s).`, rationale_ko: `JSON-LD 블록이 ${ctx.jsonLd.length}개 있습니다.` };\n }\n return {\n status: 'fail',\n score: 0,\n rationale: 'No JSON-LD blocks found. Add schema.org structured data.',\n rationale_ko: 'JSON-LD 블록이 없습니다. schema.org 구조화 데이터를 추가하세요.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","export const KNOWN_SCHEMA_TYPES = [\n 'Article',\n 'NewsArticle',\n 'BlogPosting',\n 'FAQPage',\n 'HowTo',\n 'Organization',\n 'Person',\n 'BreadcrumbList',\n 'Product',\n 'WebSite',\n 'WebPage',\n];\n\nexport const REQUIRED_FIELDS: Record<string, string[]> = {\n Article: ['headline', 'author', 'datePublished'],\n NewsArticle: ['headline', 'author', 'datePublished'],\n BlogPosting: ['headline', 'author', 'datePublished'],\n FAQPage: ['mainEntity'],\n HowTo: ['name', 'step'],\n Product: ['name', 'offers'],\n Organization: ['name'],\n Person: ['name'],\n BreadcrumbList: ['itemListElement'],\n};\n\nexport function getTypes(node: unknown): string[] {\n if (!node || typeof node !== 'object') return [];\n const t = (node as { '@type'?: unknown })['@type'];\n if (typeof t === 'string') return [t];\n if (Array.isArray(t)) return t.filter((x): x is string => typeof x === 'string');\n return [];\n}\n\nexport function flattenJsonLd(blocks: unknown[]): unknown[] {\n const out: unknown[] = [];\n const visit = (node: unknown) => {\n if (!node || typeof node !== 'object') return;\n if (Array.isArray(node)) {\n for (const item of node) visit(item);\n return;\n }\n out.push(node);\n const graph = (node as { '@graph'?: unknown })['@graph'];\n if (Array.isArray(graph)) for (const item of graph) visit(item);\n };\n for (const b of blocks) visit(b);\n return out;\n}\n\nexport function hasParseError(blocks: unknown[]): boolean {\n return blocks.some((b) => b && typeof b === 'object' && (b as { __parseError?: boolean }).__parseError);\n}\n\nexport function hasField(node: unknown, field: string): boolean {\n if (!node || typeof node !== 'object') return false;\n const v = (node as Record<string, unknown>)[field];\n if (v == null) return false;\n if (typeof v === 'string') return v.trim().length > 0;\n if (Array.isArray(v)) return v.length > 0;\n return true;\n}\n","import { defineRule } from '../../types.js';\nimport { hasParseError } from '../util.js';\n\nexport const jsonLdValidJsonRule = defineRule({\n id: 'sd.jsonld-valid-json',\n stableId: 'sd.jsonld-valid-json',\n category: 'structured-data',\n group: 'diagnostic',\n weight: 3,\n impact: 'high',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#sdjsonld-valid-json',\n title: 'JSON-LD blocks parse as valid JSON',\n title_ko: 'JSON-LD 블록의 JSON 유효성',\n description: 'Malformed JSON in an ld+json block is silently ignored by most consumers — a costly silent failure.',\n run(ctx) {\n if (ctx.jsonLd.length === 0) {\n return { status: 'skip', score: 0, rationale: 'No JSON-LD to validate.', rationale_ko: '검증할 JSON-LD가 없습니다.' };\n }\n if (hasParseError(ctx.jsonLd)) {\n return {\n status: 'fail',\n score: 0,\n rationale: 'One or more JSON-LD blocks failed to parse.',\n rationale_ko: 'JSON-LD 블록 하나 이상을 파싱하지 못했습니다.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n }\n return { status: 'pass', score: 1, rationale: 'All JSON-LD blocks parse cleanly.', rationale_ko: '모든 JSON-LD 블록이 올바르게 파싱됩니다.' };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { flattenJsonLd, getTypes, KNOWN_SCHEMA_TYPES } from '../util.js';\n\nexport const schemaTypeRecognizedRule = defineRule({\n id: 'sd.schema-type-recognized',\n stableId: 'sd.schema-type-recognized',\n category: 'structured-data',\n group: 'diagnostic',\n weight: 4,\n impact: 'high',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#sdschema-type-recognized',\n title: 'Schema.org @type is a recognised kind',\n title_ko: 'Schema.org @type 인식 가능 여부',\n description: 'AI engines match pages against well-known types (Article, Product, FAQPage...). Obscure types weaken the signal.',\n run(ctx) {\n if (ctx.jsonLd.length === 0) {\n return { status: 'skip', score: 0, rationale: 'No JSON-LD to analyse.', rationale_ko: '분석할 JSON-LD가 없습니다.' };\n }\n const nodes = flattenJsonLd(ctx.jsonLd);\n const recognized = new Set<string>();\n const seenTypes = new Set<string>();\n for (const node of nodes) {\n for (const t of getTypes(node)) {\n seenTypes.add(t);\n if (KNOWN_SCHEMA_TYPES.includes(t)) recognized.add(t);\n }\n }\n if (recognized.size > 0) {\n return {\n status: 'pass',\n score: 1,\n rationale: `Recognised: ${[...recognized].join(', ')}.`,\n rationale_ko: `인식된 타입: ${[...recognized].join(', ')}.`,\n evidence: { recognized: [...recognized], all: [...seenTypes] },\n };\n }\n return {\n status: 'warn',\n score: 0.3,\n rationale: `No recognised schema.org types. Saw: ${[...seenTypes].join(', ') || '(none)'}.`,\n rationale_ko: `인식 가능한 schema.org 타입이 없습니다. 발견된 타입: ${[...seenTypes].join(', ') || '(없음)'}.`,\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { flattenJsonLd, getTypes, hasField, REQUIRED_FIELDS } from '../util.js';\n\nexport const requiredFieldsRule = defineRule({\n id: 'sd.required-fields',\n stableId: 'sd.required-fields',\n category: 'structured-data',\n group: 'opportunity',\n weight: 6,\n impact: 'high',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#sdrequired-fields',\n title: 'Required fields for recognised types are set',\n title_ko: '인식된 타입의 필수 필드 충족 여부',\n description: 'Article needs headline/author/datePublished, FAQPage needs mainEntity, Product needs offers, etc.',\n run(ctx) {\n if (ctx.jsonLd.length === 0) {\n return { status: 'skip', score: 0, rationale: 'No JSON-LD to analyse.', rationale_ko: '분석할 JSON-LD가 없습니다.' };\n }\n const nodes = flattenJsonLd(ctx.jsonLd);\n const missing: Array<{ type: string; field: string }> = [];\n const checked: string[] = [];\n for (const node of nodes) {\n for (const t of getTypes(node)) {\n const required = REQUIRED_FIELDS[t];\n if (!required) continue;\n checked.push(t);\n for (const f of required) {\n if (!hasField(node, f)) missing.push({ type: t, field: f });\n }\n }\n }\n if (checked.length === 0) {\n return {\n status: 'skip',\n score: 0,\n rationale: 'No types with known required fields were found.',\n rationale_ko: '필수 필드가 정의된 타입이 없습니다.',\n };\n }\n if (missing.length === 0) {\n return {\n status: 'pass',\n score: 1,\n rationale: `Required fields set on ${checked.length} node(s).`,\n rationale_ko: `${checked.length}개 노드의 필수 필드가 모두 충족됩니다.`,\n };\n }\n const msg = missing.map((m) => `${m.type}.${m.field}`).join(', ');\n return {\n status: 'fail',\n score: Math.max(0, 1 - missing.length / (checked.length * 2)),\n rationale: `Missing required fields: ${msg}.`,\n rationale_ko: `누락된 필수 필드: ${msg}.`,\n evidence: missing,\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const microdataFallbackRule = defineRule({\n id: 'sd.microdata-fallback',\n stableId: 'sd.microdata-fallback',\n category: 'structured-data',\n group: 'diagnostic',\n weight: 2,\n impact: 'medium',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#sdmicrodata-fallback',\n title: 'Microdata or RDFa fallback when JSON-LD is missing',\n title_ko: 'JSON-LD 없을 때 Microdata/RDFa 대체 여부',\n description: 'If JSON-LD is absent, inline microdata (itemscope/itemtype) or RDFa still gives some structured signal.',\n run(ctx) {\n if (ctx.jsonLd.length > 0) {\n return { status: 'skip', score: 0, rationale: 'JSON-LD is present; fallback not needed.', rationale_ko: 'JSON-LD가 있으므로 대체 수단이 필요하지 않습니다.' };\n }\n const microdata = ctx.$('[itemscope][itemtype]').length;\n const rdfa = ctx.$('[typeof][vocab], [typeof][property]').length;\n if (microdata > 0 || rdfa > 0) {\n return {\n status: 'pass',\n score: 1,\n rationale: `Found ${microdata} microdata and ${rdfa} RDFa nodes.`,\n rationale_ko: `Microdata ${microdata}개, RDFa ${rdfa}개 발견됩니다.`,\n };\n }\n return {\n status: 'fail',\n score: 0,\n rationale: 'No structured data at all (no JSON-LD, no microdata, no RDFa).',\n rationale_ko: '구조화 데이터가 전혀 없습니다 (JSON-LD, Microdata, RDFa 모두 없음).',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { flattenJsonLd, getTypes } from '../util.js';\n\nconst UNIQUE_TYPES = new Set(['Article', 'NewsArticle', 'BlogPosting', 'Product', 'Organization']);\n\nexport const noDuplicateTypesRule = defineRule({\n id: 'sd.no-duplicate-types',\n stableId: 'sd.no-duplicate-types',\n category: 'structured-data',\n group: 'diagnostic',\n weight: 2,\n impact: 'medium',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#sdno-duplicate-types',\n title: 'No conflicting duplicate @types',\n title_ko: '@type 중복 충돌 없음',\n description: 'Multiple competing entities of the same primary type (e.g. two Articles) confuse the engine about which one represents the page.',\n run(ctx) {\n if (ctx.jsonLd.length === 0) {\n return { status: 'skip', score: 0, rationale: 'No JSON-LD to analyse.', rationale_ko: '분석할 JSON-LD가 없습니다.' };\n }\n const counts = new Map<string, number>();\n for (const node of flattenJsonLd(ctx.jsonLd)) {\n for (const t of getTypes(node)) {\n if (UNIQUE_TYPES.has(t)) counts.set(t, (counts.get(t) ?? 0) + 1);\n }\n }\n const dupes = [...counts.entries()].filter(([, n]) => n > 1);\n if (dupes.length === 0) {\n return { status: 'pass', score: 1, rationale: 'No duplicate primary types.', rationale_ko: '중복된 기본 타입이 없습니다.' };\n }\n return {\n status: 'warn',\n score: 0.4,\n rationale: `Duplicate primary types: ${dupes.map(([t, n]) => `${t}×${n}`).join(', ')}.`,\n rationale_ko: `중복된 기본 타입: ${dupes.map(([t, n]) => `${t}×${n}`).join(', ')}.`,\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { flattenJsonLd, getTypes } from '../util.js';\n\nconst ENTITY_TYPES = ['Organization', 'Person', 'LocalBusiness', 'Brand', 'Corporation'];\nconst TRUSTED_HOSTS = [\n 'wikipedia.org',\n 'wikidata.org',\n 'linkedin.com',\n 'twitter.com',\n 'x.com',\n 'github.com',\n 'crunchbase.com',\n 'facebook.com',\n 'youtube.com',\n 'instagram.com',\n];\n\nfunction extractSameAs(node: unknown): string[] {\n if (!node || typeof node !== 'object') return [];\n const v = (node as { sameAs?: unknown }).sameAs;\n if (typeof v === 'string') return [v];\n if (Array.isArray(v)) return v.filter((x): x is string => typeof x === 'string');\n return [];\n}\n\nfunction trustedCount(urls: string[]): number {\n let n = 0;\n for (const u of urls) {\n try {\n const host = new URL(u).hostname.toLowerCase();\n if (TRUSTED_HOSTS.some((h) => host === h || host.endsWith('.' + h))) n++;\n } catch {\n /* ignore malformed */\n }\n }\n return n;\n}\n\nexport const sameAsEntityRule = defineRule({\n id: 'sd.sameas-entity',\n stableId: 'sd.sameas-entity',\n category: 'structured-data',\n group: 'opportunity',\n weight: 3,\n impact: 'high',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#sdsameas-entity',\n title: 'Entity nodes link the knowledge graph via sameAs',\n title_ko: 'sameAs로 지식 그래프 연결 여부',\n description:\n 'Organization/Person nodes should declare a sameAs[] array linking to Wikipedia/Wikidata/LinkedIn so AI engines can resolve the entity in their knowledge graph (E-E-A-T signal).',\n run(ctx) {\n if (ctx.jsonLd.length === 0) {\n return { status: 'skip', score: 0, rationale: 'No JSON-LD to analyse.', rationale_ko: '분석할 JSON-LD가 없습니다.' };\n }\n const nodes = flattenJsonLd(ctx.jsonLd);\n const entities = nodes.filter((n) => getTypes(n).some((t) => ENTITY_TYPES.includes(t)));\n if (entities.length === 0) {\n return {\n status: 'skip',\n score: 0,\n rationale: 'No Organization/Person/LocalBusiness/Brand entity to link.',\n rationale_ko: '연결할 Organization/Person/LocalBusiness/Brand 엔티티가 없습니다.',\n };\n }\n let bestScore = 0;\n let bestEvidence: { type: string; sameAs: string[]; trusted: number } | null = null;\n for (const e of entities) {\n const sameAs = extractSameAs(e);\n const trusted = trustedCount(sameAs);\n const types = getTypes(e);\n let score = 0;\n if (sameAs.length === 0) score = 0;\n else if (trusted === 0) score = 0.4;\n else if (trusted === 1) score = 0.7;\n else score = 1;\n if (score > bestScore) {\n bestScore = score;\n bestEvidence = { type: types[0] ?? 'Entity', sameAs, trusted };\n }\n }\n if (bestScore >= 1) {\n return {\n status: 'pass',\n score: 1,\n rationale: `Entity links ${bestEvidence!.trusted} trusted knowledge-graph hosts via sameAs.`,\n rationale_ko: `엔티티가 sameAs로 신뢰할 수 있는 지식 그래프 사이트 ${bestEvidence!.trusted}개에 연결되어 있습니다.`,\n evidence: bestEvidence,\n };\n }\n if (bestScore >= 0.7) {\n return {\n status: 'pass',\n score: bestScore,\n rationale: `Entity has 1 trusted sameAs link. Add Wikipedia/Wikidata for stronger E-E-A-T.`,\n rationale_ko: '신뢰할 수 있는 sameAs 링크가 1개 있습니다. E-E-A-T 강화를 위해 Wikipedia/Wikidata를 추가하세요.',\n evidence: bestEvidence,\n estimatedImpact: 1,\n };\n }\n if (bestScore > 0) {\n return {\n status: 'warn',\n score: bestScore,\n rationale: 'Entity declares sameAs but no trusted knowledge-graph hosts (Wikipedia/Wikidata/LinkedIn).',\n rationale_ko: 'sameAs가 선언되어 있지만 신뢰할 수 있는 지식 그래프 호스트(Wikipedia/Wikidata/LinkedIn)가 없습니다.',\n evidence: bestEvidence,\n fixHint: 'Add Wikipedia/Wikidata/LinkedIn URLs to your Organization sameAs[].',\n estimatedImpact: 2,\n };\n }\n return {\n status: 'warn',\n score: 0,\n rationale: `${entities.length} entity node(s) found but none declare sameAs links.`,\n rationale_ko: `엔티티 노드가 ${entities.length}개 있지만 sameAs 링크가 없습니다.`,\n fixHint: 'Add sameAs:[\"https://en.wikipedia.org/wiki/...\", \"https://www.linkedin.com/company/...\"] to your Organization JSON-LD.',\n estimatedImpact: 3,\n };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { flattenJsonLd, getTypes, hasField } from '../util.js';\n\ninterface ItemListIssue {\n index: number;\n missing: string[];\n}\n\nfunction validateItemList(node: unknown): ItemListIssue[] {\n if (!node || typeof node !== 'object') return [];\n const items = (node as { itemListElement?: unknown }).itemListElement;\n if (!Array.isArray(items) || items.length === 0) return [{ index: -1, missing: ['itemListElement'] }];\n const issues: ItemListIssue[] = [];\n items.forEach((item, i) => {\n const missing: string[] = [];\n if (!hasField(item, 'position')) missing.push('position');\n if (!hasField(item, 'name') && !hasField(item, 'item')) missing.push('name');\n if (!hasField(item, 'item') && !hasField(item, 'name')) missing.push('item');\n if (missing.length > 0) issues.push({ index: i, missing });\n });\n return issues;\n}\n\nexport const breadcrumbValidRule = defineRule({\n id: 'sd.breadcrumb-valid',\n stableId: 'sd.breadcrumb-valid',\n category: 'structured-data',\n group: 'opportunity',\n weight: 2,\n impact: 'medium',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#sdbreadcrumb-valid',\n title: 'BreadcrumbList items declare position, name, and item',\n title_ko: 'BreadcrumbList 항목의 필수 필드 충족 여부',\n description:\n 'When BreadcrumbList JSON-LD is present, every itemListElement should set position (1-indexed), name, and item (URL) — otherwise AI engines cannot reconstruct the path.',\n run(ctx) {\n if (ctx.jsonLd.length === 0) {\n return { status: 'skip', score: 0, rationale: 'No JSON-LD to analyse.', rationale_ko: '분석할 JSON-LD가 없습니다.' };\n }\n const nodes = flattenJsonLd(ctx.jsonLd);\n const breadcrumbs = nodes.filter((n) => getTypes(n).includes('BreadcrumbList'));\n if (breadcrumbs.length === 0) {\n return { status: 'skip', score: 0, rationale: 'No BreadcrumbList present.', rationale_ko: 'BreadcrumbList가 없습니다.' };\n }\n const allIssues: ItemListIssue[] = [];\n let totalItems = 0;\n for (const bc of breadcrumbs) {\n const items = (bc as { itemListElement?: unknown }).itemListElement;\n if (Array.isArray(items)) totalItems += items.length;\n allIssues.push(...validateItemList(bc));\n }\n if (allIssues.length === 0) {\n return {\n status: 'pass',\n score: 1,\n rationale: `BreadcrumbList(s) valid (${totalItems} items).`,\n rationale_ko: `BreadcrumbList가 유효합니다 (항목 ${totalItems}개).`,\n };\n }\n const fatalCount = allIssues.length;\n const denom = Math.max(1, totalItems);\n const score = Math.max(0, 1 - fatalCount / denom);\n return {\n status: score < 0.5 ? 'fail' : 'warn',\n score,\n rationale: `${fatalCount} breadcrumb item(s) missing required fields.`,\n rationale_ko: `breadcrumb 항목 ${fatalCount}개에 필수 필드가 없습니다.`,\n evidence: allIssues.slice(0, 5),\n fixHint: 'Each itemListElement needs { \"@type\": \"ListItem\", position: N, name, item }.',\n estimatedImpact: Math.round(2 * (1 - score)),\n };\n },\n});\n","import { jsonLdPresentRule } from './jsonld-present.js';\nimport { jsonLdValidJsonRule } from './jsonld-valid-json.js';\nimport { schemaTypeRecognizedRule } from './schema-type-recognized.js';\nimport { requiredFieldsRule } from './required-fields.js';\nimport { microdataFallbackRule } from './microdata-fallback.js';\nimport { noDuplicateTypesRule } from './no-duplicate-types.js';\nimport { sameAsEntityRule } from './sameas-entity.js';\nimport { breadcrumbValidRule } from './breadcrumb-valid.js';\n\nexport const structuredDataRules = [\n jsonLdPresentRule,\n jsonLdValidJsonRule,\n schemaTypeRecognizedRule,\n requiredFieldsRule,\n microdataFallbackRule,\n noDuplicateTypesRule,\n sameAsEntityRule,\n breadcrumbValidRule,\n];\n","import { defineRule } from '../../types.js';\n\nexport const titleRule = defineRule({\n id: 'cit.title',\n stableId: 'cit.title',\n category: 'citation',\n group: 'diagnostic',\n weight: 2,\n impact: 'critical',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#cittitle',\n title: '<title> is set with a reasonable length',\n title_ko: '<title> 태그 적정 길이 설정 여부',\n description: 'The document title is the single most-cited piece of text and should be 10–70 characters.',\n run(ctx) {\n const title = ctx.$('head > title').first().text().trim();\n if (!title) {\n return {\n status: 'fail',\n score: 0,\n rationale: 'Page has no <title>.',\n rationale_ko: '페이지에 <title>이 없습니다.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n }\n if (title.length < 10) {\n return {\n status: 'warn',\n score: 0.4,\n rationale: `Title is only ${title.length} chars; consider a more descriptive one.`,\n rationale_ko: `제목이 ${title.length}자밖에 안 됩니다. 더 구체적으로 작성하세요.`,\n };\n }\n if (title.length > 70) {\n return {\n status: 'warn',\n score: 0.6,\n rationale: `Title is ${title.length} chars; search UIs commonly truncate after ~70.`,\n rationale_ko: `제목이 ${title.length}자입니다. 검색 UI에서 70자 이후는 잘릴 수 있습니다.`,\n };\n }\n return { status: 'pass', score: 1, rationale: `Title length ${title.length} is within range.`, rationale_ko: `제목 길이 ${title.length}자로 적절합니다.` };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const metaDescriptionRule = defineRule({\n id: 'cit.meta-description',\n stableId: 'cit.meta-description',\n category: 'citation',\n group: 'opportunity',\n weight: 2,\n impact: 'high',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#citmeta-description',\n title: 'meta description is set (50–160 chars)',\n title_ko: 'meta description 설정 여부 (50–160자)',\n description: 'AI snippets often quote the meta description verbatim; aim for 50–160 chars.',\n run(ctx) {\n const desc = ctx.$('head meta[name=\"description\"]').attr('content')?.trim() ?? '';\n if (!desc) {\n return {\n status: 'warn',\n score: 0,\n rationale: 'No meta description set.',\n rationale_ko: 'meta description이 없습니다.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n }\n if (desc.length < 50) {\n return { status: 'warn', score: 0.5, rationale: `Only ${desc.length} chars; aim for 50+.`, rationale_ko: `${desc.length}자밖에 안 됩니다. 50자 이상을 목표로 하세요.` };\n }\n if (desc.length > 160) {\n return { status: 'warn', score: 0.7, rationale: `${desc.length} chars; may be truncated after 160.`, rationale_ko: `${desc.length}자입니다. 160자 이후는 잘릴 수 있습니다.` };\n }\n return { status: 'pass', score: 1, rationale: `Description length ${desc.length} is within range.`, rationale_ko: `설명 길이 ${desc.length}자로 적절합니다.` };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const canonicalRule = defineRule({\n id: 'cit.canonical',\n stableId: 'cit.canonical',\n category: 'citation',\n group: 'diagnostic',\n weight: 3,\n impact: 'high',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#citcanonical',\n title: 'Canonical URL is declared',\n title_ko: 'Canonical URL 선언 여부',\n description: 'rel=\"canonical\" tells crawlers which URL is the source of truth, preventing duplicate-citation confusion.',\n run(ctx) {\n const href = ctx.$('head link[rel=\"canonical\"]').attr('href')?.trim();\n if (!href) {\n return {\n status: 'warn',\n score: 0,\n rationale: 'No <link rel=\"canonical\"> found.',\n rationale_ko: '<link rel=\"canonical\">이 없습니다.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n }\n try {\n const abs = new URL(href, ctx.finalUrl).toString();\n return { status: 'pass', score: 1, rationale: `Canonical URL: ${abs}.`, rationale_ko: `Canonical URL: ${abs}.` };\n } catch {\n return { status: 'fail', score: 0, rationale: `Canonical href is not a valid URL: ${href}`, rationale_ko: `Canonical href가 유효한 URL이 아닙니다: ${href}` };\n }\n },\n});\n","import { defineRule } from '../../types.js';\n\nconst REQUIRED = ['og:title', 'og:type', 'og:url', 'og:image'] as const;\n\nexport const ogTagsRule = defineRule({\n id: 'cit.og-tags',\n stableId: 'cit.og-tags',\n category: 'citation',\n group: 'opportunity',\n weight: 3,\n impact: 'high',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#citog-tags',\n title: 'Open Graph tags are set',\n title_ko: 'Open Graph 태그 설정 여부',\n description: 'og:title/type/url/image power rich previews on AI chat, social, and messaging.',\n run(ctx) {\n const missing: string[] = [];\n for (const prop of REQUIRED) {\n const val = ctx.$(`head meta[property=\"${prop}\"]`).attr('content')?.trim();\n if (!val) missing.push(prop);\n }\n if (missing.length === 0) {\n return { status: 'pass', score: 1, rationale: 'All required OG tags present.', rationale_ko: '필수 OG 태그가 모두 있습니다.' };\n }\n const ratio = 1 - missing.length / REQUIRED.length;\n return {\n status: missing.length === REQUIRED.length ? 'fail' : 'warn',\n score: ratio,\n rationale: `Missing: ${missing.join(', ')}.`,\n rationale_ko: `누락된 태그: ${missing.join(', ')}.`,\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const twitterCardRule = defineRule({\n id: 'cit.twitter-card',\n stableId: 'cit.twitter-card',\n category: 'citation',\n group: 'opportunity',\n weight: 2,\n impact: 'low',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#cittwitter-card',\n title: 'Twitter Card metadata is set',\n title_ko: 'Twitter Card 메타데이터 설정 여부',\n description: 'twitter:card + twitter:title give better previews on X/Twitter and some AI surfaces that reuse the tags.',\n run(ctx) {\n const card = ctx.$('head meta[name=\"twitter:card\"]').attr('content')?.trim();\n const title = ctx.$('head meta[name=\"twitter:title\"]').attr('content')?.trim();\n if (card && title) {\n return { status: 'pass', score: 1, rationale: `Card type: ${card}.`, rationale_ko: `카드 유형: ${card}.` };\n }\n if (card || title) {\n return { status: 'warn', score: 0.5, rationale: 'Partial twitter:* metadata; add the missing tag.', rationale_ko: 'twitter:* 메타데이터가 일부만 있습니다. 누락된 태그를 추가하세요.' };\n }\n return {\n status: 'warn',\n score: 0,\n rationale: 'No twitter:card metadata.',\n rationale_ko: 'twitter:card 메타데이터가 없습니다.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const langAttrRule = defineRule({\n id: 'cit.lang-attr',\n stableId: 'cit.lang-attr',\n category: 'citation',\n group: 'diagnostic',\n weight: 2,\n impact: 'medium',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#citlang-attr',\n title: '<html lang> is set',\n title_ko: '<html lang> 속성 설정 여부',\n description: 'A lang attribute helps AI engines route the page to the right-language search surface (and helps screen readers).',\n run(ctx) {\n const lang = ctx.$('html').attr('lang')?.trim();\n if (!lang) {\n return {\n status: 'warn',\n score: 0,\n rationale: 'No lang attribute on <html>.',\n rationale_ko: '<html>에 lang 속성이 없습니다.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n }\n return { status: 'pass', score: 1, rationale: `lang=\"${lang}\".`, rationale_ko: `lang=\"${lang}\".` };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { flattenJsonLd, hasField } from '../util.js';\n\nexport const authorVisibleRule = defineRule({\n id: 'cit.author-visible',\n stableId: 'cit.author-visible',\n category: 'citation',\n group: 'opportunity',\n weight: 4,\n impact: 'high',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#citauthor-visible',\n title: 'Author is declared',\n title_ko: '작성자 정보 선언 여부',\n description: 'AI engines prefer citing content with an identifiable author; expose one via JSON-LD, meta[name=author], rel=author, or a .author class.',\n run(ctx) {\n for (const node of flattenJsonLd(ctx.jsonLd)) {\n if (hasField(node, 'author')) {\n return { status: 'pass', score: 1, rationale: 'Author found in JSON-LD.', rationale_ko: 'JSON-LD에서 작성자 정보를 찾았습니다.' };\n }\n }\n const metaAuthor = ctx.$('head meta[name=\"author\"]').attr('content')?.trim();\n if (metaAuthor) return { status: 'pass', score: 1, rationale: `meta[name=author] = \"${metaAuthor}\".`, rationale_ko: `meta[name=author] = \"${metaAuthor}\".` };\n if (ctx.$('[rel=\"author\"]').length > 0) {\n return { status: 'pass', score: 1, rationale: 'rel=\"author\" link found.', rationale_ko: 'rel=\"author\" 링크를 찾았습니다.' };\n }\n if (ctx.$('.author, [class*=\"author\"], [itemprop=\"author\"]').length > 0) {\n return { status: 'pass', score: 0.8, rationale: 'Author-ish DOM selector found (weaker signal).', rationale_ko: '작성자 관련 DOM 선택자가 있습니다 (신호 강도 낮음).' };\n }\n return {\n status: 'warn',\n score: 0,\n rationale: 'No author signal found (JSON-LD, meta, rel, or .author).',\n rationale_ko: '작성자 정보가 없습니다 (JSON-LD, meta, rel, .author 모두 없음).',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { flattenJsonLd, hasField } from '../util.js';\n\nexport const datesRule = defineRule({\n id: 'cit.dates',\n stableId: 'cit.dates',\n category: 'citation',\n group: 'opportunity',\n weight: 5,\n impact: 'high',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#citdates',\n title: 'Publish / modified date is present',\n title_ko: '발행일 / 수정일 존재 여부',\n description: 'AI engines rank recent pages higher; expose datePublished via JSON-LD, <time datetime>, or article:published_time meta.',\n run(ctx) {\n for (const node of flattenJsonLd(ctx.jsonLd)) {\n if (hasField(node, 'datePublished')) {\n return { status: 'pass', score: 1, rationale: 'datePublished found in JSON-LD.', rationale_ko: 'JSON-LD에서 datePublished를 찾았습니다.' };\n }\n }\n const articleTime = ctx.$('head meta[property=\"article:published_time\"]').attr('content')?.trim();\n if (articleTime) {\n return { status: 'pass', score: 1, rationale: `article:published_time = ${articleTime}.`, rationale_ko: `article:published_time = ${articleTime}.` };\n }\n const timeEl = ctx.$('time[datetime]').first().attr('datetime')?.trim();\n if (timeEl) {\n return { status: 'pass', score: 0.8, rationale: `<time datetime=\"${timeEl}\"> found.`, rationale_ko: `<time datetime=\"${timeEl}\">를 찾았습니다.` };\n }\n return {\n status: 'warn',\n score: 0,\n rationale: 'No publish date found (JSON-LD, meta article:published_time, or <time datetime>).',\n rationale_ko: '발행일이 없습니다 (JSON-LD, meta article:published_time, <time datetime> 모두 없음).',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { flattenJsonLd, getTypes } from '../util.js';\n\nconst ARTICLE_TYPES = new Set(['Article', 'NewsArticle', 'BlogPosting', 'Report', 'TechArticle']);\nconst ONE_DAY = 24 * 60 * 60 * 1000;\n\nfunction pickDate(node: unknown, field: string): string | undefined {\n if (!node || typeof node !== 'object') return undefined;\n const v = (node as Record<string, unknown>)[field];\n return typeof v === 'string' && v.trim() ? v.trim() : undefined;\n}\n\nfunction parseDateMs(s: string): number | null {\n const t = Date.parse(s);\n return Number.isNaN(t) ? null : t;\n}\n\nexport const contentFreshnessRule = defineRule({\n id: 'cit.content-freshness',\n stableId: 'cit.content-freshness',\n category: 'citation',\n group: 'opportunity',\n weight: 3,\n impact: 'high',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#citcontent-freshness',\n title: 'Article content is fresh (dateModified within 1 year)',\n title_ko: '콘텐츠 최신성 (dateModified 1년 이내)',\n description:\n 'AI engines down-rank stale content. Surface a recent dateModified (≤365 days) on Article-like pages so retrieval rankings stay strong.',\n run(ctx) {\n const nodes = flattenJsonLd(ctx.jsonLd);\n const articles = nodes.filter((n) => getTypes(n).some((t) => ARTICLE_TYPES.has(t)));\n if (articles.length === 0) {\n return {\n status: 'skip',\n score: 0,\n rationale: 'No Article/BlogPosting/NewsArticle JSON-LD; freshness signal not applicable.',\n rationale_ko: 'Article/BlogPosting/NewsArticle JSON-LD가 없어 최신성 신호를 확인할 수 없습니다.',\n };\n }\n let bestMs: number | null = null;\n let usedField: 'dateModified' | 'datePublished' | null = null;\n for (const a of articles) {\n const mod = pickDate(a, 'dateModified');\n const pub = pickDate(a, 'datePublished');\n const candidate = mod ?? pub;\n if (!candidate) continue;\n const ms = parseDateMs(candidate);\n if (ms === null) continue;\n if (bestMs === null || ms > bestMs) {\n bestMs = ms;\n usedField = mod ? 'dateModified' : 'datePublished';\n }\n }\n if (bestMs === null) {\n return {\n status: 'warn',\n score: 0,\n rationale: 'Article has no parseable dateModified or datePublished.',\n rationale_ko: 'Article JSON-LD에 파싱 가능한 dateModified 또는 datePublished가 없습니다.',\n fixHint: 'Add ISO-8601 dateModified and datePublished to your Article JSON-LD.',\n estimatedImpact: 3,\n };\n }\n const ageDays = Math.round((Date.now() - bestMs) / ONE_DAY);\n if (ageDays <= 365) {\n return {\n status: 'pass',\n score: 1,\n rationale: `${usedField} within the last year (~${ageDays} day${ageDays === 1 ? '' : 's'} ago).`,\n rationale_ko: `${usedField}이 1년 이내입니다 (약 ${ageDays}일 전).`,\n evidence: { ageDays, field: usedField },\n };\n }\n if (ageDays <= 730) {\n return {\n status: 'warn',\n score: 0.6,\n rationale: `${usedField} is ${ageDays} days old. Refresh within a year for best AI ranking.`,\n rationale_ko: `${usedField}이 ${ageDays}일 됐습니다. AI 순위를 유지하려면 1년 이내로 갱신하세요.`,\n evidence: { ageDays, field: usedField },\n estimatedImpact: 2,\n };\n }\n return {\n status: 'warn',\n score: 0.2,\n rationale: `${usedField} is ${ageDays} days old (>2 years). AI engines treat this as stale.`,\n rationale_ko: `${usedField}이 ${ageDays}일 됐습니다 (2년 초과). AI 엔진이 오래된 콘텐츠로 간주합니다.`,\n evidence: { ageDays, field: usedField },\n fixHint: 'Update content and bump dateModified to today\\'s date.',\n estimatedImpact: 3,\n };\n },\n});\n","import { titleRule } from './title.js';\nimport { metaDescriptionRule } from './meta-description.js';\nimport { canonicalRule } from './canonical.js';\nimport { ogTagsRule } from './og-tags.js';\nimport { twitterCardRule } from './twitter-card.js';\nimport { langAttrRule } from './lang-attr.js';\nimport { authorVisibleRule } from './author-visible.js';\nimport { datesRule } from './dates.js';\nimport { contentFreshnessRule } from './content-freshness.js';\n\nexport const citationRules = [\n titleRule,\n metaDescriptionRule,\n canonicalRule,\n ogTagsRule,\n twitterCardRule,\n langAttrRule,\n authorVisibleRule,\n datesRule,\n contentFreshnessRule,\n];\n","import { defineRule } from '../../types.js';\n\nexport const singleH1Rule = defineRule({\n id: 'cnt.single-h1',\n stableId: 'cnt.single-h1',\n category: 'content',\n group: 'diagnostic',\n weight: 3,\n impact: 'high',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#cntsingle-h1',\n title: 'Exactly one <h1>',\n title_ko: '<h1> 태그 1개 여부',\n description: 'A single H1 tells AI engines the primary topic of the page without ambiguity.',\n run(ctx) {\n const n = ctx.$('h1').length;\n if (n === 1) return { status: 'pass', score: 1, rationale: 'Exactly one <h1>.', rationale_ko: '<h1>이 정확히 1개입니다.' };\n if (n === 0) {\n return {\n status: 'fail',\n score: 0,\n rationale: 'No <h1> on the page.',\n rationale_ko: '페이지에 <h1>이 없습니다.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules/cnt.single-h1.md',\n };\n }\n return {\n status: 'warn',\n score: Math.max(0.3, 1 / n),\n rationale: `Found ${n} <h1> tags; prefer one primary heading.`,\n rationale_ko: `<h1>이 ${n}개 있습니다. 대표 제목 1개만 사용하세요.`,\n };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const headingHierarchyRule = defineRule({\n id: 'cnt.heading-hierarchy',\n stableId: 'cnt.heading-hierarchy',\n category: 'content',\n group: 'diagnostic',\n weight: 3,\n impact: 'medium',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#cntheading-hierarchy',\n title: 'Heading levels do not skip',\n title_ko: '제목 단계 순서 준수 여부',\n description: 'Going from H2 directly to H4 breaks the outline AI engines use to segment content.',\n run(ctx) {\n const levels: number[] = [];\n ctx.$('h1, h2, h3, h4, h5, h6').each((_i, el) => {\n const name = (el as { tagName?: string }).tagName?.toLowerCase() ?? 'h1';\n const m = /^h([1-6])$/.exec(name);\n if (m?.[1]) levels.push(parseInt(m[1], 10));\n });\n if (levels.length === 0) {\n return { status: 'skip', score: 0, rationale: 'No headings found.', rationale_ko: '제목 태그가 없습니다.' };\n }\n const skips: Array<{ from: number; to: number }> = [];\n for (let i = 1; i < levels.length; i++) {\n const prev = levels[i - 1]!;\n const curr = levels[i]!;\n if (curr > prev + 1) skips.push({ from: prev, to: curr });\n }\n if (skips.length === 0) {\n return { status: 'pass', score: 1, rationale: 'No heading-level skips.', rationale_ko: '제목 단계가 순서대로 사용됩니다.' };\n }\n return {\n status: 'warn',\n score: Math.max(0.3, 1 - skips.length / levels.length),\n rationale: `${skips.length} heading skip(s) detected (e.g. h${skips[0]!.from}→h${skips[0]!.to}).`,\n rationale_ko: `제목 단계 건너뜀이 ${skips.length}개 감지됩니다 (예: h${skips[0]!.from}→h${skips[0]!.to}).`,\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const imageAltRule = defineRule({\n id: 'cnt.image-alt',\n stableId: 'cnt.image-alt',\n category: 'content',\n group: 'opportunity',\n weight: 3,\n impact: 'medium',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#cntimage-alt',\n title: '≥80% of <img> have alt text',\n title_ko: '<img>의 80% 이상 alt 텍스트 보유 여부',\n description: 'Alt text gives AI engines a textual anchor for visual content and improves accessibility.',\n run(ctx) {\n const imgs = ctx.$('img');\n const total = imgs.length;\n if (total === 0) return { status: 'skip', score: 0, rationale: 'No <img> on the page.', rationale_ko: '페이지에 <img>가 없습니다.' };\n\n let withAlt = 0;\n imgs.each((_i, el) => {\n const alt = ctx.$(el).attr('alt');\n if (typeof alt === 'string' && alt.trim().length > 0) withAlt += 1;\n });\n const ratio = withAlt / total;\n if (ratio >= 0.8) {\n return { status: 'pass', score: 1, rationale: `${withAlt}/${total} images have alt (${Math.round(ratio * 100)}%).`, rationale_ko: `이미지 ${total}개 중 ${withAlt}개에 alt가 있습니다 (${Math.round(ratio * 100)}%).` };\n }\n return {\n status: 'warn',\n score: ratio,\n rationale: `Only ${withAlt}/${total} images have alt text (${Math.round(ratio * 100)}%). Aim for ≥80%.`,\n rationale_ko: `이미지 ${total}개 중 ${withAlt}개만 alt 텍스트가 있습니다 (${Math.round(ratio * 100)}%). 80% 이상을 목표로 하세요.`,\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { flattenJsonLd, getTypes } from '../util.js';\n\nexport const tldrOrFaqRule = defineRule({\n id: 'cnt.tldr-or-faq',\n stableId: 'cnt.tldr-or-faq',\n category: 'content',\n group: 'opportunity',\n weight: 5,\n impact: 'high',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#cnttldr-or-faq',\n title: 'TL;DR summary or FAQ block',\n title_ko: 'TL;DR 요약 또는 FAQ 블록 존재 여부',\n description: 'AI engines strongly prefer content with a quotable summary or FAQ — it makes the page \"citation-ready\".',\n run(ctx) {\n for (const node of flattenJsonLd(ctx.jsonLd)) {\n if (getTypes(node).includes('FAQPage')) {\n return { status: 'pass', score: 1, rationale: 'FAQPage schema present.', rationale_ko: 'FAQPage 스키마가 있습니다.' };\n }\n }\n const sel = [\n 'section[id*=\"tldr\" i]',\n 'section[id*=\"summary\" i]',\n 'section[id*=\"faq\" i]',\n '.tldr',\n '.summary',\n '.faq',\n '[data-tldr]',\n ].join(', ');\n if (ctx.$(sel).length > 0) {\n return { status: 'pass', score: 0.85, rationale: 'TL;DR / summary / FAQ region detected by selector.', rationale_ko: 'TL;DR / 요약 / FAQ 영역이 감지됩니다.' };\n }\n return {\n status: 'warn',\n score: 0,\n rationale: 'No TL;DR / summary / FAQ found; add one to boost AI citation odds.',\n rationale_ko: 'TL;DR / 요약 / FAQ가 없습니다. AI 인용 가능성을 높이려면 추가하세요.',\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const wordCountRule = defineRule({\n id: 'cnt.word-count',\n stableId: 'cnt.word-count',\n category: 'content',\n group: 'opportunity',\n weight: 2,\n impact: 'high',\n effort: 'high',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#cntword-count',\n title: 'Page has enough body text',\n title_ko: '충분한 본문 텍스트 여부',\n description: 'Thin pages (under ~100 words) are rarely cited by AI engines. Aim for ≥300 words of meaningful body copy.',\n run(ctx) {\n const $ = ctx.$;\n const clone = $('body').clone();\n clone.find('script, style, noscript, nav, header, footer, aside').remove();\n const text = clone.text().replace(/\\s+/g, ' ').trim();\n const words = text ? text.split(' ').length : 0;\n if (words >= 300) return { status: 'pass', score: 1, rationale: `${words} words of body text.`, rationale_ko: `본문 텍스트가 ${words}단어 있습니다.` };\n if (words >= 100) return { status: 'warn', score: 0.5, rationale: `Only ${words} words; aim for 300+.`, rationale_ko: `${words}단어밖에 없습니다. 300단어 이상을 목표로 하세요.` };\n return {\n status: 'fail',\n score: 0,\n rationale: `Only ${words} words; too thin to be cited.`,\n rationale_ko: `${words}단어밖에 없습니다. AI 엔진이 인용하기엔 너무 적습니다.`,\n fixUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md',\n };\n },\n});\n","import { defineRule } from '../../types.js';\nimport { flattenJsonLd, getTypes } from '../util.js';\n\nconst QUESTION_LEADERS = [\n // English interrogatives\n 'how',\n 'what',\n 'why',\n 'when',\n 'where',\n 'who',\n 'which',\n 'is',\n 'are',\n 'can',\n 'should',\n 'do',\n 'does',\n // Korean interrogatives (어떻게, 왜, 무엇, 언제, 어디, 누가, 어느, 왜냐하면)\n '어떻게',\n '왜',\n '무엇',\n '뭐',\n '뭔',\n '언제',\n '어디',\n '누가',\n '어느',\n '얼마',\n];\n\nfunction isQuestionHeading(text: string): boolean {\n const t = text.trim();\n if (!t) return false;\n if (t.endsWith('?') || t.endsWith('?')) return true;\n const first = t.split(/[\\s,.:]+/, 1)[0]?.toLowerCase() ?? '';\n return QUESTION_LEADERS.includes(first);\n}\n\nexport const qaStructureRule = defineRule({\n id: 'cnt.qa-structure',\n stableId: 'cnt.qa-structure',\n category: 'content',\n group: 'opportunity',\n weight: 3,\n impact: 'high',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#cntqa-structure',\n title: 'Content uses Q&A structure for answer extraction',\n title_ko: '답변 추출을 위한 Q&A 구조 사용 여부',\n description:\n 'Question-style H2/H3 headings (or FAQPage JSON-LD) help AI engines extract direct answers. Pages with ≥2 question headings are far more likely to be cited.',\n run(ctx) {\n for (const node of flattenJsonLd(ctx.jsonLd)) {\n if (getTypes(node).includes('FAQPage')) {\n return { status: 'pass', score: 1, rationale: 'FAQPage JSON-LD provides explicit Q&A.', rationale_ko: 'FAQPage JSON-LD로 명시적인 Q&A 구조가 있습니다.' };\n }\n }\n const questionHeadings: string[] = [];\n ctx.$('h2, h3').each((_i, el) => {\n const text = ctx.$(el).text();\n if (isQuestionHeading(text)) questionHeadings.push(text.trim().slice(0, 80));\n });\n if (questionHeadings.length >= 2) {\n return {\n status: 'pass',\n score: 1,\n rationale: `${questionHeadings.length} question-style headings detected.`,\n rationale_ko: `질문형 제목이 ${questionHeadings.length}개 감지됩니다.`,\n evidence: { headings: questionHeadings.slice(0, 5) },\n };\n }\n if (questionHeadings.length === 1) {\n return {\n status: 'warn',\n score: 0.6,\n rationale: '1 question-style heading. Add a second to strengthen answer extraction.',\n rationale_ko: '질문형 제목이 1개입니다. 답변 추출 강화를 위해 하나 더 추가하세요.',\n evidence: { headings: questionHeadings },\n estimatedImpact: 1,\n };\n }\n return {\n status: 'warn',\n score: 0,\n rationale: 'No question-style H2/H3 headings or FAQPage JSON-LD found.',\n rationale_ko: '질문형 H2/H3 제목이나 FAQPage JSON-LD가 없습니다.',\n fixHint: 'Reframe at least 2 H2 headings as questions (\"How do I…?\", \"What is…?\") or add FAQPage JSON-LD.',\n estimatedImpact: 3,\n };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const externalCitationsRule = defineRule({\n id: 'cnt.external-citations',\n stableId: 'cnt.external-citations',\n category: 'content',\n group: 'opportunity',\n weight: 2,\n impact: 'medium',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#cntexternal-citations',\n title: 'Content cites external sources',\n title_ko: '외부 출처 인용 여부',\n description:\n 'Outbound links to authoritative external sources are an E-E-A-T trust signal. AI engines treat well-cited pages as more credible.',\n run(ctx) {\n let host: string;\n try {\n host = new URL(ctx.finalUrl).hostname.toLowerCase();\n } catch {\n return { status: 'skip', score: 0, rationale: 'Invalid finalUrl.', rationale_ko: '유효하지 않은 finalUrl입니다.' };\n }\n const seen = new Set<string>();\n ctx.$('main a[href], article a[href], body a[href]').each((_i, el) => {\n const href = ctx.$(el).attr('href');\n if (!href || href.startsWith('#') || href.startsWith('mailto:') || href.startsWith('tel:')) return;\n const rel = (ctx.$(el).attr('rel') ?? '').toLowerCase();\n if (rel.includes('nofollow') || rel.includes('sponsored')) return;\n let linkHost: string;\n try {\n linkHost = new URL(href, ctx.finalUrl).hostname.toLowerCase();\n } catch {\n return;\n }\n if (!linkHost) return;\n if (linkHost === host) return;\n if (linkHost.endsWith('.' + host) || host.endsWith('.' + linkHost)) return;\n seen.add(linkHost);\n });\n const count = seen.size;\n if (count >= 3) {\n return {\n status: 'pass',\n score: 1,\n rationale: `${count} distinct external host(s) cited (excluding nofollow).`,\n rationale_ko: `외부 사이트 ${count}개를 인용합니다 (nofollow 제외).`,\n evidence: { hosts: [...seen].slice(0, 8) },\n };\n }\n if (count >= 1) {\n return {\n status: 'pass',\n score: 0.7,\n rationale: `${count} external host(s) cited. Aim for ≥3 for stronger E-E-A-T.`,\n rationale_ko: `외부 사이트 ${count}개를 인용합니다. E-E-A-T 강화를 위해 3개 이상을 목표로 하세요.`,\n evidence: { hosts: [...seen] },\n estimatedImpact: 1,\n };\n }\n return {\n status: 'warn',\n score: 0,\n rationale: 'No external follow citations found in main content.',\n rationale_ko: '본문에 외부 출처 링크가 없습니다.',\n fixHint: 'Cite at least one authoritative external source (research paper, official docs, news outlet).',\n estimatedImpact: 2,\n };\n },\n});\n","import { singleH1Rule } from './single-h1.js';\nimport { headingHierarchyRule } from './heading-hierarchy.js';\nimport { imageAltRule } from './image-alt.js';\nimport { tldrOrFaqRule } from './tldr-or-faq.js';\nimport { wordCountRule } from './word-count.js';\nimport { qaStructureRule } from './qa-structure.js';\nimport { externalCitationsRule } from './external-citations.js';\n\nexport const contentRules = [\n singleH1Rule,\n headingHierarchyRule,\n imageAltRule,\n tldrOrFaqRule,\n wordCountRule,\n qaStructureRule,\n externalCitationsRule,\n];\n","import { defineRule } from '../../types.js';\n\nexport const aeoSkillMdRule = defineRule({\n id: 'aeo.skill-md',\n stableId: 'aeo.skill-md',\n category: 'aeo',\n group: 'opportunity',\n weight: 3,\n impact: 'high',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#aeoskill-md',\n title: 'skill.md is present',\n title_ko: 'skill.md 파일 존재 여부',\n description: 'A /skill.md file describes site capabilities so AI agents know what this site can do for them.',\n run(ctx) {\n if (ctx.skillMd !== null) {\n return {\n status: 'pass',\n score: 1,\n rationale: 'skill.md found at site root.',\n rationale_ko: 'skill.md가 사이트 루트에 존재합니다.',\n };\n }\n return {\n status: 'warn',\n score: 0,\n rationale: 'No /skill.md found. Add one to describe your site capabilities to AI agents.',\n rationale_ko: '/skill.md가 없습니다. AI 에이전트가 사이트 기능을 파악할 수 있도록 추가하세요.',\n fixHint: 'Create /skill.md listing what services, products, and capabilities this site offers.',\n };\n },\n});\n","import { defineRule } from '../../types.js';\n\nexport const aeoAgentPermissionsRule = defineRule({\n id: 'aeo.agent-permissions',\n stableId: 'aeo.agent-permissions',\n category: 'aeo',\n group: 'opportunity',\n weight: 3,\n impact: 'medium',\n effort: 'low',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#aeoagent-permissions',\n title: 'agent-permissions.json is present',\n title_ko: 'agent-permissions.json 파일 존재 여부',\n description: 'Declares explicit read/summarize/cite/train permissions for AI agents.',\n run(ctx) {\n if (ctx.agentPermissions !== null) {\n return {\n status: 'pass',\n score: 1,\n rationale: 'agent-permissions.json found at site root.',\n rationale_ko: 'agent-permissions.json이 사이트 루트에 존재합니다.',\n evidence: ctx.agentPermissions,\n };\n }\n return {\n status: 'warn',\n score: 0,\n rationale: 'No /agent-permissions.json found. Add one to declare AI agent access policy.',\n rationale_ko: '/agent-permissions.json이 없습니다. AI 에이전트 접근 정책을 명시하려면 추가하세요.',\n fixHint: 'Create /agent-permissions.json with read, summarize, cite, and train permission flags.',\n };\n },\n});\n","import { defineRule } from '../../types.js';\n\nconst THRESHOLD_OPTIMAL = 15_000;\nconst THRESHOLD_MAX = 25_000;\n\nexport const aeoTokenLengthRule = defineRule({\n id: 'aeo.token-length',\n stableId: 'aeo.token-length',\n category: 'aeo',\n group: 'diagnostic',\n weight: 4,\n impact: 'medium',\n effort: 'medium',\n docsUrl: 'https://github.com/BaRam-OSS/geo-checker/blob/main/docs/rules.md#aeotoken-length',\n title: 'Content token length within AI agent limits',\n title_ko: '콘텐츠 토큰 수 AI 에이전트 권장 범위',\n description: 'Pages under 15K tokens are optimal for AI agents (per Addy Osmani\\'s AEO guidance).',\n run(ctx) {\n const text = ctx.$('body').text();\n const tokenEstimate = Math.round(text.length / 3);\n const evidence = { tokenEstimate, thresholds: { optimal: THRESHOLD_OPTIMAL, max: THRESHOLD_MAX } };\n\n if (tokenEstimate <= THRESHOLD_OPTIMAL) {\n return {\n status: 'pass',\n score: 1,\n rationale: `Estimated ~${tokenEstimate.toLocaleString()} tokens — within optimal range.`,\n rationale_ko: `예상 토큰 수 ~${tokenEstimate.toLocaleString()} — 권장 범위(15K) 이내입니다.`,\n evidence,\n };\n }\n if (tokenEstimate <= THRESHOLD_MAX) {\n return {\n status: 'warn',\n score: 0.5,\n rationale: `Estimated ~${tokenEstimate.toLocaleString()} tokens — exceeds 15K recommendation.`,\n rationale_ko: `예상 토큰 수 ~${tokenEstimate.toLocaleString()} — 15K 권장치를 초과합니다.`,\n fixHint: 'Consider splitting content into shorter, focused pages.',\n evidence,\n };\n }\n return {\n status: 'fail',\n score: 0,\n rationale: `Estimated ~${tokenEstimate.toLocaleString()} tokens — exceeds 25K agent processing limit.`,\n rationale_ko: `예상 토큰 수 ~${tokenEstimate.toLocaleString()} — AI 에이전트 처리 한계(25K)를 초과합니다.`,\n fixHint: 'Split this page into multiple focused pages under 15K tokens.',\n evidence,\n };\n },\n});\n","import { aeoSkillMdRule } from './skill-md.js';\nimport { aeoAgentPermissionsRule } from './agent-permissions.js';\nimport { aeoTokenLengthRule } from './token-length.js';\n\nexport const aeoRules = [aeoSkillMdRule, aeoAgentPermissionsRule, aeoTokenLengthRule];\n","import type { Rule } from '../types.js';\nimport { crawlerRules } from './crawler/index.js';\nimport { structuredDataRules } from './structured-data/index.js';\nimport { citationRules } from './citation/index.js';\nimport { contentRules } from './content/index.js';\nimport { aeoRules } from './aeo/index.js';\n\nexport const defaultRules: Rule[] = [\n ...crawlerRules,\n ...structuredDataRules,\n ...citationRules,\n ...contentRules,\n ...aeoRules,\n];\n\nexport { crawlerRules, structuredDataRules, citationRules, contentRules, aeoRules };\n","import { readFile, stat } from 'node:fs/promises';\nimport { pathToFileURL } from 'node:url';\nimport { resolve } from 'node:path';\nimport type { Category, GeoConfig, Rule } from './types.js';\nimport { CATEGORY_WEIGHTS } from './types.js';\n\nconst CANDIDATE_NAMES = ['geo-checker.config.json', 'geo-checker.config.mjs', 'geo-checker.config.js'];\n\nexport interface LoadedConfig {\n config: GeoConfig;\n path: string | null;\n}\n\nasync function fileExists(p: string): Promise<boolean> {\n try {\n const s = await stat(p);\n return s.isFile();\n } catch {\n return false;\n }\n}\n\nexport async function findConfig(cwd: string): Promise<string | null> {\n for (const name of CANDIDATE_NAMES) {\n const p = resolve(cwd, name);\n if (await fileExists(p)) return p;\n }\n return null;\n}\n\nexport async function loadConfig(explicitPath: string | null, cwd: string = process.cwd()): Promise<LoadedConfig> {\n const path = explicitPath ? resolve(cwd, explicitPath) : await findConfig(cwd);\n if (!path) return { config: {}, path: null };\n if (!(await fileExists(path))) {\n throw new Error(`Config file not found: ${path}`);\n }\n if (path.endsWith('.json')) {\n const raw = await readFile(path, 'utf8');\n return { config: JSON.parse(raw) as GeoConfig, path };\n }\n const url = pathToFileURL(path).href;\n const mod = (await import(url)) as { default?: GeoConfig } & GeoConfig;\n const config = (mod.default ?? mod) as GeoConfig;\n return { config, path };\n}\n\nexport interface ApplyResult {\n rules: Rule[];\n categoryWeights: Record<Category, number>;\n}\n\nexport function applyConfig(defaultRules: Rule[], config: GeoConfig | undefined): ApplyResult {\n const categoryWeights: Record<Category, number> = { ...CATEGORY_WEIGHTS };\n if (!config) return { rules: defaultRules, categoryWeights };\n\n const merged = [...defaultRules, ...(config.extraRules ?? [])];\n const ruleOverrides = config.rules ?? {};\n\n const rules = merged\n .map((r) => {\n const key = r.stableId ?? r.id;\n const o = ruleOverrides[key] ?? ruleOverrides[r.id];\n if (!o) return r;\n if (o.enabled === false) return null;\n if (typeof o.weight === 'number' && o.weight > 0) {\n return { ...r, weight: o.weight };\n }\n return r;\n })\n .filter((r): r is Rule => r !== null);\n\n if (config.categories) {\n for (const [cat, override] of Object.entries(config.categories)) {\n if (override?.weight && override.weight > 0) {\n categoryWeights[cat as Category] = override.weight;\n }\n }\n }\n\n return { rules, categoryWeights };\n}\n","import type { AuditOptions, AuditReport } from './types.js';\nimport { audit } from './index.js';\n\nexport interface BatchOptions extends AuditOptions {\n concurrency?: number;\n onProgress?: (event: BatchProgressEvent) => void;\n}\n\nexport interface BatchSuccess {\n url: string;\n report: AuditReport;\n}\n\nexport interface BatchFailure {\n url: string;\n error: string;\n}\n\nexport type BatchResult = ({ ok: true } & BatchSuccess) | ({ ok: false } & BatchFailure);\n\nexport interface BatchSummary {\n total: number;\n successes: number;\n failures: number;\n averageOverall: number;\n worstOverall: number | null;\n bestOverall: number | null;\n results: BatchResult[];\n}\n\nexport type BatchProgressEvent =\n | { kind: 'start'; url: string; index: number; total: number }\n | { kind: 'success'; url: string; overall: number; index: number; total: number }\n | { kind: 'failure'; url: string; error: string; index: number; total: number };\n\nexport async function runBatch(urls: string[], options: BatchOptions = {}): Promise<BatchSummary> {\n const concurrency = Math.max(1, options.concurrency ?? 4);\n const results: BatchResult[] = new Array(urls.length);\n const onProgress = options.onProgress;\n const auditOpts: AuditOptions = { ...options };\n delete (auditOpts as BatchOptions).concurrency;\n delete (auditOpts as BatchOptions).onProgress;\n\n let cursor = 0;\n async function worker(): Promise<void> {\n for (;;) {\n const i = cursor++;\n if (i >= urls.length) return;\n const url = urls[i]!;\n onProgress?.({ kind: 'start', url, index: i, total: urls.length });\n try {\n const report = await audit(url, auditOpts);\n results[i] = { ok: true, url, report };\n onProgress?.({ kind: 'success', url, overall: report.overall, index: i, total: urls.length });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n results[i] = { ok: false, url, error: message };\n onProgress?.({ kind: 'failure', url, error: message, index: i, total: urls.length });\n }\n }\n }\n\n await Promise.all(Array.from({ length: Math.min(concurrency, urls.length) }, worker));\n\n const successes = results.filter((r): r is BatchResult & { ok: true } => r.ok);\n const failures = results.filter((r): r is BatchResult & { ok: false } => !r.ok);\n const overalls = successes.map((s) => s.report.overall);\n const averageOverall =\n overalls.length === 0 ? 0 : Math.round(overalls.reduce((a, b) => a + b, 0) / overalls.length);\n\n return {\n total: urls.length,\n successes: successes.length,\n failures: failures.length,\n averageOverall,\n worstOverall: overalls.length === 0 ? null : Math.min(...overalls),\n bestOverall: overalls.length === 0 ? null : Math.max(...overalls),\n results,\n };\n}\n\nexport function summaryToJson(summary: BatchSummary): string {\n return JSON.stringify(\n {\n total: summary.total,\n successes: summary.successes,\n failures: summary.failures,\n averageOverall: summary.averageOverall,\n worstOverall: summary.worstOverall,\n bestOverall: summary.bestOverall,\n results: summary.results.map((r) =>\n r.ok\n ? {\n ok: true,\n url: r.url,\n overall: r.report.overall,\n categories: Object.fromEntries(\n Object.entries(r.report.categories).map(([k, v]) => [k, v.score]),\n ),\n }\n : { ok: false, url: r.url, error: r.error },\n ),\n },\n null,\n 2,\n );\n}\n\nexport function urlToSlug(url: string): string {\n try {\n const u = new URL(url);\n const base = (u.hostname + u.pathname).replace(/\\/+$/, '');\n const slug = base.replace(/[^a-zA-Z0-9.-]+/g, '_').replace(/^_+|_+$/g, '');\n return slug || 'page';\n } catch {\n return url.replace(/[^a-zA-Z0-9.-]+/g, '_').slice(0, 80) || 'page';\n }\n}\n","import type { AuditReport, Category } from '../types.js';\n\nconst COLS = [\n 'url',\n 'category',\n 'id',\n 'stableId',\n 'title',\n 'status',\n 'score',\n 'weight',\n 'group',\n 'impact',\n 'effort',\n 'estimatedImpact',\n 'durationMs',\n 'rationale',\n 'docsUrl',\n] as const;\n\nfunction escape(v: unknown): string {\n if (v === undefined || v === null) return '';\n const s = String(v);\n if (/[\",\\n\\r]/.test(s)) return `\"${s.replace(/\"/g, '\"\"')}\"`;\n return s;\n}\n\nexport function toCsv(report: AuditReport): string {\n const rows: string[] = [COLS.join(',')];\n for (const cat of Object.keys(report.categories) as Category[]) {\n for (const r of report.categories[cat].results) {\n rows.push(\n [\n report.finalUrl,\n cat,\n r.id,\n r.stableId ?? '',\n r.title,\n r.status,\n r.score,\n r.weight,\n r.group ?? '',\n r.impact ?? '',\n r.effort ?? '',\n r.estimatedImpact ?? '',\n r.durationMs ?? '',\n r.rationale,\n r.docsUrl ?? '',\n ]\n .map(escape)\n .join(','),\n );\n }\n }\n return rows.join('\\n') + '\\n';\n}\n","import type { AuditReport, Category, Status } from '../types.js';\n\nconst CATEGORY_LABELS: Record<Category, string> = {\n crawler: 'AI Crawler Access',\n 'structured-data': 'Structured Data',\n citation: 'Citation Signals',\n content: 'Content Structure',\n aeo: 'AEO Stack',\n};\n\nfunction scoreBadge(score: number): string {\n const color = score >= 85 ? 'brightgreen' : score >= 60 ? 'yellow' : 'red';\n return ``;\n}\n\nfunction statusEmoji(s: Status): string {\n switch (s) {\n case 'pass':\n return '✅';\n case 'warn':\n return '⚠️';\n case 'fail':\n return '❌';\n default:\n return '⏭️';\n }\n}\n\nfunction escapeMd(s: string): string {\n return s.replace(/\\|/g, '\\\\|').replace(/\\r?\\n/g, ' ');\n}\n\nexport function toMarkdown(report: AuditReport): string {\n const lines: string[] = [];\n lines.push(`## geo-checker · ${report.finalUrl}`);\n lines.push('');\n lines.push(`**Overall:** ${scoreBadge(report.overall)}`);\n lines.push('');\n lines.push('| Category | Score |');\n lines.push('| --- | --- |');\n for (const cat of Object.keys(report.categories) as Category[]) {\n const b = report.categories[cat];\n if (b.results.length === 0) continue;\n lines.push(`| ${CATEGORY_LABELS[cat]} | ${scoreBadge(b.score)} |`);\n }\n lines.push('');\n const failing = Object.values(report.categories)\n .flatMap((c) => c.results)\n .filter((r) => r.status === 'fail' || r.status === 'warn')\n .sort((a, b) => (b.estimatedImpact ?? 0) - (a.estimatedImpact ?? 0));\n if (failing.length > 0) {\n lines.push('### Issues to address');\n lines.push('');\n lines.push('| | Rule | Impact | Hint |');\n lines.push('| --- | --- | --- | --- |');\n for (const r of failing) {\n const idLink = r.docsUrl ? `[${r.stableId ?? r.id}](${r.docsUrl})` : (r.stableId ?? r.id);\n const impact = r.impact ? `\\`${r.impact}\\`` : '';\n const hint = escapeMd(r.fixHint ?? r.rationale);\n lines.push(`| ${statusEmoji(r.status)} | ${idLink} | ${impact} | ${hint} |`);\n }\n lines.push('');\n } else {\n lines.push('All audited rules pass. ✅');\n lines.push('');\n }\n if (report.warnings.length > 0) {\n lines.push('> ' + report.warnings.map(escapeMd).join(' \\n> '));\n lines.push('');\n }\n lines.push(\n `<sub>geo-checker v${report.version} · ${report.renderMode} · fetched ${report.fetchedAt} · ${report.timing.totalMs}ms</sub>`,\n );\n lines.push('');\n return lines.join('\\n');\n}\n","import type { AuditReport, RuleResultEntry, Status } from '../types.js';\n\ninterface SarifLocation {\n physicalLocation: {\n artifactLocation: { uri: string };\n region?: { startLine?: number; startColumn?: number; snippet?: { text: string } };\n };\n}\n\ninterface SarifResult {\n ruleId: string;\n level: 'error' | 'warning' | 'note' | 'none';\n message: { text: string };\n locations: SarifLocation[];\n properties?: { score: number; weight: number; impact?: string; effort?: string; estimatedImpact?: number };\n}\n\ninterface SarifRule {\n id: string;\n name: string;\n shortDescription: { text: string };\n fullDescription: { text: string };\n helpUri?: string;\n defaultConfiguration: { level: 'error' | 'warning' | 'note' };\n properties: { category: string; weight: number; impact?: string; effort?: string };\n}\n\nfunction statusToLevel(s: Status): 'error' | 'warning' | 'note' | 'none' {\n if (s === 'fail') return 'error';\n if (s === 'warn') return 'warning';\n if (s === 'skip') return 'none';\n return 'note';\n}\n\nfunction buildLocations(uri: string, r: RuleResultEntry): SarifLocation[] {\n const locs = r.locations ?? [];\n if (locs.length === 0) {\n return [{ physicalLocation: { artifactLocation: { uri } } }];\n }\n return locs.map((l) => {\n const loc: SarifLocation = { physicalLocation: { artifactLocation: { uri } } };\n if (l.line !== undefined || l.col !== undefined || l.snippet) {\n loc.physicalLocation.region = {};\n if (l.line !== undefined) loc.physicalLocation.region.startLine = l.line;\n if (l.col !== undefined) loc.physicalLocation.region.startColumn = l.col;\n if (l.snippet) loc.physicalLocation.region.snippet = { text: l.snippet };\n }\n return loc;\n });\n}\n\nexport function toSarif(report: AuditReport): string {\n const allResults = Object.values(report.categories).flatMap((c) => c.results);\n const seenRules = new Map<string, SarifRule>();\n const sarifResults: SarifResult[] = [];\n\n for (const r of allResults) {\n const id = r.stableId ?? r.id;\n if (!seenRules.has(id)) {\n const rule: SarifRule = {\n id,\n name: r.title,\n shortDescription: { text: r.title },\n fullDescription: { text: r.rationale },\n defaultConfiguration: { level: statusToLevel(r.status) === 'note' ? 'note' : statusToLevel(r.status) === 'error' ? 'error' : 'warning' },\n properties: {\n category: categoryOf(report, r.id),\n weight: r.weight,\n ...(r.impact ? { impact: r.impact } : {}),\n ...(r.effort ? { effort: r.effort } : {}),\n },\n };\n if (r.docsUrl) rule.helpUri = r.docsUrl;\n seenRules.set(id, rule);\n }\n if (r.status === 'fail' || r.status === 'warn') {\n const sr: SarifResult = {\n ruleId: id,\n level: statusToLevel(r.status),\n message: { text: r.fixHint ? `${r.rationale} — ${r.fixHint}` : r.rationale },\n locations: buildLocations(report.finalUrl, r),\n properties: {\n score: r.score,\n weight: r.weight,\n ...(r.impact ? { impact: r.impact } : {}),\n ...(r.effort ? { effort: r.effort } : {}),\n ...(r.estimatedImpact !== undefined ? { estimatedImpact: r.estimatedImpact } : {}),\n },\n };\n sarifResults.push(sr);\n }\n }\n\n const sarif = {\n $schema: 'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json',\n version: '2.1.0',\n runs: [\n {\n tool: {\n driver: {\n name: 'geo-checker',\n version: report.version,\n informationUri: 'https://github.com/BaRam-OSS/geo-checker',\n rules: [...seenRules.values()],\n },\n },\n results: sarifResults,\n invocations: [\n {\n executionSuccessful: true,\n startTimeUtc: report.fetchedAt,\n },\n ],\n },\n ],\n };\n return JSON.stringify(sarif, null, 2);\n}\n\nfunction categoryOf(report: AuditReport, ruleId: string): string {\n for (const [cat, bucket] of Object.entries(report.categories)) {\n if (bucket.results.some((r) => r.id === ruleId)) return cat;\n }\n return 'unknown';\n}\n","import type { AuditReport, Category, RuleResultEntry } from '../types.js';\n\nexport interface RuleDelta {\n id: string;\n stableId?: string;\n category: Category;\n before: RuleResultEntry['status'];\n after: RuleResultEntry['status'];\n scoreDelta: number;\n}\n\nexport interface CategoryDelta {\n category: Category;\n before: number;\n after: number;\n delta: number;\n}\n\nexport interface ReportDiff {\n before: { url: string; overall: number; version: string; fetchedAt: string };\n after: { url: string; overall: number; version: string; fetchedAt: string };\n overallDelta: number;\n categories: CategoryDelta[];\n regressions: RuleDelta[];\n fixes: RuleDelta[];\n newFailures: RuleDelta[];\n}\n\nconst SEVERITY: Record<RuleResultEntry['status'], number> = { skip: 0, pass: 1, warn: 2, fail: 3 };\n\nfunction indexResults(report: AuditReport): Map<string, { entry: RuleResultEntry; category: Category }> {\n const map = new Map<string, { entry: RuleResultEntry; category: Category }>();\n for (const cat of Object.keys(report.categories) as Category[]) {\n for (const r of report.categories[cat].results) {\n const key = r.stableId ?? r.id;\n map.set(key, { entry: r, category: cat });\n }\n }\n return map;\n}\n\nexport function diffReports(before: AuditReport, after: AuditReport): ReportDiff {\n const beforeMap = indexResults(before);\n const afterMap = indexResults(after);\n\n const regressions: RuleDelta[] = [];\n const fixes: RuleDelta[] = [];\n const newFailures: RuleDelta[] = [];\n\n for (const [key, b] of beforeMap) {\n const a = afterMap.get(key);\n if (!a) continue;\n const before = b.entry.status;\n const after = a.entry.status;\n if (SEVERITY[after] > SEVERITY[before]) {\n regressions.push({\n id: a.entry.id,\n ...(a.entry.stableId !== undefined ? { stableId: a.entry.stableId } : {}),\n category: a.category,\n before,\n after,\n scoreDelta: a.entry.score - b.entry.score,\n });\n } else if (SEVERITY[after] < SEVERITY[before] && (before === 'fail' || before === 'warn')) {\n fixes.push({\n id: a.entry.id,\n ...(a.entry.stableId !== undefined ? { stableId: a.entry.stableId } : {}),\n category: a.category,\n before,\n after,\n scoreDelta: a.entry.score - b.entry.score,\n });\n }\n }\n\n for (const [key, a] of afterMap) {\n if (beforeMap.has(key)) continue;\n if (a.entry.status === 'fail' || a.entry.status === 'warn') {\n newFailures.push({\n id: a.entry.id,\n ...(a.entry.stableId !== undefined ? { stableId: a.entry.stableId } : {}),\n category: a.category,\n before: 'skip',\n after: a.entry.status,\n scoreDelta: a.entry.score,\n });\n }\n }\n\n const categories: CategoryDelta[] = (Object.keys(after.categories) as Category[]).map((c) => ({\n category: c,\n before: before.categories[c]?.score ?? 0,\n after: after.categories[c].score,\n delta: after.categories[c].score - (before.categories[c]?.score ?? 0),\n }));\n\n return {\n before: { url: before.finalUrl, overall: before.overall, version: before.version, fetchedAt: before.fetchedAt },\n after: { url: after.finalUrl, overall: after.overall, version: after.version, fetchedAt: after.fetchedAt },\n overallDelta: after.overall - before.overall,\n categories,\n regressions,\n fixes,\n newFailures,\n };\n}\n\nconst ARROW_UP = '↑';\nconst ARROW_DOWN = '↓';\nconst ARROW_FLAT = '·';\n\nfunction arrow(d: number): string {\n if (d > 0) return ARROW_UP;\n if (d < 0) return ARROW_DOWN;\n return ARROW_FLAT;\n}\n\nexport function formatDiffLine(diff: ReportDiff): string {\n const overall = `overall ${arrow(diff.overallDelta)} ${diff.overallDelta >= 0 ? '+' : ''}${diff.overallDelta}`;\n const cats = diff.categories\n .filter((c) => c.delta !== 0)\n .map((c) => `${c.category} ${arrow(c.delta)} ${c.delta >= 0 ? '+' : ''}${c.delta}`)\n .join(' · ');\n const reg = diff.regressions.length;\n const fix = diff.fixes.length;\n const nu = diff.newFailures.length;\n const tail = [\n reg > 0 ? `🆕 ${reg} regression${reg > 1 ? 's' : ''}` : '',\n nu > 0 ? `+${nu} new fail${nu > 1 ? 's' : ''}` : '',\n fix > 0 ? `✅ ${fix} fixed` : '',\n ]\n .filter(Boolean)\n .join(' · ');\n return [overall, cats, tail].filter(Boolean).join(' · ');\n}\n","import type { AuditOptions, AuditReport } from './types.js';\nimport { buildContext } from './context.js';\nimport { runRules } from './engine.js';\nimport { defaultRules } from './rules/index.js';\nimport { applyConfig, loadConfig } from './config.js';\n\nexport { defineRule, CATEGORY_WEIGHTS } from './types.js';\nexport { defaultRules } from './rules/index.js';\nexport { runBatch, summaryToJson, urlToSlug } from './batch.js';\nexport type { BatchOptions, BatchResult, BatchSuccess, BatchFailure, BatchSummary, BatchProgressEvent } from './batch.js';\nexport { toCsv } from './reporters/csv.js';\nexport { toMarkdown } from './reporters/markdown.js';\nexport { toSarif } from './reporters/sarif.js';\nexport { diffReports, formatDiffLine } from './reporters/diff.js';\nexport type { ReportDiff, RuleDelta, CategoryDelta } from './reporters/diff.js';\nexport { loadConfig, findConfig, applyConfig } from './config.js';\nexport type {\n Status,\n Category,\n Rule,\n RuleResult,\n AuditContext,\n AuditOptions,\n AuditReport,\n CategoryReport,\n RobotsTxt,\n RobotsRuleGroup,\n LlmsTxt,\n LlmsTxtLink,\n LlmsTxtSection,\n SitemapSummary,\n GeoConfig,\n RuleOverride,\n} from './types.js';\n\nexport async function audit(url: string, options: AuditOptions = {}): Promise<AuditReport> {\n const startedAt = performance.now();\n\n let config = options.config;\n let configPath = options.configPath ?? null;\n if (!config && configPath) {\n const loaded = await loadConfig(configPath);\n config = loaded.config;\n configPath = loaded.path;\n }\n\n const ctx = await buildContext(url, {\n ...(options.render ? { render: true } : {}),\n ...(options.userAgent !== undefined ? { userAgent: options.userAgent } : {}),\n ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n });\n const fetchMs = Math.round(performance.now() - startedAt);\n\n const baseRules = [...defaultRules, ...(options.extraRules ?? [])];\n const { rules, categoryWeights } = applyConfig(baseRules, config);\n\n const meta: { userAgent?: string; configPath?: string } = {};\n if (options.userAgent !== undefined) meta.userAgent = options.userAgent;\n if (configPath) meta.configPath = configPath;\n\n return runRules(ctx, rules, {\n ...(options.only ? { only: options.only } : {}),\n ...(options.categories ? { categories: options.categories } : {}),\n ...(Object.keys(meta).length > 0 ? { meta } : {}),\n categoryWeights,\n fetchMs,\n startedAt,\n });\n}\n","import type { AuditReport } from '../types.js';\n\nexport function toJson(report: AuditReport, pretty = true): string {\n return pretty ? JSON.stringify(report, null, 2) : JSON.stringify(report);\n}\n","import kleur from 'kleur';\nimport Table from 'cli-table3';\nimport type { AuditReport, Category, Impact, Status } from '../types.js';\n\nconst CATEGORY_LABELS: Record<Category, string> = {\n crawler: 'AI Crawler Access',\n 'structured-data': 'Structured Data',\n citation: 'Citation Signals',\n content: 'Content Structure',\n aeo: 'AEO Stack',\n};\n\nfunction colorScore(score: number): string {\n if (score >= 85) return kleur.green().bold(`${score}`);\n if (score >= 60) return kleur.yellow().bold(`${score}`);\n return kleur.red().bold(`${score}`);\n}\n\nfunction statusBadge(status: Status): string {\n switch (status) {\n case 'pass':\n return kleur.green('pass');\n case 'warn':\n return kleur.yellow('warn');\n case 'fail':\n return kleur.red('fail');\n default:\n return kleur.gray('skip');\n }\n}\n\nfunction impactChip(impact?: Impact): string {\n if (!impact) return '';\n switch (impact) {\n case 'critical':\n return kleur.red().bold('[crit]');\n case 'high':\n return kleur.red('[high]');\n case 'medium':\n return kleur.yellow('[med]');\n case 'low':\n return kleur.gray('[low]');\n }\n}\n\nfunction renderNote(rationale: string, impact?: Impact, estimatedImpact?: number): string {\n const parts: string[] = [];\n const chip = impactChip(impact);\n if (chip) parts.push(chip);\n if (estimatedImpact !== undefined && estimatedImpact > 0) {\n parts.push(kleur.cyan(`+${estimatedImpact}`));\n }\n parts.push(rationale);\n return parts.join(' ');\n}\n\nfunction bar(score: number, width = 20): string {\n const filled = Math.round((score / 100) * width);\n const empty = width - filled;\n const color = score >= 85 ? kleur.green : score >= 60 ? kleur.yellow : kleur.red;\n return color('█'.repeat(filled)) + kleur.gray('░'.repeat(empty));\n}\n\nexport function toCli(report: AuditReport): string {\n const lines: string[] = [];\n lines.push('');\n lines.push(\n kleur.bold('geo-checker') +\n kleur.gray(' · ') +\n report.finalUrl +\n kleur.gray(` (${report.renderMode})`),\n );\n lines.push(\n kleur.gray('fetched ') +\n report.fetchedAt +\n kleur.gray(' · v') +\n report.version +\n kleur.gray(\n ` · fetch ${report.timing.fetchMs}ms, audit ${report.timing.auditMs}ms, total ${report.timing.totalMs}ms`,\n ),\n );\n lines.push('');\n lines.push(kleur.bold('Overall ') + colorScore(report.overall) + kleur.gray(' / 100'));\n lines.push('');\n\n for (const w of report.warnings) {\n lines.push(kleur.yellow('! ') + w);\n }\n if (report.warnings.length > 0) lines.push('');\n\n for (const cat of Object.keys(report.categories) as Category[]) {\n const b = report.categories[cat];\n if (b.results.length === 0) continue;\n lines.push(\n ` ${kleur.bold(CATEGORY_LABELS[cat].padEnd(20))} ${bar(b.score)} ${colorScore(b.score).padStart(3)}/100`,\n );\n const table = new Table({\n head: [kleur.gray('status'), kleur.gray('rule'), kleur.gray('note')],\n colWidths: [7, 34, 70],\n wordWrap: true,\n style: { head: [], border: ['grey'] },\n });\n for (const r of b.results) {\n table.push([statusBadge(r.status), r.id, renderNote(r.rationale, r.impact, r.estimatedImpact)]);\n }\n lines.push(\n table\n .toString()\n .split('\\n')\n .map((l) => ' ' + l)\n .join('\\n'),\n );\n lines.push('');\n }\n\n const fixUrls = Object.values(report.categories)\n .flatMap((c) => c.results)\n .filter((r) => (r.status === 'fail' || r.status === 'warn') && r.fixUrl)\n .map((r) => ` - ${r.id}: ${r.fixUrl}`);\n if (fixUrls.length > 0) {\n lines.push(kleur.bold('How to fix:'));\n lines.push(...fixUrls);\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n","import type {\n AuditReport,\n Category,\n EvidenceLocation,\n Impact,\n RuleResultEntry,\n Status,\n} from '../types.js';\n\nconst CATEGORY_LABELS: Record<Category, string> = {\n crawler: 'AI Crawler Access',\n 'structured-data': 'Structured Data',\n citation: 'Citation Signals',\n content: 'Content Structure',\n aeo: 'AEO Stack',\n};\n\nconst IMPACT_ORDER: Record<Impact, number> = {\n critical: 4,\n high: 3,\n medium: 2,\n low: 1,\n};\n\nfunction esc(s: unknown): string {\n if (s === null || s === undefined) return '';\n return String(s)\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\nfunction scoreClass(score: number): 'good' | 'avg' | 'poor' {\n if (score >= 85) return 'good';\n if (score >= 60) return 'avg';\n return 'poor';\n}\n\nfunction ring(score: number, label: string, size = 128): string {\n const r = size / 2 - 8;\n const c = 2 * Math.PI * r;\n const offset = c * (1 - score / 100);\n const cls = scoreClass(score);\n return `<div class=\"ring ring-${cls}\">\n <svg viewBox=\"0 0 ${size} ${size}\" width=\"${size}\" height=\"${size}\" aria-hidden=\"true\">\n <circle cx=\"${size / 2}\" cy=\"${size / 2}\" r=\"${r}\" class=\"ring-track\" />\n <circle cx=\"${size / 2}\" cy=\"${size / 2}\" r=\"${r}\" class=\"ring-value\"\n stroke-dasharray=\"${c.toFixed(2)}\" stroke-dashoffset=\"${offset.toFixed(2)}\" />\n </svg>\n <div class=\"ring-num\">${score}</div>\n <div class=\"ring-label\">${esc(label)}</div>\n </div>`;\n}\n\nfunction statusChip(status: Status): string {\n return `<span class=\"chip chip-${status}\">${status}</span>`;\n}\n\nfunction impactChip(impact?: Impact): string {\n if (!impact) return '';\n return `<span class=\"chip chip-impact chip-impact-${impact}\">impact: ${impact}</span>`;\n}\n\nfunction effortChip(effort?: string): string {\n if (!effort) return '';\n return `<span class=\"chip chip-effort\">effort: ${esc(effort)}</span>`;\n}\n\nfunction locationBlock(locations?: EvidenceLocation[]): string {\n if (!locations || locations.length === 0) return '';\n const items = locations\n .map((loc) => {\n const parts: string[] = [];\n if (loc.selector) parts.push(`<code class=\"sel\">${esc(loc.selector)}</code>`);\n if (loc.line !== undefined) parts.push(`line ${loc.line}${loc.col !== undefined ? `:${loc.col}` : ''}`);\n const head = parts.length > 0 ? `<div class=\"loc-head\">${parts.join(' · ')}</div>` : '';\n const snippet = loc.snippet ? `<pre class=\"snippet\">${esc(loc.snippet)}</pre>` : '';\n return `<li class=\"loc\">${head}${snippet}</li>`;\n })\n .join('');\n return `<ul class=\"locations\">${items}</ul>`;\n}\n\nfunction auditRow(r: RuleResultEntry): string {\n const impact = impactChip(r.impact);\n const effort = effortChip(r.effort);\n const est =\n r.estimatedImpact !== undefined\n ? `<span class=\"chip chip-est\">est +${r.estimatedImpact}</span>`\n : '';\n const docs = r.docsUrl\n ? `<a class=\"docs\" href=\"${esc(r.docsUrl)}\" target=\"_blank\" rel=\"noopener\">docs ↗</a>`\n : '';\n const fixHint = r.fixHint ? `<div class=\"fix-hint\">${esc(r.fixHint)}</div>` : '';\n const id = esc(r.stableId ?? r.id);\n const score = Math.round(r.score * 100);\n return `<div class=\"audit audit-${r.status}\" data-stable-id=\"${id}\">\n <div class=\"audit-head\">\n ${statusChip(r.status)}\n <span class=\"audit-title\">${esc(r.title)}</span>\n <span class=\"audit-score\">${score}</span>\n ${impact}${effort}${est}\n ${docs}\n </div>\n <div class=\"audit-id\"><code>${id}</code> · weight ${r.weight}${r.durationMs !== undefined ? ` · ${r.durationMs}ms` : ''}</div>\n <div class=\"audit-rationale\">${esc(r.rationale)}</div>\n ${fixHint}\n ${locationBlock(r.locations)}\n </div>`;\n}\n\nfunction partitionResults(report: AuditReport): {\n opportunities: RuleResultEntry[];\n diagnostics: Record<Category, RuleResultEntry[]>;\n passed: Record<Category, RuleResultEntry[]>;\n} {\n const opportunities: RuleResultEntry[] = [];\n const diagnostics: Record<Category, RuleResultEntry[]> = {\n crawler: [],\n 'structured-data': [],\n citation: [],\n content: [],\n aeo: [],\n };\n const passed: Record<Category, RuleResultEntry[]> = {\n crawler: [],\n 'structured-data': [],\n citation: [],\n content: [],\n aeo: [],\n };\n for (const cat of Object.keys(report.categories) as Category[]) {\n for (const r of report.categories[cat].results) {\n if (r.status === 'pass') {\n passed[cat].push(r);\n } else if (r.group === 'opportunity') {\n opportunities.push(r);\n } else {\n diagnostics[cat].push(r);\n }\n }\n }\n\n opportunities.sort((a, b) => {\n const ai = a.estimatedImpact ?? (1 - a.score) * a.weight;\n const bi = b.estimatedImpact ?? (1 - b.score) * b.weight;\n if (bi !== ai) return bi - ai;\n const aw = IMPACT_ORDER[a.impact ?? 'low'];\n const bw = IMPACT_ORDER[b.impact ?? 'low'];\n return bw - aw;\n });\n\n return { opportunities, diagnostics, passed };\n}\n\nfunction renderOpportunities(list: RuleResultEntry[]): string {\n if (list.length === 0) return '';\n return `<section class=\"section\">\n <h2>Opportunities <span class=\"count\">${list.length}</span></h2>\n <p class=\"section-hint\">Highest-leverage fixes first — sorted by estimated points recovered.</p>\n <div class=\"audits\">${list.map(auditRow).join('')}</div>\n </section>`;\n}\n\nfunction renderDiagnostics(groups: Record<Category, RuleResultEntry[]>): string {\n const total = Object.values(groups).reduce((n, arr) => n + arr.length, 0);\n if (total === 0) return '';\n const blocks = (Object.keys(groups) as Category[])\n .filter((c) => groups[c].length > 0)\n .map(\n (c) => `<div class=\"cat-block\">\n <h3>${esc(CATEGORY_LABELS[c])} <span class=\"count\">${groups[c].length}</span></h3>\n <div class=\"audits\">${groups[c].map(auditRow).join('')}</div>\n </div>`,\n )\n .join('');\n return `<section class=\"section\">\n <h2>Diagnostics <span class=\"count\">${total}</span></h2>\n <p class=\"section-hint\">More information about what's wrong, grouped by category.</p>\n ${blocks}\n </section>`;\n}\n\nfunction renderPassed(groups: Record<Category, RuleResultEntry[]>): string {\n const total = Object.values(groups).reduce((n, arr) => n + arr.length, 0);\n if (total === 0) return '';\n const blocks = (Object.keys(groups) as Category[])\n .filter((c) => groups[c].length > 0)\n .map(\n (c) => `<div class=\"cat-block\">\n <h3>${esc(CATEGORY_LABELS[c])} <span class=\"count\">${groups[c].length}</span></h3>\n <div class=\"audits\">${groups[c].map(auditRow).join('')}</div>\n </div>`,\n )\n .join('');\n return `<section class=\"section\">\n <details>\n <summary><h2 class=\"inline\">Passed audits <span class=\"count\">${total}</span></h2></summary>\n ${blocks}\n </details>\n </section>`;\n}\n\nfunction renderWarnings(warnings: string[]): string {\n if (warnings.length === 0) return '';\n const items = warnings.map((w) => `<li>${esc(w)}</li>`).join('');\n return `<section class=\"warnings\"><ul>${items}</ul></section>`;\n}\n\nfunction renderRings(report: AuditReport): string {\n const catRings = (Object.keys(report.categories) as Category[])\n .filter((c) => report.categories[c].results.length > 0)\n .map((c) => ring(report.categories[c].score, CATEGORY_LABELS[c], 96))\n .join('');\n return `<section class=\"rings\">\n <div class=\"rings-overall\">${ring(report.overall, 'Overall', 160)}</div>\n <div class=\"rings-cats\">${catRings}</div>\n </section>`;\n}\n\nfunction renderJsonBlock(report: AuditReport): string {\n const json = JSON.stringify(report, null, 2).replace(/<\\/script/g, '<\\\\/script');\n return `<section class=\"section\">\n <details>\n <summary><h2 class=\"inline\">Report JSON</h2></summary>\n <p class=\"section-hint\">The raw report, as emitted by <code>--json</code>.</p>\n <pre class=\"json-blob\" id=\"geo-json\">${esc(JSON.stringify(report, null, 2))}</pre>\n </details>\n <script type=\"application/json\" id=\"geo-report-data\">${json}</script>\n </section>`;\n}\n\nconst STYLES = `\n:root {\n color-scheme: light dark;\n --bg: #0b0d10;\n --panel: #141820;\n --panel-2: #1b2029;\n --border: #252b36;\n --fg: #e7ecf3;\n --fg-dim: #9aa6b2;\n --good: #17c27b;\n --avg: #f5b042;\n --poor: #ef476f;\n --accent: #5e9df8;\n --snippet: #0f1218;\n}\n@media (prefers-color-scheme: light) {\n :root {\n --bg: #fafbfc;\n --panel: #ffffff;\n --panel-2: #f3f5f9;\n --border: #e3e7ee;\n --fg: #1a222c;\n --fg-dim: #5a6572;\n --snippet: #f4f6fa;\n }\n}\n* { box-sizing: border-box; }\nhtml, body { margin: 0; padding: 0; }\nbody {\n font: 14px/1.55 ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif;\n background: var(--bg);\n color: var(--fg);\n}\n.wrap { max-width: 1100px; margin: 0 auto; padding: 32px 24px 64px; }\nheader.hdr {\n display: flex; justify-content: space-between; align-items: flex-start; gap: 16px;\n padding-bottom: 24px; border-bottom: 1px solid var(--border);\n}\n.hdr-main h1 { font-size: 20px; margin: 0 0 6px; letter-spacing: -0.01em; }\n.hdr-main h1 .brand { color: var(--fg-dim); font-weight: 500; }\n.url { word-break: break-all; color: var(--fg); }\n.hdr-meta { color: var(--fg-dim); font-size: 12px; margin-top: 8px; display: flex; gap: 14px; flex-wrap: wrap; }\n.hdr-meta code { background: var(--panel-2); padding: 1px 6px; border-radius: 4px; }\n.hdr-actions { display: flex; gap: 8px; }\n.btn {\n background: var(--panel); color: var(--fg); border: 1px solid var(--border);\n padding: 6px 12px; border-radius: 6px; font: inherit; cursor: pointer;\n}\n.btn:hover { border-color: var(--accent); color: var(--accent); }\n\n.rings {\n display: grid; grid-template-columns: auto 1fr; gap: 32px; align-items: center;\n margin: 28px 0 32px; padding: 24px; border-radius: 12px; background: var(--panel);\n border: 1px solid var(--border);\n}\n.rings-cats { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 16px; }\n.ring { display: grid; justify-items: center; gap: 4px; position: relative; }\n.ring svg { transform: rotate(-90deg); }\n.ring-track { fill: none; stroke: var(--panel-2); stroke-width: 8; }\n.ring-value { fill: none; stroke-width: 8; stroke-linecap: round; transition: stroke-dashoffset .5s ease; }\n.ring-good .ring-value { stroke: var(--good); }\n.ring-avg .ring-value { stroke: var(--avg); }\n.ring-poor .ring-value { stroke: var(--poor); }\n.ring-num {\n position: absolute; top: 50%; left: 50%; transform: translate(-50%, -65%);\n font-weight: 700; font-size: 28px; letter-spacing: -0.02em;\n}\n.rings-overall .ring-num { font-size: 44px; }\n.ring-label { color: var(--fg-dim); font-size: 12px; }\n\n.warnings {\n background: color-mix(in srgb, var(--avg) 12%, transparent);\n border: 1px solid color-mix(in srgb, var(--avg) 40%, var(--border));\n border-radius: 8px; padding: 12px 16px; margin-bottom: 24px;\n}\n.warnings ul { margin: 0; padding-left: 20px; }\n\n.section { margin: 28px 0; }\n.section h2 { font-size: 18px; margin: 0 0 6px; letter-spacing: -0.01em; }\n.section .section-hint { color: var(--fg-dim); font-size: 13px; margin: 0 0 14px; }\n.section h2.inline { display: inline-block; margin: 0; cursor: pointer; }\ndetails > summary { list-style: none; cursor: pointer; }\ndetails > summary::-webkit-details-marker { display: none; }\ndetails > summary::before { content: \"▸ \"; color: var(--fg-dim); }\ndetails[open] > summary::before { content: \"▾ \"; }\n\n.count {\n display: inline-block; background: var(--panel-2); color: var(--fg-dim);\n font-size: 11px; padding: 1px 8px; border-radius: 999px; margin-left: 6px; vertical-align: middle;\n}\n\n.cat-block { margin: 14px 0; }\n.cat-block h3 { font-size: 14px; color: var(--fg-dim); font-weight: 600; margin: 18px 0 8px; }\n\n.audits { display: grid; gap: 10px; }\n.audit {\n background: var(--panel); border: 1px solid var(--border); border-radius: 10px;\n padding: 12px 14px;\n}\n.audit-fail { border-left: 3px solid var(--poor); }\n.audit-warn { border-left: 3px solid var(--avg); }\n.audit-skip { opacity: 0.7; }\n.audit-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }\n.audit-title { font-weight: 600; flex: 1 1 auto; min-width: 0; }\n.audit-score { color: var(--fg-dim); font-variant-numeric: tabular-nums; font-size: 12px; }\n.audit-id { color: var(--fg-dim); font-size: 11px; margin-top: 4px; }\n.audit-id code { background: transparent; color: var(--fg-dim); }\n.audit-rationale { margin-top: 8px; color: var(--fg); }\n.fix-hint { margin-top: 6px; color: var(--accent); font-size: 13px; }\n.docs { color: var(--accent); text-decoration: none; font-size: 12px; margin-left: auto; }\n.docs:hover { text-decoration: underline; }\n\n.chip {\n display: inline-block; font-size: 11px; padding: 1px 8px; border-radius: 999px;\n border: 1px solid var(--border); background: var(--panel-2); color: var(--fg-dim);\n text-transform: lowercase; letter-spacing: 0.02em;\n}\n.chip-pass { color: var(--good); border-color: color-mix(in srgb, var(--good) 40%, var(--border)); }\n.chip-warn { color: var(--avg); border-color: color-mix(in srgb, var(--avg) 40%, var(--border)); }\n.chip-fail { color: var(--poor); border-color: color-mix(in srgb, var(--poor) 40%, var(--border)); }\n.chip-impact-critical, .chip-impact-high { color: var(--poor); border-color: color-mix(in srgb, var(--poor) 40%, var(--border)); }\n.chip-impact-medium { color: var(--avg); border-color: color-mix(in srgb, var(--avg) 40%, var(--border)); }\n.chip-est { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 40%, var(--border)); }\n\n.locations { list-style: none; padding: 0; margin: 10px 0 0; display: grid; gap: 6px; }\n.loc { border: 1px solid var(--border); border-radius: 6px; padding: 6px 8px; background: var(--panel-2); }\n.loc-head { color: var(--fg-dim); font-size: 12px; }\n.loc-head .sel { background: transparent; color: var(--accent); padding: 0; }\n.snippet, .json-blob {\n font-family: ui-monospace, \"SF Mono\", Menlo, Consolas, monospace; font-size: 12px;\n background: var(--snippet); padding: 10px 12px; border-radius: 6px;\n white-space: pre-wrap; word-break: break-word; margin: 6px 0 0; max-height: 320px; overflow: auto;\n}\n.json-blob { max-height: 480px; }\n\nfooter.ftr {\n margin-top: 48px; padding-top: 16px; border-top: 1px solid var(--border);\n color: var(--fg-dim); font-size: 12px; display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap;\n}\n`;\n\nconst SCRIPT = `\n(function () {\n var btn = document.getElementById('copy-json');\n var data = document.getElementById('geo-report-data');\n if (!btn || !data) return;\n btn.addEventListener('click', function () {\n var payload = data.textContent || '';\n if (navigator.clipboard && navigator.clipboard.writeText) {\n navigator.clipboard.writeText(payload).then(function () {\n btn.textContent = 'Copied ✓';\n setTimeout(function () { btn.textContent = 'Copy JSON'; }, 1200);\n }).catch(function () { fallback(); });\n } else { fallback(); }\n function fallback() {\n var ta = document.createElement('textarea');\n ta.value = payload; document.body.appendChild(ta);\n ta.select(); try { document.execCommand('copy'); } catch (e) {}\n document.body.removeChild(ta);\n btn.textContent = 'Copied ✓';\n setTimeout(function () { btn.textContent = 'Copy JSON'; }, 1200);\n }\n });\n})();\n`;\n\nexport function toHtml(report: AuditReport): string {\n const { opportunities, diagnostics, passed } = partitionResults(report);\n const title = `geo-checker · ${esc(report.finalUrl)}`;\n const timingLine = `fetch ${report.timing.fetchMs}ms · audit ${report.timing.auditMs}ms · total ${report.timing.totalMs}ms`;\n\n const body = `<div class=\"wrap\">\n <header class=\"hdr\">\n <div class=\"hdr-main\">\n <h1><span class=\"brand\">geo-checker</span> · <span class=\"url\">${esc(report.finalUrl)}</span></h1>\n <div class=\"hdr-meta\">\n <span>mode: <code>${esc(report.renderMode)}</code></span>\n <span>fetched: <code>${esc(report.fetchedAt)}</code></span>\n <span>tool: <code>v${esc(report.meta.toolVersion)}</code></span>\n <span>node: <code>${esc(report.meta.nodeVersion)}</code></span>\n <span>${timingLine}</span>\n </div>\n </div>\n <div class=\"hdr-actions\">\n <button class=\"btn\" id=\"copy-json\" type=\"button\">Copy JSON</button>\n </div>\n </header>\n\n ${renderRings(report)}\n ${renderWarnings(report.warnings)}\n ${renderOpportunities(opportunities)}\n ${renderDiagnostics(diagnostics)}\n ${renderPassed(passed)}\n ${renderJsonBlock(report)}\n\n <footer class=\"ftr\">\n <span>Generated by geo-checker v${esc(report.meta.toolVersion)}</span>\n <span>Schema v${report.schemaVersion}</span>\n </footer>\n </div>`;\n\n return `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n<meta name=\"generator\" content=\"geo-checker v${esc(report.meta.toolVersion)}\" />\n<title>${title}</title>\n<style>${STYLES}</style>\n</head>\n<body>\n${body}\n<script>${SCRIPT}</script>\n</body>\n</html>\n`;\n}\n"],"mappings":"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","names":["import_promises","import_node_path","import_kleur","cheerioLoad","defaultRules","before","after","CATEGORY_LABELS","kleur","Table","CATEGORY_LABELS","impactChip","resolvePath","kleur"]}
|