@rankture/cli 0.1.0 → 0.1.1
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.mjs +18 -15
- package/dist/index.mjs +0 -1
- package/package.json +5 -4
- package/dist/cli.mjs.map +0 -1
- package/dist/index.mjs.map +0 -1
package/dist/cli.mjs
CHANGED
|
@@ -1738,6 +1738,9 @@ function runChecks(page, allPages, basePath, enabledChecks) {
|
|
|
1738
1738
|
return results;
|
|
1739
1739
|
}
|
|
1740
1740
|
|
|
1741
|
+
// src/version.ts
|
|
1742
|
+
var VERSION = "0.1.1";
|
|
1743
|
+
|
|
1741
1744
|
// src/reporters/terminal.ts
|
|
1742
1745
|
import chalk from "chalk";
|
|
1743
1746
|
function formatTerminal(report) {
|
|
@@ -2352,7 +2355,7 @@ async function checkCommand(options) {
|
|
|
2352
2355
|
}
|
|
2353
2356
|
spinner.stop();
|
|
2354
2357
|
const report = {
|
|
2355
|
-
version:
|
|
2358
|
+
version: VERSION,
|
|
2356
2359
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2357
2360
|
path: options.path,
|
|
2358
2361
|
summary: {
|
|
@@ -2756,7 +2759,7 @@ function printValidationResult(type, filePath, result) {
|
|
|
2756
2759
|
|
|
2757
2760
|
// src/cli.ts
|
|
2758
2761
|
var program = new Command();
|
|
2759
|
-
program.name("rankture").description("SEO audit tool for developers - check your sites before deploy").version(
|
|
2762
|
+
program.name("rankture").description("SEO audit tool for developers - check your sites before deploy").version(VERSION);
|
|
2760
2763
|
program.command("check <path>").description("Run SEO checks on local HTML files").option("-f, --format <format>", "Output format: terminal, json, html", "terminal").option("-o, --output <file>", "Write output to file").option("--fail-on <level>", "Exit with code 1 on: none, critical, warning, any", "none").option("--ignore <patterns...>", "Glob patterns to ignore", []).option("--config <file>", "Config file path").option("-w, --watch", "Watch for file changes and re-run checks").option("--changed", "Only check files changed in git (staged + unstaged)").option("--staged", "Only check git staged files").action(async (pathArg, opts) => {
|
|
2761
2764
|
const options = {
|
|
2762
2765
|
path: pathArg,
|
|
@@ -2777,16 +2780,16 @@ program.command("check <path>").description("Run SEO checks on local HTML files"
|
|
|
2777
2780
|
}
|
|
2778
2781
|
});
|
|
2779
2782
|
program.command("audit <url>").description("Audit a live URL (requires API key for full features)").option("--api-key <key>", "Rankture API key for Pro features").option("--sync", "Sync results to Rankture dashboard").option("--mobile", "Run mobile audit", true).option("--desktop", "Run desktop audit", false).option("--pages <number>", "Max pages to audit (Pro only)", "1").option("-f, --format <format>", "Output format: terminal, json, html", "terminal").option("--fail-on <level>", "Exit with code 1 on: none, critical, warning, any", "none").action(async (_url, _opts) => {
|
|
2780
|
-
console.
|
|
2781
|
-
console.
|
|
2782
|
-
console.
|
|
2783
|
-
console.
|
|
2784
|
-
console.
|
|
2785
|
-
console.
|
|
2786
|
-
console.
|
|
2787
|
-
console.
|
|
2788
|
-
console.
|
|
2789
|
-
process.exit(
|
|
2783
|
+
console.error("");
|
|
2784
|
+
console.error(" The audit command is not implemented yet.");
|
|
2785
|
+
console.error("");
|
|
2786
|
+
console.error(" For now, use the check command on your built files:");
|
|
2787
|
+
console.error(" rankture check ./dist");
|
|
2788
|
+
console.error("");
|
|
2789
|
+
console.error(" Or run a free audit at:");
|
|
2790
|
+
console.error(" https://rankture.com/free-seo-audit/");
|
|
2791
|
+
console.error("");
|
|
2792
|
+
process.exit(2);
|
|
2790
2793
|
});
|
|
2791
2794
|
program.command("init").description("Create a rankture.config.json file").option("--force", "Overwrite existing config file").action(async (opts) => {
|
|
2792
2795
|
const fs4 = await import("fs");
|
|
@@ -2863,8 +2866,9 @@ program.command("validate <type> <file>").description("Validate sitemap.xml, rob
|
|
|
2863
2866
|
printValidationResult("sitemap.xml", file, result);
|
|
2864
2867
|
process.exit(result.valid ? 0 : 1);
|
|
2865
2868
|
} else if (normalizedType === "schema") {
|
|
2866
|
-
console.
|
|
2867
|
-
|
|
2869
|
+
console.error("\n Schema validation is not implemented yet.");
|
|
2870
|
+
console.error(" JSON-LD syntax and structure checks run as part of: rankture check <path>\n");
|
|
2871
|
+
process.exit(2);
|
|
2868
2872
|
}
|
|
2869
2873
|
} catch (error) {
|
|
2870
2874
|
console.error(`
|
|
@@ -2874,4 +2878,3 @@ program.command("validate <type> <file>").description("Validate sitemap.xml, rob
|
|
|
2874
2878
|
}
|
|
2875
2879
|
});
|
|
2876
2880
|
program.parse();
|
|
2877
|
-
//# sourceMappingURL=cli.mjs.map
|
package/dist/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rankture/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "SEO audit tool for developers - check your sites before deploy",
|
|
5
5
|
"author": "Rankture",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"bin": {
|
|
9
|
-
"rankture": "
|
|
9
|
+
"rankture": "dist/cli.mjs"
|
|
10
10
|
},
|
|
11
11
|
"main": "./dist/index.mjs",
|
|
12
12
|
"types": "./dist/index.d.ts",
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
".": {
|
|
15
15
|
"types": "./dist/index.d.ts",
|
|
16
16
|
"import": "./dist/index.mjs"
|
|
17
|
-
}
|
|
17
|
+
},
|
|
18
|
+
"./cli": "./dist/cli.mjs"
|
|
18
19
|
},
|
|
19
20
|
"files": [
|
|
20
21
|
"dist",
|
|
@@ -62,7 +63,7 @@
|
|
|
62
63
|
},
|
|
63
64
|
"repository": {
|
|
64
65
|
"type": "git",
|
|
65
|
-
"url": "https://github.com/ChrisDrinks/seo-audit-tool.git",
|
|
66
|
+
"url": "git+https://github.com/ChrisDrinks/seo-audit-tool.git",
|
|
66
67
|
"directory": "packages/cli"
|
|
67
68
|
},
|
|
68
69
|
"homepage": "https://rankture.com",
|
package/dist/cli.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/commands/check.ts","../src/parsers/html.ts","../src/checks/meta-tags.ts","../src/checks/headings.ts","../src/checks/images.ts","../src/checks/links.ts","../src/checks/schema.ts","../src/checks/social.ts","../src/checks/accessibility.ts","../src/checks/index.ts","../src/reporters/terminal.ts","../src/reporters/json.ts","../src/reporters/html.ts","../src/commands/validate.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { checkCommand, watchCommand } from './commands/check.js';\nimport { validateRobotsTxt, validateSitemap, printValidationResult } from './commands/validate.js';\nimport type { CheckOptions } from './types/index.js';\n\nconst program = new Command();\n\nprogram\n .name('rankture')\n .description('SEO audit tool for developers - check your sites before deploy')\n .version('0.1.0');\n\n// Check command - run local offline checks\nprogram\n .command('check <path>')\n .description('Run SEO checks on local HTML files')\n .option('-f, --format <format>', 'Output format: terminal, json, html', 'terminal')\n .option('-o, --output <file>', 'Write output to file')\n .option('--fail-on <level>', 'Exit with code 1 on: none, critical, warning, any', 'none')\n .option('--ignore <patterns...>', 'Glob patterns to ignore', [])\n .option('--config <file>', 'Config file path')\n .option('-w, --watch', 'Watch for file changes and re-run checks')\n .option('--changed', 'Only check files changed in git (staged + unstaged)')\n .option('--staged', 'Only check git staged files')\n .action(async (pathArg: string, opts) => {\n const options: CheckOptions = {\n path: pathArg,\n format: opts.format as 'terminal' | 'json' | 'html',\n output: opts.output,\n failOn: opts.failOn as 'none' | 'critical' | 'warning' | 'any',\n ignore: opts.ignore,\n config: opts.config,\n watch: opts.watch,\n changed: opts.changed,\n staged: opts.staged,\n };\n\n if (opts.watch) {\n await watchCommand(options);\n } else {\n const exitCode = await checkCommand(options);\n process.exit(exitCode);\n }\n });\n\n// Audit command - check a live URL (placeholder for now)\nprogram\n .command('audit <url>')\n .description('Audit a live URL (requires API key for full features)')\n .option('--api-key <key>', 'Rankture API key for Pro features')\n .option('--sync', 'Sync results to Rankture dashboard')\n .option('--mobile', 'Run mobile audit', true)\n .option('--desktop', 'Run desktop audit', false)\n .option('--pages <number>', 'Max pages to audit (Pro only)', '1')\n .option('-f, --format <format>', 'Output format: terminal, json, html', 'terminal')\n .option('--fail-on <level>', 'Exit with code 1 on: none, critical, warning, any', 'none')\n .action(async (_url: string, _opts) => {\n console.log('');\n console.log(' The audit command is coming soon!');\n console.log('');\n console.log(' For now, use the check command on your built files:');\n console.log(' rankture check ./dist');\n console.log('');\n console.log(' Or run a free audit at:');\n console.log(' https://rankture.com/free-seo-audit/');\n console.log('');\n process.exit(0);\n });\n\n// Init command - create config file\nprogram\n .command('init')\n .description('Create a rankture.config.json file')\n .option('--force', 'Overwrite existing config file')\n .action(async (opts) => {\n const fs = await import('fs');\n const configPath = './rankture.config.json';\n \n if (fs.existsSync(configPath) && !opts.force) {\n console.log('');\n console.log(' ⚠️ rankture.config.json already exists');\n console.log(' Use --force to overwrite');\n console.log('');\n process.exit(1);\n }\n\n const config = {\n checks: {\n 'meta-title': true,\n 'meta-description': true,\n 'viewport': true,\n 'lang': true,\n 'canonical': true,\n 'h1': true,\n 'heading-hierarchy': true,\n 'image-alt': true,\n 'internal-links': true,\n 'schema': true,\n // AI/Voice optimization checks\n 'schema-speakable': true,\n 'schema-offers': true,\n 'schema-faq': true,\n 'schema-howto': true,\n 'open-graph': true,\n 'twitter-cards': true,\n 'robots-meta': true,\n 'accessibility': true,\n 'color-contrast': true,\n 'focus-indicators': true,\n },\n ignore: [\n '**/node_modules/**',\n '**/.git/**',\n '**/404.html',\n '**/500.html',\n ],\n thresholds: {\n titleLength: { min: 30, max: 60 },\n descriptionLength: { min: 120, max: 160 },\n },\n };\n\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2));\n console.log('');\n console.log(' ✅ Created rankture.config.json');\n console.log('');\n console.log(' Next steps:');\n console.log(' 1. Edit the config to customize checks');\n console.log(' 2. Run: rankture check ./dist');\n console.log('');\n process.exit(0);\n });\n\n// Validate command - validate SEO assets\nprogram\n .command('validate <type> <file>')\n .description('Validate sitemap.xml, robots.txt, or schema.json')\n .action(async (type: string, file: string) => {\n const validTypes = ['robots', 'robots.txt', 'sitemap', 'sitemap.xml', 'schema'];\n \n if (!validTypes.includes(type.toLowerCase())) {\n console.error(`\\n Invalid type: \"${type}\"`);\n console.error(` Valid types: robots, sitemap, schema\\n`);\n process.exit(1);\n }\n\n const normalizedType = type.toLowerCase().replace('.txt', '').replace('.xml', '').replace('.json', '');\n\n try {\n if (normalizedType === 'robots') {\n const result = await validateRobotsTxt(file);\n printValidationResult('robots.txt', file, result);\n process.exit(result.valid ? 0 : 1);\n } else if (normalizedType === 'sitemap') {\n const result = await validateSitemap(file);\n printValidationResult('sitemap.xml', file, result);\n process.exit(result.valid ? 0 : 1);\n } else if (normalizedType === 'schema') {\n console.log('\\n Schema validation coming soon!\\n');\n process.exit(0);\n }\n } catch (error) {\n console.error(`\\n Error validating ${type}: ${error}\\n`);\n process.exit(1);\n }\n });\n\n// Parse arguments and run\nprogram.parse();\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport fg from 'fast-glob';\nimport ora from 'ora';\nimport type { CheckOptions, CheckReport, CheckResult, ParsedPage } from '../types/index.js';\nimport { parseHtml, parseSourceFile, SUPPORTED_EXTENSIONS } from '../parsers/html.js';\nimport { runChecks } from '../checks/index.js';\nimport { printReport } from '../reporters/terminal.js';\nimport { formatJson } from '../reporters/json.js';\nimport { formatHtml } from '../reporters/html.js';\nimport { execSync } from 'child_process';\n\n/**\n * Get git changed files (staged and/or unstaged)\n */\nfunction getGitChangedFiles(basePath: string, stagedOnly: boolean): string[] {\n try {\n const cwd = path.resolve(basePath);\n \n // Get staged files\n const stagedOutput = execSync('git diff --cached --name-only --diff-filter=ACMR', {\n cwd,\n encoding: 'utf-8',\n }).trim();\n \n const stagedFiles = stagedOutput ? stagedOutput.split('\\n') : [];\n \n if (stagedOnly) {\n return stagedFiles.map(f => path.join(cwd, f));\n }\n \n // Get unstaged files (modified/added)\n const unstagedOutput = execSync('git diff --name-only --diff-filter=ACMR', {\n cwd,\n encoding: 'utf-8',\n }).trim();\n \n const unstagedFiles = unstagedOutput ? unstagedOutput.split('\\n') : [];\n \n // Combine and dedupe\n const allFiles = [...new Set([...stagedFiles, ...unstagedFiles])];\n return allFiles.map(f => path.join(cwd, f));\n } catch {\n // Not a git repo or git not available\n return [];\n }\n}\n\n/**\n * Run SEO checks on local files\n */\nexport async function checkCommand(options: CheckOptions): Promise<number> {\n const spinner = ora('Scanning files...').start();\n\n try {\n // Resolve the path\n const basePath = path.resolve(options.path);\n\n // Check if path exists\n if (!fs.existsSync(basePath)) {\n spinner.fail(`Path not found: ${basePath}`);\n return 1;\n }\n\n // Check if it's a single file or directory\n const stats = fs.statSync(basePath);\n let targetFiles: string[];\n\n // All supported extensions\n const allExtensions = [...SUPPORTED_EXTENSIONS.html, ...SUPPORTED_EXTENSIONS.source];\n\n // Git diff mode\n if (options.changed || options.staged) {\n spinner.text = options.staged ? 'Getting staged files...' : 'Getting changed files...';\n \n const gitFiles = getGitChangedFiles(basePath, !!options.staged);\n \n // Filter to only supported extensions\n targetFiles = gitFiles.filter(f => {\n const ext = path.extname(f).toLowerCase();\n return allExtensions.includes(ext);\n });\n\n if (targetFiles.length === 0) {\n spinner.succeed(options.staged \n ? 'No staged files to check' \n : 'No changed files to check');\n return 0;\n }\n\n spinner.text = `Found ${targetFiles.length} ${options.staged ? 'staged' : 'changed'} file(s)`;\n } else if (stats.isFile()) {\n // Single file - check if it's a supported type\n const ext = path.extname(basePath).toLowerCase();\n if (!allExtensions.includes(ext)) {\n spinner.fail(`Unsupported file type: ${ext}. Supported: ${allExtensions.join(', ')}`);\n return 1;\n }\n targetFiles = [basePath];\n } else {\n // Directory - scan for supported files\n // Build ignore patterns\n const ignorePatterns = [\n '**/node_modules/**',\n '**/.git/**',\n '**/.astro/**',\n '**/.next/**',\n '**/.nuxt/**',\n '**/.svelte-kit/**',\n '**/dist/**/*.js',\n '**/dist/**/*.css',\n ...options.ignore,\n ];\n\n // Build glob pattern for all supported extensions\n const extensionPattern = allExtensions.map(e => e.slice(1)).join(',');\n const globPattern = `**/*.{${extensionPattern}}`;\n\n // Find all supported files\n targetFiles = await fg(globPattern, {\n cwd: basePath,\n ignore: ignorePatterns,\n absolute: true,\n });\n\n if (targetFiles.length === 0) {\n spinner.fail(`No supported files found in ${basePath}. Looking for: ${allExtensions.join(', ')}`);\n return 1;\n }\n }\n\n spinner.text = `Parsing ${targetFiles.length} file${targetFiles.length > 1 ? 's' : ''}...`;\n\n // Parse all files based on their type\n const pages: ParsedPage[] = [];\n for (const filePath of targetFiles) {\n const content = fs.readFileSync(filePath, 'utf-8');\n const ext = path.extname(filePath).toLowerCase();\n \n let page: ParsedPage;\n if (SUPPORTED_EXTENSIONS.html.includes(ext)) {\n // HTML files - direct parsing\n page = parseHtml(filePath, content);\n } else {\n // Source files (JSX, TSX, Astro, MDX, etc.) - extract HTML-like content\n page = parseSourceFile(filePath, content);\n }\n pages.push(page);\n }\n\n spinner.text = 'Running checks...';\n\n // Determine base path for broken link checks\n const effectiveBasePath = stats.isFile() ? path.dirname(basePath) : basePath;\n\n // Run checks on all pages\n const allResults: CheckResult[] = [];\n for (const page of pages) {\n const results = runChecks(page, pages, effectiveBasePath);\n allResults.push(...results);\n }\n\n spinner.stop();\n\n // Build report\n const report: CheckReport = {\n version: '0.1.0',\n timestamp: new Date().toISOString(),\n path: options.path,\n summary: {\n totalFiles: pages.length,\n passed: allResults.filter((r) => r.passed).length,\n critical: allResults.filter((r) => !r.passed && r.severity === 'critical').length,\n warning: allResults.filter((r) => !r.passed && r.severity === 'warning').length,\n info: allResults.filter((r) => !r.passed && r.severity === 'info').length,\n },\n results: allResults.filter((r) => !r.passed), // Only include failures\n };\n\n // Output report\n if (options.format === 'json') {\n const json = formatJson(report);\n if (options.output) {\n fs.writeFileSync(options.output, json);\n console.log(`Report written to ${options.output}`);\n } else {\n console.log(json);\n }\n } else if (options.format === 'html') {\n const html = formatHtml(report);\n if (options.output) {\n fs.writeFileSync(options.output, html);\n console.log(`\\n ✅ HTML report written to ${options.output}`);\n console.log(` Open in browser: file://${path.resolve(options.output)}\\n`);\n } else {\n // Default output file\n const outputFile = `seo-report-${new Date().toISOString().split('T')[0]}.html`;\n fs.writeFileSync(outputFile, html);\n console.log(`\\n ✅ HTML report written to ${outputFile}`);\n console.log(` Open in browser: file://${path.resolve(outputFile)}\\n`);\n }\n } else {\n // Terminal output (default)\n printReport(report);\n }\n\n // Determine exit code based on fail-on setting\n let exitCode = 0;\n \n switch (options.failOn) {\n case 'critical':\n if (report.summary.critical > 0) exitCode = 1;\n break;\n case 'warning':\n if (report.summary.critical > 0 || report.summary.warning > 0) exitCode = 1;\n break;\n case 'any':\n if (report.summary.critical > 0 || report.summary.warning > 0 || report.summary.info > 0) {\n exitCode = 1;\n }\n break;\n case 'none':\n default:\n exitCode = 0;\n }\n\n return exitCode;\n } catch (error) {\n spinner.fail('Error running checks');\n console.error(error);\n return 1;\n }\n}\n\n/**\n * Watch mode - re-run checks when files change\n */\nexport async function watchCommand(options: CheckOptions): Promise<void> {\n const basePath = path.resolve(options.path);\n \n // Check if path exists\n if (!fs.existsSync(basePath)) {\n console.error(`Path not found: ${basePath}`);\n process.exit(1);\n }\n\n console.log('');\n console.log(' 👀 Watch mode enabled');\n console.log(` Watching: ${basePath}`);\n console.log(' Press Ctrl+C to stop');\n console.log('');\n\n // Run initial check\n await checkCommand(options);\n\n // All supported extensions\n const allExtensions = [...SUPPORTED_EXTENSIONS.html, ...SUPPORTED_EXTENSIONS.source];\n \n // Build glob pattern\n const extensionPattern = allExtensions.map(e => e.slice(1)).join(',');\n const watchPattern = path.join(basePath, `**/*.{${extensionPattern}}`);\n\n // Use chokidar for file watching\n const chokidar = await import('chokidar');\n \n let debounceTimer: NodeJS.Timeout | null = null;\n let isRunning = false;\n\n const runChecks = async () => {\n if (isRunning) return;\n isRunning = true;\n \n console.clear();\n console.log('');\n console.log(' 🔄 File change detected, re-running checks...');\n console.log('');\n \n await checkCommand(options);\n \n console.log('');\n console.log(' 👀 Watching for changes...');\n \n isRunning = false;\n };\n\n const debouncedRun = () => {\n if (debounceTimer) {\n clearTimeout(debounceTimer);\n }\n debounceTimer = setTimeout(runChecks, 300);\n };\n\n const watcher = chokidar.watch(watchPattern, {\n ignored: [\n '**/node_modules/**',\n '**/.git/**',\n '**/.astro/**',\n '**/.next/**',\n '**/.nuxt/**',\n '**/.svelte-kit/**',\n ...options.ignore.map(p => `**/${p}`),\n ],\n persistent: true,\n ignoreInitial: true,\n });\n\n watcher\n .on('change', debouncedRun)\n .on('add', debouncedRun)\n .on('unlink', debouncedRun);\n\n // Keep process alive\n process.on('SIGINT', () => {\n console.log('');\n console.log(' 👋 Watch mode stopped');\n watcher.close();\n process.exit(0);\n });\n}\n","import * as cheerio from 'cheerio';\nimport type { ParsedPage } from '../types/index.js';\nimport type { Element } from 'domhandler';\n\n/**\n * Supported file extensions by category\n */\nexport const SUPPORTED_EXTENSIONS = {\n // Built HTML output\n html: ['.html', '.htm'],\n // Source files that can contain HTML-like content\n source: [\n '.astro', // Astro\n '.jsx', '.tsx', // React/Next.js\n '.vue', // Vue/Nuxt\n '.svelte', // Svelte/SvelteKit\n '.md', '.mdx', // Markdown\n '.njk', // Nunjucks\n '.ejs', // EJS\n '.hbs', // Handlebars\n '.pug', // Pug/Jade\n '.liquid', // Liquid (Shopify, 11ty)\n ],\n};\n\n/**\n * Parse an HTML file and extract SEO-relevant data\n */\nexport function parseHtml(filePath: string, html: string): ParsedPage {\n const $ = cheerio.load(html);\n\n // Extract title\n const title = $('title').first().text().trim() || undefined;\n\n // Extract meta description\n const metaDescription =\n $('meta[name=\"description\"]').attr('content')?.trim() || undefined;\n\n // Extract canonical\n const canonical = $('link[rel=\"canonical\"]').attr('href')?.trim() || undefined;\n\n // Extract viewport\n const viewport = $('meta[name=\"viewport\"]').attr('content')?.trim() || undefined;\n\n // Extract lang\n const lang = $('html').attr('lang')?.trim() || undefined;\n\n // Extract H1s\n const h1s: string[] = [];\n $('h1').each((_, el) => {\n const text = $(el).text().trim();\n if (text) h1s.push(text);\n });\n\n // Extract all headings in order\n const headings: { level: number; text: string }[] = [];\n $('h1, h2, h3, h4, h5, h6').each((_, el) => {\n const tagName = (el as Element).tagName.toLowerCase();\n const level = parseInt(tagName.replace('h', ''), 10);\n const text = $(el).text().trim();\n if (text) headings.push({ level, text });\n });\n\n // Extract images\n const images: { src: string; alt?: string }[] = [];\n $('img').each((_, el) => {\n const src = $(el).attr('src') || '';\n const alt = $(el).attr('alt');\n images.push({ src, alt: alt !== undefined ? alt : undefined });\n });\n\n // Extract links\n const internalLinks: { href: string; text: string }[] = [];\n const externalLinks: { href: string; text: string }[] = [];\n \n $('a[href]').each((_, el) => {\n const href = $(el).attr('href') || '';\n const text = $(el).text().trim();\n \n // Skip javascript:, mailto:, tel:; keep empty and \"#\" hrefs so the\n // link-empty-href check can flag them (the broken-link check skips them)\n if (href.startsWith('javascript:') || href.startsWith('mailto:') || href.startsWith('tel:')) {\n return;\n }\n\n // Determine if internal or external\n if (href.startsWith('http://') || href.startsWith('https://') || href.startsWith('//')) {\n externalLinks.push({ href, text });\n } else {\n internalLinks.push({ href, text });\n }\n });\n\n // Extract JSON-LD\n const jsonLd: object[] = [];\n $('script[type=\"application/ld+json\"]').each((_, el) => {\n try {\n const content = $(el).html();\n if (content) {\n const parsed = JSON.parse(content);\n jsonLd.push(parsed);\n }\n } catch {\n // Invalid JSON-LD, will be caught by schema check\n }\n });\n\n // Extract Open Graph tags\n const ogTags: Record<string, string> = {};\n $('meta[property^=\"og:\"]').each((_, el) => {\n const property = $(el).attr('property');\n const content = $(el).attr('content');\n if (property && content) {\n ogTags[property] = content;\n }\n });\n\n // Extract Twitter Card tags\n const twitterTags: Record<string, string> = {};\n $('meta[name^=\"twitter:\"], meta[property^=\"twitter:\"]').each((_, el) => {\n const name = $(el).attr('name') || $(el).attr('property');\n const content = $(el).attr('content');\n if (name && content) {\n twitterTags[name] = content;\n }\n });\n\n // Extract robots meta\n const robots = $('meta[name=\"robots\"]').attr('content')?.trim() || undefined;\n\n return {\n filePath,\n html,\n title,\n metaDescription,\n canonical,\n viewport,\n lang,\n h1s,\n headings,\n images,\n internalLinks,\n externalLinks,\n jsonLd,\n ogTags,\n twitterTags,\n robots,\n isSourceFile: false, // This is a built HTML file\n };\n}\n\n/**\n * Parse source files (JSX, TSX, Astro, Vue, Svelte, MD, MDX, Nunjucks, EJS, etc.)\n * Extracts HTML-like content for SEO checking\n */\nexport function parseSourceFile(filePath: string, content: string): ParsedPage {\n const ext = filePath.toLowerCase().split('.').pop() || '';\n \n let htmlContent = content;\n \n switch (ext) {\n case 'astro':\n htmlContent = parseAstroFile(content);\n break;\n \n case 'vue':\n htmlContent = parseVueFile(content);\n break;\n \n case 'svelte':\n htmlContent = parseSvelteFile(content);\n break;\n \n case 'md':\n case 'mdx':\n htmlContent = parseMarkdownFile(content);\n break;\n \n case 'jsx':\n case 'tsx':\n htmlContent = extractJsxContent(content);\n break;\n \n case 'njk':\n htmlContent = parseNunjucksFile(content);\n break;\n \n case 'ejs':\n htmlContent = parseEjsFile(content);\n break;\n \n case 'hbs':\n htmlContent = parseHandlebarsFile(content);\n break;\n \n case 'pug':\n htmlContent = parsePugFile(content);\n break;\n \n case 'liquid':\n htmlContent = parseLiquidFile(content);\n break;\n \n default:\n // Try generic extraction\n htmlContent = content;\n }\n\n // Now parse the extracted HTML-like content\n return parseHtmlLikeContent(filePath, content, htmlContent);\n}\n\n/**\n * Parse Astro files - extract template after frontmatter\n */\nfunction parseAstroFile(content: string): string {\n // Astro files have frontmatter between --- markers\n const frontmatterMatch = content.match(/^---[\\s\\S]*?---\\n?([\\s\\S]*)$/);\n let htmlContent = frontmatterMatch ? frontmatterMatch[1] : content;\n \n // Normalize Image and Link components\n htmlContent = normalizeImageComponents(htmlContent);\n htmlContent = normalizeLinkComponents(htmlContent);\n \n return htmlContent;\n}\n\n/**\n * Parse Vue SFC files - extract template and handle script setup\n */\nfunction parseVueFile(content: string): string {\n let htmlContent = '';\n \n // Extract <template> section\n const templateMatch = content.match(/<template[^>]*>([\\s\\S]*?)<\\/template>/i);\n if (templateMatch) {\n htmlContent = templateMatch[1];\n }\n \n // Handle <script setup> - extract defineProps for meta info\n // Vue 3 Composition API with <script setup>\n const scriptSetupMatch = content.match(/<script\\s+setup[^>]*>([\\s\\S]*?)<\\/script>/i);\n if (scriptSetupMatch) {\n // Look for useSeoMeta or useHead from @unhead/vue or nuxt\n const seoMetaMatch = scriptSetupMatch[1].match(/useSeoMeta\\s*\\(\\s*{([^}]+)}/);\n if (seoMetaMatch) {\n // Extract title and description from useSeoMeta\n const titleMatch = seoMetaMatch[1].match(/title:\\s*['\"`]([^'\"`]+)['\"`]/);\n const descMatch = seoMetaMatch[1].match(/description:\\s*['\"`]([^'\"`]+)['\"`]/);\n if (titleMatch) {\n htmlContent = `<title>${titleMatch[1]}</title>` + htmlContent;\n }\n if (descMatch) {\n htmlContent = `<meta name=\"description\" content=\"${descMatch[1]}\">` + htmlContent;\n }\n }\n \n // Look for useHead\n const useHeadMatch = scriptSetupMatch[1].match(/useHead\\s*\\(\\s*{([^}]+)}/);\n if (useHeadMatch) {\n const titleMatch = useHeadMatch[1].match(/title:\\s*['\"`]([^'\"`]+)['\"`]/);\n if (titleMatch) {\n htmlContent = `<title>${titleMatch[1]}</title>` + htmlContent;\n }\n }\n }\n \n // Handle Nuxt-specific patterns\n // definePageMeta for Nuxt 3\n const pageMetaMatch = content.match(/definePageMeta\\s*\\(\\s*{([^}]+)}/);\n if (pageMetaMatch) {\n const titleMatch = pageMetaMatch[1].match(/title:\\s*['\"`]([^'\"`]+)['\"`]/);\n if (titleMatch) {\n htmlContent = `<title>${titleMatch[1]}</title>` + htmlContent;\n }\n }\n \n // Normalize Image and Link components (NuxtImg, NuxtLink)\n htmlContent = normalizeImageComponents(htmlContent);\n htmlContent = normalizeLinkComponents(htmlContent);\n \n // Handle NuxtImg specifically\n htmlContent = htmlContent.replace(\n /<NuxtImg\\s+([^>]*?)\\s*\\/>/gi,\n (match, attrs) => `<img ${attrs}>`\n );\n htmlContent = htmlContent.replace(\n /<NuxtImg\\s+([^>]*?)>([\\s\\S]*?)<\\/NuxtImg>/gi,\n (match, attrs) => `<img ${attrs}>`\n );\n \n return htmlContent;\n}\n\n/**\n * Parse Svelte files - handle SvelteKit patterns\n */\nfunction parseSvelteFile(content: string): string {\n // Remove script and style sections\n let htmlContent = content\n .replace(/<script[^>]*>[\\s\\S]*?<\\/script>/gi, '')\n .replace(/<style[^>]*>[\\s\\S]*?<\\/style>/gi, '');\n \n // Handle SvelteKit's <svelte:head> for SEO\n const headMatch = content.match(/<svelte:head[^>]*>([\\s\\S]*?)<\\/svelte:head>/i);\n if (headMatch) {\n // Prepend head content so title/meta are parsed\n htmlContent = headMatch[1] + htmlContent;\n }\n \n // Look for SvelteKit load function metadata\n const scriptMatch = content.match(/<script[^>]*>([\\s\\S]*?)<\\/script>/i);\n if (scriptMatch) {\n // Check for export const prerender, ssr, etc.\n // Also check for page data pattern\n scriptMatch[1].match(/export\\s+const\\s+\\w+\\s*=\\s*{([^}]+)}/g);\n // This is a simplified check - SvelteKit uses +page.ts for metadata\n }\n \n // Normalize Image and Link components\n htmlContent = normalizeImageComponents(htmlContent);\n htmlContent = normalizeLinkComponents(htmlContent);\n \n // Remove Svelte-specific syntax that might confuse cheerio\n htmlContent = htmlContent\n .replace(/{#if\\s+[^}]+}/g, '')\n .replace(/{:else\\s*(?:if\\s+[^}]+)?}/g, '')\n .replace(/{\\/if}/g, '')\n .replace(/{#each\\s+[^}]+}/g, '')\n .replace(/{\\/each}/g, '')\n .replace(/{#await\\s+[^}]+}/g, '')\n .replace(/{:then\\s*[^}]*}/g, '')\n .replace(/{:catch\\s*[^}]*}/g, '')\n .replace(/{\\/await}/g, '')\n .replace(/{@html\\s+[^}]+}/g, '')\n .replace(/{@const\\s+[^}]+}/g, '');\n \n return htmlContent;\n}\n\n/**\n * Parse Markdown/MDX files\n */\nfunction parseMarkdownFile(content: string): string {\n // Extract frontmatter\n const frontmatterMatch = content.match(/^---[\\s\\S]*?---\\n?([\\s\\S]*)$/);\n let htmlContent = frontmatterMatch ? frontmatterMatch[1] : content;\n \n // Convert markdown to HTML-like structure\n htmlContent = convertMarkdownHeadings(htmlContent);\n htmlContent = convertMarkdownImages(htmlContent);\n htmlContent = convertMarkdownLinks(htmlContent);\n \n return htmlContent;\n}\n\n/**\n * Parse Nunjucks (.njk) files\n */\nfunction parseNunjucksFile(content: string): string {\n let htmlContent = content;\n \n // Remove Nunjucks block tags but keep content\n htmlContent = htmlContent\n .replace(/{%\\s*block\\s+\\w+\\s*%}/g, '')\n .replace(/{%\\s*endblock\\s*%}/g, '')\n .replace(/{%\\s*extends\\s+['\"][^'\"]+['\"]\\s*%}/g, '')\n .replace(/{%\\s*include\\s+['\"][^'\"]+['\"]\\s*%}/g, '')\n .replace(/{%\\s*import\\s+['\"][^'\"]+['\"].*?%}/g, '')\n .replace(/{%\\s*from\\s+['\"][^'\"]+['\"].*?%}/g, '');\n \n // Keep if/for/set blocks content\n htmlContent = htmlContent\n .replace(/{%\\s*if\\s+.*?%}/g, '')\n .replace(/{%\\s*elif\\s+.*?%}/g, '')\n .replace(/{%\\s*else\\s*%}/g, '')\n .replace(/{%\\s*endif\\s*%}/g, '')\n .replace(/{%\\s*for\\s+.*?%}/g, '')\n .replace(/{%\\s*endfor\\s*%}/g, '')\n .replace(/{%\\s*set\\s+.*?%}/g, '');\n \n // Convert Nunjucks variables to markers\n htmlContent = htmlContent.replace(/{{\\s*([^}]+)\\s*}}/g, '[dynamic: $1]');\n \n return htmlContent;\n}\n\n/**\n * Parse EJS (.ejs) files\n */\nfunction parseEjsFile(content: string): string {\n let htmlContent = content;\n \n // Remove EJS scriptlets but keep HTML\n htmlContent = htmlContent\n .replace(/<%[-_]?\\s*[\\s\\S]*?[-_]?%>/g, '') // Remove <% ... %>\n .replace(/<%[-_]?=\\s*([^%]+)[-_]?%>/g, '[dynamic: $1]'); // Convert <%= ... %> to marker\n \n return htmlContent;\n}\n\n/**\n * Parse Handlebars (.hbs) files\n */\nfunction parseHandlebarsFile(content: string): string {\n let htmlContent = content;\n \n // Remove Handlebars block helpers but keep content\n htmlContent = htmlContent\n .replace(/{{#\\s*\\w+.*?}}/g, '')\n .replace(/{{\\/\\s*\\w+\\s*}}/g, '')\n .replace(/{{>\\s*[^}]+}}/g, ''); // Remove partials\n \n // Convert Handlebars expressions to markers\n htmlContent = htmlContent.replace(/{{\\s*([^}#/]+)\\s*}}/g, '[dynamic: $1]');\n \n return htmlContent;\n}\n\n/**\n * Parse Pug (.pug) files - basic conversion\n */\nfunction parsePugFile(content: string): string {\n let htmlContent = '';\n const lines = content.split('\\n');\n \n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('//') || trimmed.startsWith('-')) {\n continue;\n }\n \n // Match tag patterns: h1 text, h1.class text, h1#id text, h1(attr=\"val\") text\n const tagMatch = trimmed.match(/^(h[1-6]|p|a|img|title|meta)([.#(][^\\s]*)?\\s*(.*)?$/);\n if (tagMatch) {\n const [, tag, attrs, text] = tagMatch;\n \n if (tag === 'img') {\n // Parse img with attributes\n const srcMatch = (attrs || '').match(/src=['\"]([^'\"]+)['\"]/);\n const altMatch = (attrs || '').match(/alt=['\"]([^'\"]*)['\"]/);\n htmlContent += `<img src=\"${srcMatch?.[1] || ''}\" ${altMatch ? `alt=\"${altMatch[1]}\"` : ''}>\\n`;\n } else if (tag === 'a') {\n const hrefMatch = (attrs || '').match(/href=['\"]([^'\"]+)['\"]/);\n htmlContent += `<a href=\"${hrefMatch?.[1] || ''}\">${text || ''}</a>\\n`;\n } else if (tag === 'title') {\n htmlContent += `<title>${text || ''}</title>\\n`;\n } else if (tag === 'meta') {\n // Pass through meta tags\n htmlContent += `<meta ${attrs?.replace(/[()]/g, '') || ''}>\\n`;\n } else {\n htmlContent += `<${tag}>${text || ''}</${tag}>\\n`;\n }\n }\n }\n \n return htmlContent;\n}\n\n/**\n * Parse Liquid (.liquid) files - Shopify/11ty\n */\nfunction parseLiquidFile(content: string): string {\n let htmlContent = content;\n \n // Remove Liquid tags but keep content\n htmlContent = htmlContent\n .replace(/{%\\s*comment\\s*%}[\\s\\S]*?{%\\s*endcomment\\s*%}/g, '')\n .replace(/{%\\s*schema\\s*%}[\\s\\S]*?{%\\s*endschema\\s*%}/g, '')\n .replace(/{%\\s*style\\s*%}[\\s\\S]*?{%\\s*endstyle\\s*%}/g, '')\n .replace(/{%\\s*javascript\\s*%}[\\s\\S]*?{%\\s*endjavascript\\s*%}/g, '')\n .replace(/{%\\s*capture\\s+\\w+\\s*%}/g, '')\n .replace(/{%\\s*endcapture\\s*%}/g, '')\n .replace(/{%\\s*if\\s+.*?%}/g, '')\n .replace(/{%\\s*elsif\\s+.*?%}/g, '')\n .replace(/{%\\s*else\\s*%}/g, '')\n .replace(/{%\\s*endif\\s*%}/g, '')\n .replace(/{%\\s*for\\s+.*?%}/g, '')\n .replace(/{%\\s*endfor\\s*%}/g, '')\n .replace(/{%\\s*unless\\s+.*?%}/g, '')\n .replace(/{%\\s*endunless\\s*%}/g, '')\n .replace(/{%\\s*assign\\s+.*?%}/g, '')\n .replace(/{%\\s*render\\s+.*?%}/g, '')\n .replace(/{%\\s*include\\s+.*?%}/g, '')\n .replace(/{%\\s*section\\s+.*?%}/g, '');\n \n // Convert Liquid output to markers\n htmlContent = htmlContent.replace(/{{\\s*([^}|]+)(?:\\|[^}]*)?\\s*}}/g, '[dynamic: $1]');\n \n return htmlContent;\n}\n\n/**\n * Convert markdown headings to HTML\n */\nfunction convertMarkdownHeadings(content: string): string {\n return content\n .replace(/^######\\s+(.+)$/gm, '<h6>$1</h6>')\n .replace(/^#####\\s+(.+)$/gm, '<h5>$1</h5>')\n .replace(/^####\\s+(.+)$/gm, '<h4>$1</h4>')\n .replace(/^###\\s+(.+)$/gm, '<h3>$1</h3>')\n .replace(/^##\\s+(.+)$/gm, '<h2>$1</h2>')\n .replace(/^#\\s+(.+)$/gm, '<h1>$1</h1>');\n}\n\n/**\n * Convert markdown images to HTML\n */\nfunction convertMarkdownImages(content: string): string {\n // \n return content.replace(/!\\[([^\\]]*)\\]\\(([^)]+)\\)/g, '<img alt=\"$1\" src=\"$2\">');\n}\n\n/**\n * Convert markdown links to HTML\n */\nfunction convertMarkdownLinks(content: string): string {\n // [text](href)\n return content.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, '<a href=\"$2\">$1</a>');\n}\n\n/**\n * Extract JSX content from JSX/TSX files\n * Improved extraction for complex React/Next.js components\n */\nfunction extractJsxContent(content: string): string {\n let jsxContent = '';\n \n // Remove imports section\n const withoutImports = content.replace(/^import\\s+.*?;?\\s*$/gm, '');\n \n // Find all return statements with JSX (handles multi-line and nested)\n // Use a more robust regex that handles nested parens\n const returnBlocks: string[] = [];\n \n // Pattern 1: return ( ... ) - standard\n const standardReturns = withoutImports.match(/return\\s*\\([\\s\\S]*?\\n\\s*\\);/g);\n if (standardReturns) {\n returnBlocks.push(...standardReturns);\n }\n \n // Pattern 2: return <Component>...</Component> - without parens\n const directReturns = withoutImports.match(/return\\s+<[A-Z][a-zA-Z]*[\\s\\S]*?<\\/[A-Z][a-zA-Z]*>/g);\n if (directReturns) {\n returnBlocks.push(...directReturns);\n }\n \n // Pattern 3: Arrow function returns: => ( ... )\n const arrowReturns = withoutImports.match(/=>\\s*\\([\\s\\S]*?\\n\\s*\\)/g);\n if (arrowReturns) {\n returnBlocks.push(...arrowReturns);\n }\n \n // Pattern 4: Arrow function direct return: => <div>...</div>\n const arrowDirectReturns = withoutImports.match(/=>\\s*<[a-zA-Z][^;]+/g);\n if (arrowDirectReturns) {\n returnBlocks.push(...arrowDirectReturns);\n }\n \n if (returnBlocks.length > 0) {\n jsxContent = returnBlocks.join('\\n');\n } else {\n // Fallback: look for JSX-like content (starts with <)\n jsxContent = withoutImports;\n }\n \n // Extract Next.js Head component content\n const headMatch = content.match(/<Head[^>]*>([\\s\\S]*?)<\\/Head>/gi);\n if (headMatch) {\n jsxContent = headMatch.join('\\n') + jsxContent;\n }\n \n // Extract next/head import pattern: import Head from 'next/head' then <Head>\n // Also handle @next/head\n \n // Look for Next.js metadata export (App Router)\n // Handles: export const metadata = { ... } and export const metadata: Metadata = { ... }\n const metadataMatch = content.match(/export\\s+const\\s+metadata(?:\\s*:\\s*\\w+)?\\s*=\\s*\\{([\\s\\S]*?)\\n\\}/);\n if (metadataMatch) {\n const metaContent = metadataMatch[1];\n const titleMatch = metaContent.match(/title:\\s*['\"`]([^'\"`]+)['\"`]/);\n const descMatch = metaContent.match(/description:\\s*['\"`]([^'\"`]+)['\"`]/);\n if (titleMatch) {\n jsxContent = `<title>${titleMatch[1]}</title>` + jsxContent;\n }\n if (descMatch) {\n jsxContent = `<meta name=\"description\" content=\"${descMatch[1]}\">` + jsxContent;\n }\n }\n \n // Look for generateMetadata function (Next.js App Router dynamic)\n const generateMetadataMatch = content.match(/export\\s+(?:async\\s+)?function\\s+generateMetadata[\\s\\S]*?return\\s*\\{([\\s\\S]*?)\\n\\s*\\}/);\n if (generateMetadataMatch) {\n const metaContent = generateMetadataMatch[1];\n const titleMatch = metaContent.match(/title:\\s*['\"`]([^'\"`]+)['\"`]/);\n const descMatch = metaContent.match(/description:\\s*['\"`]([^'\"`]+)['\"`]/);\n if (titleMatch) {\n jsxContent = `<title>${titleMatch[1]}</title>` + jsxContent;\n }\n if (descMatch) {\n jsxContent = `<meta name=\"description\" content=\"${descMatch[1]}\">` + jsxContent;\n }\n }\n\n // Convert JSX className to class for cheerio\n jsxContent = jsxContent.replace(/className=/g, 'class=');\n \n // Handle self-closing JSX tags that might confuse cheerio\n jsxContent = jsxContent.replace(/<(\\w+)([^>]*)\\s*\\/>/g, '<$1$2></$1>');\n \n // Convert Image component to img for parsing\n jsxContent = normalizeImageComponents(jsxContent);\n \n // Convert Link component to a for parsing\n jsxContent = normalizeLinkComponents(jsxContent);\n \n return jsxContent;\n}\n\n/**\n * Normalize Image components from various frameworks to <img>\n * Handles: Next.js <Image>, Astro <Image>, Gatsby <Img>, etc.\n */\nfunction normalizeImageComponents(content: string): string {\n // Next.js/Astro Image component: <Image src=\"...\" alt=\"...\" />\n // Convert to standard <img> for parsing\n \n // Handle <Image ... /> self-closing\n let normalized = content.replace(\n /<Image\\s+([^>]*?)\\s*\\/>/gi,\n (match, attrs) => {\n return `<img ${attrs}>`;\n }\n );\n \n // Handle <Image ...>...</Image>\n normalized = normalized.replace(\n /<Image\\s+([^>]*?)>([\\s\\S]*?)<\\/Image>/gi,\n (match, attrs, _children) => {\n return `<img ${attrs}>`;\n }\n );\n \n // Gatsby's Img component\n normalized = normalized.replace(\n /<Img\\s+([^>]*?)\\s*\\/>/gi,\n (match, attrs) => {\n return `<img ${attrs}>`;\n }\n );\n \n // Gatsby's StaticImage\n normalized = normalized.replace(\n /<StaticImage\\s+([^>]*?)\\s*\\/>/gi,\n (match, attrs) => {\n return `<img ${attrs}>`;\n }\n );\n \n // Gatsby's GatsbyImage (wrapper component)\n normalized = normalized.replace(\n /<GatsbyImage\\s+([^>]*?)\\s*\\/>/gi,\n (match, attrs) => {\n // GatsbyImage uses 'image' prop instead of 'src', and 'alt' is required\n return `<img ${attrs}>`;\n }\n );\n \n // Handle picture/source patterns - extract img from picture\n const pictureMatch = normalized.match(/<picture[^>]*>[\\s\\S]*?<img\\s+([^>]*?)>[\\s\\S]*?<\\/picture>/gi);\n if (pictureMatch) {\n // Keep the img tags from picture elements\n // They're already captured in the above patterns\n }\n \n return normalized;\n}\n\n/**\n * Normalize Link components from various frameworks to <a>\n * Handles: Next.js <Link>, Gatsby <Link>, React Router <Link>, etc.\n */\nfunction normalizeLinkComponents(content: string): string {\n // Next.js Link: <Link href=\"...\">text</Link>\n let normalized = content.replace(\n /<Link\\s+([^>]*?)>([\\s\\S]*?)<\\/Link>/gi,\n (match, attrs, children) => {\n // Convert 'to' prop to 'href' for React Router compatibility\n const normalizedAttrs = attrs.replace(/\\bto=/g, 'href=');\n return `<a ${normalizedAttrs}>${children}</a>`;\n }\n );\n \n // Self-closing Link (rare but possible)\n normalized = normalized.replace(\n /<Link\\s+([^>]*?)\\s*\\/>/gi,\n (match, attrs) => {\n const normalizedAttrs = attrs.replace(/\\bto=/g, 'href=');\n return `<a ${normalizedAttrs}></a>`;\n }\n );\n \n // Astro client:* directives - remove them\n normalized = normalized.replace(/client:\\w+/g, '');\n \n // Nuxt's NuxtLink\n normalized = normalized.replace(\n /<NuxtLink\\s+([^>]*?)>([\\s\\S]*?)<\\/NuxtLink>/gi,\n (match, attrs, children) => {\n const normalizedAttrs = attrs.replace(/\\bto=/g, 'href=');\n return `<a ${normalizedAttrs}>${children}</a>`;\n }\n );\n \n // SvelteKit's sveltekit:prefetch and similar\n normalized = normalized.replace(/sveltekit:\\w+/g, '');\n normalized = normalized.replace(/data-sveltekit-\\w+=\"[^\"]*\"/g, '');\n \n return normalized;\n}\n\n/**\n * Parse HTML-like content (handles JSX, Astro, Vue templates)\n */\nfunction parseHtmlLikeContent(filePath: string, originalContent: string, htmlContent: string): ParsedPage {\n const $ = cheerio.load(htmlContent, { xml: false });\n\n // Extract H1s (including JSX expressions like {title})\n const h1s: string[] = [];\n $('h1').each((_, el) => {\n let text = $(el).text().trim();\n // Check for dynamic content markers\n const html = $(el).html() || '';\n if (html.includes('{') && html.includes('}')) {\n text = `[dynamic: ${html.replace(/<[^>]+>/g, '').trim()}]`;\n }\n if (text) h1s.push(text);\n });\n\n // Also check for markdown-style H1 in the original content\n const mdH1Match = originalContent.match(/^#\\s+(.+)$/m);\n if (mdH1Match && h1s.length === 0) {\n h1s.push(mdH1Match[1]);\n }\n\n // Extract all headings\n const headings: { level: number; text: string }[] = [];\n $('h1, h2, h3, h4, h5, h6').each((_, el) => {\n const tagName = (el as Element).tagName.toLowerCase();\n const level = parseInt(tagName.replace('h', ''), 10);\n let text = $(el).text().trim();\n const html = $(el).html() || '';\n if (html.includes('{') && html.includes('}')) {\n text = `[dynamic: ${html.replace(/<[^>]+>/g, '').trim()}]`;\n }\n if (text) headings.push({ level, text });\n });\n\n // Extract images (handle both src and dynamic {src})\n const images: { src: string; alt?: string }[] = [];\n $('img').each((_, el) => {\n let src = $(el).attr('src') || '';\n const alt = $(el).attr('alt');\n \n // Handle dynamic src\n if (!src) {\n const srcAttr = $(el).attr(':src') || $(el).attr('v-bind:src'); // Vue\n if (srcAttr) src = `[dynamic: ${srcAttr}]`;\n }\n \n images.push({ src, alt: alt !== undefined ? alt : undefined });\n });\n\n // Also extract Image components (Next.js, Astro)\n $('Image').each((_, el) => {\n const src = $(el).attr('src') || '[dynamic]';\n const alt = $(el).attr('alt');\n images.push({ src, alt: alt !== undefined ? alt : undefined });\n });\n\n // Extract links\n const internalLinks: { href: string; text: string }[] = [];\n const externalLinks: { href: string; text: string }[] = [];\n \n $('a[href], Link[href], Link[to]').each((_, el) => {\n let href = $(el).attr('href') || $(el).attr('to') || '';\n const text = $(el).text().trim();\n \n if (!href || href === '#' || href.startsWith('javascript:') || \n href.startsWith('mailto:') || href.startsWith('tel:')) {\n return;\n }\n\n // Handle dynamic hrefs\n if (href.startsWith('{') || href.includes('${')) {\n href = `[dynamic: ${href}]`;\n }\n\n if (href.startsWith('http://') || href.startsWith('https://') || href.startsWith('//')) {\n externalLinks.push({ href, text });\n } else {\n internalLinks.push({ href, text });\n }\n });\n\n // Try to extract title - first from parsed HTML content\n let title: string | undefined;\n const parsedTitle = $('title').first().text().trim();\n if (parsedTitle) {\n title = parsedTitle;\n }\n \n // Fallback to frontmatter\n if (!title) {\n const titleMatch = originalContent.match(/^title:\\s*[\"']?([^\"'\\n]+)[\"']?/m);\n if (titleMatch) {\n title = titleMatch[1].trim();\n }\n }\n\n // Try to extract description - first from parsed HTML content\n let metaDescription: string | undefined;\n const parsedDesc = $('meta[name=\"description\"]').attr('content')?.trim();\n if (parsedDesc) {\n metaDescription = parsedDesc;\n }\n \n // Fallback to frontmatter\n if (!metaDescription) {\n const descMatch = originalContent.match(/^description:\\s*[\"']?([^\"'\\n]+)[\"']?/m);\n if (descMatch) {\n metaDescription = descMatch[1].trim();\n }\n }\n\n return {\n filePath,\n html: originalContent,\n title,\n metaDescription,\n canonical: undefined,\n viewport: undefined, // Source files usually don't have viewport\n lang: undefined,\n h1s,\n headings,\n images,\n internalLinks,\n externalLinks,\n jsonLd: [],\n ogTags: {},\n twitterTags: {},\n robots: undefined,\n isSourceFile: true, // This is a source file\n };\n}\n","import type { ParsedPage, CheckResult } from '../types/index.js';\n\n/**\n * Check for missing or problematic title tags\n */\nexport function checkMetaTitle(page: ParsedPage, allPages: ParsedPage[]): CheckResult[] {\n const results: CheckResult[] = [];\n\n // Check for missing title\n if (!page.title) {\n results.push({\n checkId: 'meta-title-missing',\n name: 'Missing Title Tag',\n severity: 'critical',\n passed: false,\n file: page.filePath,\n message: 'Page has no <title> tag',\n fix: 'Add a unique, descriptive <title> tag in the <head> section',\n });\n return results; // No point checking length if missing\n }\n\n // Check title length\n const titleLength = page.title.length;\n if (titleLength < 30) {\n results.push({\n checkId: 'meta-title-length',\n name: 'Title Too Short',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `Title is too short (${titleLength} chars, recommended 30-60)`,\n fix: 'Expand your title to be more descriptive (30-60 characters)',\n });\n } else if (titleLength > 60) {\n results.push({\n checkId: 'meta-title-length',\n name: 'Title Too Long',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `Title is too long (${titleLength} chars, recommended 30-60)`,\n fix: 'Shorten your title to under 60 characters to prevent truncation in search results',\n });\n }\n\n // Check for duplicate titles\n const duplicates = allPages.filter(\n (p) => p.filePath !== page.filePath && p.title === page.title\n );\n if (duplicates.length > 0) {\n results.push({\n checkId: 'meta-title-duplicate',\n name: 'Duplicate Title',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `Title is duplicated on ${duplicates.length} other page(s)`,\n fix: 'Each page should have a unique title',\n details: duplicates.map((p) => p.filePath),\n });\n }\n\n return results;\n}\n\n/**\n * Check for missing or problematic meta descriptions\n */\nexport function checkMetaDescription(page: ParsedPage, allPages: ParsedPage[]): CheckResult[] {\n const results: CheckResult[] = [];\n\n // Check for missing description\n if (!page.metaDescription) {\n results.push({\n checkId: 'meta-description-missing',\n name: 'Missing Meta Description',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Page has no meta description',\n fix: 'Add a <meta name=\"description\" content=\"...\"> tag in the <head> section',\n });\n return results;\n }\n\n // Check description length\n const descLength = page.metaDescription.length;\n if (descLength < 120) {\n results.push({\n checkId: 'meta-description-length',\n name: 'Meta Description Too Short',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `Meta description is too short (${descLength} chars, recommended 120-160)`,\n fix: 'Expand your meta description to be more descriptive (120-160 characters)',\n });\n } else if (descLength > 160) {\n results.push({\n checkId: 'meta-description-length',\n name: 'Meta Description Too Long',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `Meta description is too long (${descLength} chars, recommended 120-160)`,\n fix: 'Shorten your meta description to under 160 characters to prevent truncation',\n });\n }\n\n // Check for duplicate descriptions\n const duplicates = allPages.filter(\n (p) => p.filePath !== page.filePath && p.metaDescription === page.metaDescription\n );\n if (duplicates.length > 0) {\n results.push({\n checkId: 'meta-description-duplicate',\n name: 'Duplicate Meta Description',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `Meta description is duplicated on ${duplicates.length} other page(s)`,\n fix: 'Each page should have a unique meta description',\n details: duplicates.map((p) => p.filePath),\n });\n }\n\n return results;\n}\n\n/**\n * Check for missing viewport meta tag\n * Note: Skipped for source files since viewport is typically in layouts\n */\nexport function checkViewport(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n\n // Skip for source files - viewport is typically in layout files\n if (page.isSourceFile) {\n return results;\n }\n\n if (!page.viewport) {\n results.push({\n checkId: 'viewport-missing',\n name: 'Missing Viewport Meta Tag',\n severity: 'critical',\n passed: false,\n file: page.filePath,\n message: 'Page has no viewport meta tag',\n fix: 'Add <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"> in the <head>',\n });\n }\n\n return results;\n}\n\n/**\n * Check for missing lang attribute\n * Note: Skipped for source files since lang is typically in layouts\n */\nexport function checkLang(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n\n // Skip for source files - lang is typically on the root <html> in layouts\n if (page.isSourceFile) {\n return results;\n }\n\n if (!page.lang) {\n results.push({\n checkId: 'lang-missing',\n name: 'Missing Language Attribute',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Page has no lang attribute on <html> tag',\n fix: 'Add lang=\"en\" (or appropriate language code) to the <html> tag',\n });\n }\n\n return results;\n}\n\n/**\n * Check for canonical URL issues\n * Note: Skipped for source files since canonical is typically set dynamically\n */\nexport function checkCanonical(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n\n // Skip for source files - canonical is typically set in layouts or dynamically\n if (page.isSourceFile) {\n return results;\n }\n\n if (!page.canonical) {\n results.push({\n checkId: 'canonical-missing',\n name: 'Missing Canonical URL',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Page has no canonical URL defined',\n fix: 'Add <link rel=\"canonical\" href=\"...\"> in the <head> section',\n });\n }\n\n return results;\n}\n","import type { ParsedPage, CheckResult } from '../types/index.js';\n\n/**\n * Check for missing or multiple H1 tags\n */\nexport function checkH1(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n\n if (page.h1s.length === 0) {\n results.push({\n checkId: 'h1-missing',\n name: 'Missing H1 Tag',\n severity: 'critical',\n passed: false,\n file: page.filePath,\n message: 'Page has no H1 tag',\n fix: 'Add a single H1 tag that describes the main content of the page',\n });\n } else if (page.h1s.length > 1) {\n results.push({\n checkId: 'h1-multiple',\n name: 'Multiple H1 Tags',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `Page has ${page.h1s.length} H1 tags (should have exactly 1)`,\n fix: 'Use only one H1 tag per page. Use H2-H6 for subheadings.',\n details: page.h1s,\n });\n }\n\n return results;\n}\n\n/**\n * Check heading hierarchy (no skipped levels)\n */\nexport function checkHeadingHierarchy(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n \n if (page.headings.length === 0) {\n return results; // No headings to check\n }\n\n let prevLevel = 0;\n const skippedLevels: string[] = [];\n\n for (const heading of page.headings) {\n // Allow going from 0 to any level (first heading)\n // Allow going to same level or lower (sibling or parent)\n // Allow going to next level (child)\n // Don't allow skipping levels (e.g., H1 -> H3)\n if (prevLevel > 0 && heading.level > prevLevel + 1) {\n skippedLevels.push(`H${prevLevel} → H${heading.level} (\"${heading.text.substring(0, 30)}...\")`);\n }\n prevLevel = heading.level;\n }\n\n if (skippedLevels.length > 0) {\n results.push({\n checkId: 'heading-hierarchy',\n name: 'Skipped Heading Levels',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `Heading hierarchy skips levels in ${skippedLevels.length} place(s)`,\n fix: 'Use headings in order (H1 → H2 → H3). Don\\'t skip levels.',\n details: skippedLevels,\n });\n }\n\n return results;\n}\n","import type { ParsedPage, CheckResult } from '../types/index.js';\n\n/**\n * Check for images missing alt text\n */\nexport function checkImageAlt(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n\n // Find images with no alt attribute at all\n const missingAlt = page.images.filter((img) => img.alt === undefined);\n \n if (missingAlt.length > 0) {\n results.push({\n checkId: 'image-alt-missing',\n name: 'Images Missing Alt Text',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `${missingAlt.length} image(s) missing alt attribute`,\n fix: 'Add descriptive alt text to all images for accessibility and SEO',\n details: missingAlt.map((img) => img.src),\n });\n }\n\n // Find images with empty alt (this is okay for decorative images, just info)\n const emptyAlt = page.images.filter((img) => img.alt === '');\n \n if (emptyAlt.length > 0) {\n results.push({\n checkId: 'image-alt-empty',\n name: 'Images With Empty Alt Text',\n severity: 'info',\n passed: true, // Empty alt is valid for decorative images\n file: page.filePath,\n message: `${emptyAlt.length} image(s) have empty alt=\"\" (okay for decorative images)`,\n details: emptyAlt.map((img) => img.src),\n });\n }\n\n return results;\n}\n","import * as path from 'path';\nimport * as fs from 'fs';\nimport type { ParsedPage, CheckResult } from '../types/index.js';\n\n/**\n * Check for broken internal links (links to files that don't exist)\n */\nexport function checkInternalLinks(\n page: ParsedPage,\n allPages: ParsedPage[],\n basePath: string\n): CheckResult[] {\n const results: CheckResult[] = [];\n const brokenLinks: string[] = [];\n\n // Get all file paths that exist\n const existingPaths = new Set(\n allPages.map((p) => {\n // Normalize to relative path from base\n const rel = path.relative(basePath, p.filePath);\n // Convert to URL-like path\n return '/' + rel.replace(/\\\\/g, '/').replace(/index\\.html$/, '').replace(/\\.html$/, '');\n })\n );\n\n // Also add the raw file paths\n allPages.forEach((p) => {\n const rel = path.relative(basePath, p.filePath);\n existingPaths.add('/' + rel.replace(/\\\\/g, '/'));\n });\n\n for (const link of page.internalLinks) {\n let href = link.href;\n\n // Skip anchors, empty, or special links\n if (!href || href.startsWith('#') || href.startsWith('javascript:')) {\n continue;\n }\n\n // Handle relative links\n if (!href.startsWith('/')) {\n const pageDir = path.dirname(page.filePath);\n const absolutePath = path.resolve(pageDir, href);\n href = '/' + path.relative(basePath, absolutePath).replace(/\\\\/g, '/');\n }\n\n // Normalize the href\n const normalizedHref = href\n .split('#')[0] // Remove anchor\n .split('?')[0] // Remove query string\n .replace(/\\/$/, ''); // Remove trailing slash\n\n // Check if the target exists\n const targetExists =\n existingPaths.has(normalizedHref) ||\n existingPaths.has(normalizedHref + '/') ||\n existingPaths.has(normalizedHref + '/index.html') ||\n existingPaths.has(normalizedHref + '.html') ||\n // Check if actual file exists (for non-HTML assets)\n fs.existsSync(path.join(basePath, normalizedHref));\n\n if (!targetExists && normalizedHref !== '' && normalizedHref !== '/') {\n brokenLinks.push(link.href);\n }\n }\n\n if (brokenLinks.length > 0) {\n results.push({\n checkId: 'link-broken-internal',\n name: 'Broken Internal Links',\n severity: 'critical',\n passed: false,\n file: page.filePath,\n message: `${brokenLinks.length} internal link(s) point to non-existent pages`,\n fix: 'Fix or remove links to pages that don\\'t exist',\n details: [...new Set(brokenLinks)], // Dedupe\n });\n }\n\n // Check for empty hrefs\n const emptyLinks = page.internalLinks.filter(\n (link) => !link.href || link.href === '#'\n );\n\n if (emptyLinks.length > 0) {\n results.push({\n checkId: 'link-empty-href',\n name: 'Empty Link Href',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `${emptyLinks.length} link(s) have empty or \"#\" href`,\n fix: 'Add proper href values to all links or use buttons for non-navigation actions',\n });\n }\n\n return results;\n}\n","import type { ParsedPage, CheckResult } from '../types/index.js';\n\n// Type for JSON-LD schema objects\ntype JsonLdSchema = Record<string, unknown>;\n\n/**\n * Check JSON-LD structured data for validity\n */\nexport function checkSchema(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n\n // Check if JSON-LD was parseable\n // Note: Invalid JSON is already filtered out in the parser,\n // but we can check for common issues in valid JSON\n\n for (const schema of page.jsonLd as JsonLdSchema[]) {\n // Check for missing @context\n if (!('@context' in schema)) {\n results.push({\n checkId: 'schema-missing-context',\n name: 'Schema Missing @context',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'JSON-LD is missing @context property',\n fix: 'Add \"@context\": \"https://schema.org\" to your JSON-LD',\n });\n }\n\n // Check for missing @type\n if (!('@type' in schema)) {\n results.push({\n checkId: 'schema-missing-type',\n name: 'Schema Missing @type',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'JSON-LD is missing @type property',\n fix: 'Add \"@type\": \"YourSchemaType\" to your JSON-LD',\n });\n }\n }\n\n return results;\n}\n\n/**\n * Validate JSON-LD syntax by attempting to find invalid scripts\n * This runs on the raw HTML to catch JSON parse errors\n */\nexport function checkSchemaJsonValidity(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n\n // Use regex to find JSON-LD scripts\n const jsonLdRegex = /<script[^>]*type=[\"']application\\/ld\\+json[\"'][^>]*>([\\s\\S]*?)<\\/script>/gi;\n let match;\n let index = 0;\n\n while ((match = jsonLdRegex.exec(page.html)) !== null) {\n index++;\n const content = match[1].trim();\n \n if (!content) {\n results.push({\n checkId: 'schema-empty',\n name: 'Empty JSON-LD Script',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `JSON-LD script #${index} is empty`,\n fix: 'Add valid JSON-LD content or remove the empty script tag',\n });\n continue;\n }\n\n try {\n JSON.parse(content);\n } catch (error) {\n results.push({\n checkId: 'schema-invalid-json',\n name: 'Invalid JSON-LD Syntax',\n severity: 'critical',\n passed: false,\n file: page.filePath,\n message: `JSON-LD script #${index} has invalid JSON syntax`,\n fix: 'Fix the JSON syntax error in your structured data',\n details: [error instanceof Error ? error.message : 'Unknown error'],\n });\n }\n }\n\n return results;\n}\n\n/**\n * Check for Speakable schema (important for voice search and AI discoverability)\n */\nexport function checkSpeakableSchema(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n const schemas = page.jsonLd as JsonLdSchema[];\n \n // Look for speakable in any schema\n const hasSpeakable = schemas.some(schema => {\n if ('speakable' in schema) return true;\n // Check nested schemas (like WebPage with speakable)\n if (typeof schema === 'object') {\n return JSON.stringify(schema).includes('\"speakable\"');\n }\n return false;\n });\n\n // Check if this is a content page that should have speakable\n const isContentPage = schemas.some(schema => {\n const type = schema['@type'];\n return ['Article', 'NewsArticle', 'BlogPosting', 'WebPage', 'FAQPage', 'Product', 'Service'].includes(type as string);\n });\n\n if (isContentPage && !hasSpeakable) {\n results.push({\n checkId: 'schema-speakable-missing',\n name: 'Speakable Schema Missing',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Content page lacks speakable schema for voice search/AI optimization',\n fix: 'Add speakable specification to help voice assistants and AI find key content:\\n' +\n ' \"speakable\": {\\n' +\n ' \"@type\": \"SpeakableSpecification\",\\n' +\n ' \"cssSelector\": [\"h1\", \".main-content\", \".key-points\"]\\n' +\n ' }',\n });\n }\n\n // Validate speakable structure if present\n for (const schema of schemas) {\n if ('speakable' in schema) {\n const speakable = schema.speakable as JsonLdSchema;\n \n if (!speakable['@type'] || speakable['@type'] !== 'SpeakableSpecification') {\n results.push({\n checkId: 'schema-speakable-invalid-type',\n name: 'Invalid Speakable Type',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Speakable schema has incorrect or missing @type',\n fix: 'Set \"@type\": \"SpeakableSpecification\" in the speakable object',\n });\n }\n\n if (!speakable.cssSelector && !speakable.xpath) {\n results.push({\n checkId: 'schema-speakable-no-selector',\n name: 'Speakable Missing Selector',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Speakable schema needs cssSelector or xpath to identify content',\n fix: 'Add \"cssSelector\": [\"h1\", \".content\"] or \"xpath\": [\"/html/body/article\"]',\n });\n }\n }\n }\n\n return results;\n}\n\n/**\n * Check Offer/Pricing schema for e-commerce and SaaS pages\n */\nexport function checkOfferSchema(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n const schemas = page.jsonLd as JsonLdSchema[];\n\n // Check Product/SoftwareApplication schemas for offers\n const productSchemas = schemas.filter(schema => {\n const type = schema['@type'];\n return ['Product', 'SoftwareApplication', 'Service'].includes(type as string);\n });\n\n for (const product of productSchemas) {\n if (!product.offers) {\n results.push({\n checkId: 'schema-product-no-offers',\n name: 'Product Missing Offers',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `${product['@type']} schema is missing offers/pricing information`,\n fix: 'Add \"offers\" property with price, priceCurrency, and availability',\n });\n continue;\n }\n\n // Validate offer structure\n const offersRaw = product.offers;\n const offers = (Array.isArray(offersRaw) ? offersRaw : [offersRaw]) as JsonLdSchema[];\n for (const offer of offers) {\n if (!offer.price && offer.price !== 0) {\n results.push({\n checkId: 'schema-offer-no-price',\n name: 'Offer Missing Price',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Offer schema is missing price property',\n fix: 'Add \"price\": \"29.99\" or \"price\": \"0\" for free items',\n });\n }\n\n if (!offer.priceCurrency) {\n results.push({\n checkId: 'schema-offer-no-currency',\n name: 'Offer Missing Currency',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Offer schema is missing priceCurrency property',\n fix: 'Add \"priceCurrency\": \"USD\" (use ISO 4217 currency code)',\n });\n }\n }\n }\n\n // Check for Sale/Discount schema opportunities\n const hasSaleSchema = schemas.some(schema => schema['@type'] === 'Sale');\n const hasDiscountedOffers = schemas.some(schema => {\n if (schema.offers) {\n const offersRaw = schema.offers;\n const offers = (Array.isArray(offersRaw) ? offersRaw : [offersRaw]) as JsonLdSchema[];\n return offers.some(o => o.priceSpecification || o.discount);\n }\n return false;\n });\n\n // Look for discount indicators in HTML (common patterns)\n const htmlLower = page.html.toLowerCase();\n const hasDiscountContent = /sale|discount|% off|save \\$|was \\$|original price|strike|line-through/i.test(htmlLower);\n\n if (hasDiscountContent && !hasSaleSchema && !hasDiscountedOffers) {\n results.push({\n checkId: 'schema-sale-missing',\n name: 'Sale Schema Recommended',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Page appears to have discounted pricing but no Sale or discount schema',\n fix: 'Add Sale schema or priceSpecification with validThrough date:\\n' +\n ' {\\n' +\n ' \"@type\": \"Sale\",\\n' +\n ' \"name\": \"Holiday Sale\",\\n' +\n ' \"description\": \"20% off all plans\",\\n' +\n ' \"validThrough\": \"2025-12-31\"\\n' +\n ' }',\n });\n }\n\n return results;\n}\n\n/**\n * Check for FAQ schema (great for AI/voice search)\n */\nexport function checkFAQSchema(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n const schemas = page.jsonLd as JsonLdSchema[];\n\n const faqSchema = schemas.find(schema => schema['@type'] === 'FAQPage');\n\n // Check if page has FAQ-like content but no schema\n const hasFAQContent = /<(dt|summary|h[2-4])[^>]*>[^<]*(faq|question|q:|q\\.|ask|how|what|why|when|where|who)/i.test(page.html) ||\n /class=[\"'][^\"']*faq/i.test(page.html);\n\n if (hasFAQContent && !faqSchema) {\n results.push({\n checkId: 'schema-faq-missing',\n name: 'FAQ Schema Recommended',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Page has FAQ content but no FAQPage schema',\n fix: 'Add FAQPage schema to get rich results and improve AI discoverability:\\n' +\n ' {\\n' +\n ' \"@type\": \"FAQPage\",\\n' +\n ' \"mainEntity\": [{\\n' +\n ' \"@type\": \"Question\",\\n' +\n ' \"name\": \"Your question?\",\\n' +\n ' \"acceptedAnswer\": {\\n' +\n ' \"@type\": \"Answer\",\\n' +\n ' \"text\": \"Your answer\"\\n' +\n ' }\\n' +\n ' }]\\n' +\n ' }',\n });\n }\n\n // Validate FAQ schema structure\n if (faqSchema) {\n const mainEntity = faqSchema.mainEntity as JsonLdSchema[] | undefined;\n \n if (!mainEntity || !Array.isArray(mainEntity) || mainEntity.length === 0) {\n results.push({\n checkId: 'schema-faq-empty',\n name: 'FAQ Schema Empty',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'FAQPage schema has no questions in mainEntity',\n fix: 'Add Question/Answer pairs to the mainEntity array',\n });\n } else {\n // Validate each question\n for (let i = 0; i < mainEntity.length; i++) {\n const qa = mainEntity[i];\n \n if (qa['@type'] !== 'Question') {\n results.push({\n checkId: 'schema-faq-invalid-question',\n name: 'FAQ Invalid Question Type',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `FAQ item ${i + 1} is not a Question type`,\n fix: 'Set \"@type\": \"Question\" for each FAQ item',\n });\n }\n\n if (!qa.name) {\n results.push({\n checkId: 'schema-faq-no-question-text',\n name: 'FAQ Missing Question Text',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `FAQ Question ${i + 1} is missing the question text (name property)`,\n fix: 'Add \"name\": \"Your question?\" to each Question',\n });\n }\n\n const answer = qa.acceptedAnswer as JsonLdSchema | undefined;\n if (!answer || !answer.text) {\n results.push({\n checkId: 'schema-faq-no-answer',\n name: 'FAQ Missing Answer',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `FAQ Question ${i + 1} is missing an answer`,\n fix: 'Add acceptedAnswer with @type \"Answer\" and \"text\" property',\n });\n }\n }\n }\n }\n\n return results;\n}\n\n/**\n * Check for HowTo schema (great for AI featured snippets)\n */\nexport function checkHowToSchema(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n const schemas = page.jsonLd as JsonLdSchema[];\n\n const howToSchema = schemas.find(schema => schema['@type'] === 'HowTo');\n\n // Check if page has how-to content but no schema\n const hasHowToContent = /how to|step[s]? [0-9]|guide:|tutorial|instruction/i.test(page.html) &&\n /<(ol|ul)[^>]*class=[\"'][^\"']*step/i.test(page.html);\n\n if (hasHowToContent && !howToSchema) {\n results.push({\n checkId: 'schema-howto-missing',\n name: 'HowTo Schema Recommended',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Page has step-by-step content but no HowTo schema',\n fix: 'Add HowTo schema for rich results:\\n' +\n ' {\\n' +\n ' \"@type\": \"HowTo\",\\n' +\n ' \"name\": \"How to ...\",\\n' +\n ' \"step\": [{\\n' +\n ' \"@type\": \"HowToStep\",\\n' +\n ' \"name\": \"Step 1\",\\n' +\n ' \"text\": \"Description...\"\\n' +\n ' }]\\n' +\n ' }',\n });\n }\n\n return results;\n}\n","import type { ParsedPage, CheckResult } from '../types/index.js';\n\n/**\n * Check for Open Graph meta tags\n */\nexport function checkOpenGraph(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n\n // Skip source files - OG tags are usually in layouts\n if (page.isSourceFile) {\n return results;\n }\n\n const og = page.ogTags;\n\n // Check og:title\n if (!og['og:title']) {\n results.push({\n checkId: 'og-title-missing',\n name: 'Missing og:title',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Page is missing og:title meta tag',\n fix: 'Add <meta property=\"og:title\" content=\"Your Page Title\" /> for better social sharing',\n });\n }\n\n // Check og:description\n if (!og['og:description']) {\n results.push({\n checkId: 'og-description-missing',\n name: 'Missing og:description',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Page is missing og:description meta tag',\n fix: 'Add <meta property=\"og:description\" content=\"Your description\" /> for better social sharing',\n });\n }\n\n // Check og:image\n if (!og['og:image']) {\n results.push({\n checkId: 'og-image-missing',\n name: 'Missing og:image',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Page is missing og:image meta tag - shared links will have no preview image',\n fix: 'Add <meta property=\"og:image\" content=\"https://example.com/image.jpg\" /> (use absolute URL, min 1200x630px recommended)',\n });\n } else {\n // Check if og:image is absolute URL\n const ogImage = og['og:image'];\n if (!ogImage.startsWith('http://') && !ogImage.startsWith('https://')) {\n results.push({\n checkId: 'og-image-relative',\n name: 'Relative og:image URL',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'og:image should use an absolute URL',\n fix: 'Change to absolute URL: https://yourdomain.com/path/to/image.jpg',\n });\n }\n }\n\n // Check og:type\n if (!og['og:type']) {\n results.push({\n checkId: 'og-type-missing',\n name: 'Missing og:type',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Page is missing og:type meta tag (defaults to \"website\")',\n fix: 'Add <meta property=\"og:type\" content=\"website\" /> or \"article\" for blog posts',\n });\n }\n\n // Check og:url\n if (!og['og:url']) {\n results.push({\n checkId: 'og-url-missing',\n name: 'Missing og:url',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Page is missing og:url meta tag',\n fix: 'Add <meta property=\"og:url\" content=\"https://example.com/page\" /> with the canonical URL',\n });\n }\n\n return results;\n}\n\n/**\n * Check for Twitter Card meta tags\n */\nexport function checkTwitterCards(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n\n // Skip source files - Twitter tags are usually in layouts\n if (page.isSourceFile) {\n return results;\n }\n\n const twitter = page.twitterTags;\n const og = page.ogTags;\n\n // Check twitter:card\n if (!twitter['twitter:card']) {\n results.push({\n checkId: 'twitter-card-missing',\n name: 'Missing twitter:card',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Page is missing twitter:card meta tag',\n fix: 'Add <meta name=\"twitter:card\" content=\"summary_large_image\" /> for large preview, or \"summary\" for small',\n });\n } else {\n // Validate card type\n const validTypes = ['summary', 'summary_large_image', 'app', 'player'];\n if (!validTypes.includes(twitter['twitter:card'])) {\n results.push({\n checkId: 'twitter-card-invalid',\n name: 'Invalid twitter:card value',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `Invalid twitter:card value: \"${twitter['twitter:card']}\"`,\n fix: `Use one of: ${validTypes.join(', ')}`,\n });\n }\n }\n\n // Check twitter:title (falls back to og:title)\n if (!twitter['twitter:title'] && !og['og:title']) {\n results.push({\n checkId: 'twitter-title-missing',\n name: 'Missing twitter:title',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Page has no twitter:title or og:title to fall back on',\n fix: 'Add <meta name=\"twitter:title\" content=\"Your Title\" /> or og:title',\n });\n }\n\n // Check twitter:description (falls back to og:description)\n if (!twitter['twitter:description'] && !og['og:description']) {\n results.push({\n checkId: 'twitter-description-missing',\n name: 'Missing twitter:description',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Page has no twitter:description or og:description to fall back on',\n fix: 'Add <meta name=\"twitter:description\" content=\"Your description\" /> or og:description',\n });\n }\n\n // Check twitter:image (falls back to og:image)\n if (!twitter['twitter:image'] && !og['og:image']) {\n results.push({\n checkId: 'twitter-image-missing',\n name: 'Missing twitter:image',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Page has no twitter:image or og:image to fall back on',\n fix: 'Add <meta name=\"twitter:image\" content=\"https://example.com/image.jpg\" /> or og:image',\n });\n }\n\n return results;\n}\n\n/**\n * Check for robots meta issues\n */\nexport function checkRobotsMeta(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n\n // Skip source files\n if (page.isSourceFile) {\n return results;\n }\n\n if (page.robots) {\n const robotsLower = page.robots.toLowerCase();\n\n // Check if page is blocking indexing\n if (robotsLower.includes('noindex')) {\n results.push({\n checkId: 'robots-noindex',\n name: 'Page blocked from indexing',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Page has \"noindex\" in robots meta tag - it will not appear in search results',\n fix: 'Remove noindex if you want this page to be indexed, or ignore if intentional',\n });\n }\n\n // Check if page is blocking following\n if (robotsLower.includes('nofollow')) {\n results.push({\n checkId: 'robots-nofollow',\n name: 'Links blocked from following',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Page has \"nofollow\" in robots meta tag - links will not pass PageRank',\n fix: 'Remove nofollow unless intentional (e.g., user-generated content pages)',\n });\n }\n\n // Check for conflicting directives\n if (robotsLower.includes('noindex') && robotsLower.includes('index')) {\n results.push({\n checkId: 'robots-conflicting',\n name: 'Conflicting robots directives',\n severity: 'critical',\n passed: false,\n file: page.filePath,\n message: 'Page has both \"index\" and \"noindex\" directives - this is confusing for crawlers',\n fix: 'Use either \"index\" or \"noindex\", not both',\n });\n }\n }\n\n return results;\n}\n","import type { ParsedPage, CheckResult } from '../types/index.js';\nimport * as cheerio from 'cheerio';\nimport type { Element } from 'domhandler';\n\n/**\n * Check for ARIA and accessibility issues\n */\nexport function checkAccessibility(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n const $ = cheerio.load(page.html);\n\n // Check for skip link\n const skipLink = $('a[href=\"#main\"], a[href=\"#content\"], a[href=\"#main-content\"], .skip-link, .skip-to-content');\n if (skipLink.length === 0) {\n results.push({\n checkId: 'a11y-skip-link',\n name: 'Missing Skip Link',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Page has no skip navigation link for keyboard users',\n fix: 'Add a skip link as the first focusable element: <a href=\"#main\" class=\"sr-only focus:not-sr-only\">Skip to content</a>',\n });\n }\n\n // Check for main landmark\n const mainLandmark = $('main, [role=\"main\"]');\n if (mainLandmark.length === 0) {\n results.push({\n checkId: 'a11y-main-landmark',\n name: 'Missing Main Landmark',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Page has no <main> element or role=\"main\"',\n fix: 'Wrap your main content in a <main> element for screen reader navigation',\n });\n } else if (mainLandmark.length > 1) {\n results.push({\n checkId: 'a11y-multiple-main',\n name: 'Multiple Main Landmarks',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `Page has ${mainLandmark.length} main landmarks - there should only be one`,\n fix: 'Ensure only one <main> element exists per page',\n });\n }\n\n // Check for nav landmark\n const navLandmark = $('nav, [role=\"navigation\"]');\n if (navLandmark.length === 0) {\n results.push({\n checkId: 'a11y-nav-landmark',\n name: 'Missing Nav Landmark',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Page has no <nav> element for navigation',\n fix: 'Wrap your navigation in a <nav> element',\n });\n }\n\n // Check for buttons without accessible names\n const buttonsWithoutText: string[] = [];\n $('button').each((_, el) => {\n const $btn = $(el);\n const text = $btn.text().trim();\n const ariaLabel = $btn.attr('aria-label');\n const ariaLabelledby = $btn.attr('aria-labelledby');\n const title = $btn.attr('title');\n \n if (!text && !ariaLabel && !ariaLabelledby && !title) {\n // Try to identify the button\n const className = $btn.attr('class') || '';\n const id = $btn.attr('id') || '';\n buttonsWithoutText.push(className || id || 'unnamed button');\n }\n });\n \n if (buttonsWithoutText.length > 0) {\n results.push({\n checkId: 'a11y-button-name',\n name: 'Buttons Without Accessible Name',\n severity: 'critical',\n passed: false,\n file: page.filePath,\n message: `${buttonsWithoutText.length} button(s) have no accessible name`,\n fix: 'Add text content, aria-label, or aria-labelledby to buttons',\n details: buttonsWithoutText.slice(0, 10),\n });\n }\n\n // Check for links without accessible names\n const linksWithoutText: string[] = [];\n $('a[href]').each((_, el) => {\n const $link = $(el);\n const text = $link.text().trim();\n const ariaLabel = $link.attr('aria-label');\n const ariaLabelledby = $link.attr('aria-labelledby');\n const title = $link.attr('title');\n const hasImg = $link.find('img[alt]').length > 0;\n \n if (!text && !ariaLabel && !ariaLabelledby && !title && !hasImg) {\n const href = $link.attr('href') || '';\n linksWithoutText.push(href.substring(0, 50));\n }\n });\n \n if (linksWithoutText.length > 0) {\n results.push({\n checkId: 'a11y-link-name',\n name: 'Links Without Accessible Name',\n severity: 'critical',\n passed: false,\n file: page.filePath,\n message: `${linksWithoutText.length} link(s) have no accessible name`,\n fix: 'Add text content, aria-label, or an image with alt text to links',\n details: linksWithoutText.slice(0, 10),\n });\n }\n\n // Check for form inputs without labels\n const inputsWithoutLabels: string[] = [];\n $('input:not([type=\"hidden\"]):not([type=\"submit\"]):not([type=\"button\"]):not([type=\"reset\"]), textarea, select').each((_, el) => {\n const $input = $(el);\n const id = $input.attr('id');\n const ariaLabel = $input.attr('aria-label');\n const ariaLabelledby = $input.attr('aria-labelledby');\n const placeholder = $input.attr('placeholder');\n const title = $input.attr('title');\n \n // Check for associated label\n let hasLabel = false;\n if (id) {\n hasLabel = $(`label[for=\"${id}\"]`).length > 0;\n }\n \n // Check if wrapped in label\n if (!hasLabel) {\n hasLabel = $input.closest('label').length > 0;\n }\n \n if (!hasLabel && !ariaLabel && !ariaLabelledby && !title) {\n const name = $input.attr('name') || $input.attr('id') || 'unnamed';\n const type = $input.attr('type') || 'text';\n inputsWithoutLabels.push(`${type}: ${name}${placeholder ? ` (placeholder: ${placeholder})` : ''}`);\n }\n });\n \n if (inputsWithoutLabels.length > 0) {\n results.push({\n checkId: 'a11y-input-label',\n name: 'Form Inputs Without Labels',\n severity: 'critical',\n passed: false,\n file: page.filePath,\n message: `${inputsWithoutLabels.length} form input(s) have no associated label`,\n fix: 'Add <label for=\"inputId\"> or wrap inputs in <label> elements. Placeholder is not a substitute for labels.',\n details: inputsWithoutLabels.slice(0, 10),\n });\n }\n\n // Check for tabindex > 0 (anti-pattern)\n const positiveTabindex: string[] = [];\n $('[tabindex]').each((_, el) => {\n const tabindex = parseInt($(el).attr('tabindex') || '0', 10);\n if (tabindex > 0) {\n const tagName = (el as Element).tagName;\n positiveTabindex.push(`${tagName} (tabindex=${tabindex})`);\n }\n });\n \n if (positiveTabindex.length > 0) {\n results.push({\n checkId: 'a11y-tabindex-positive',\n name: 'Positive Tabindex Values',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `${positiveTabindex.length} element(s) have tabindex > 0, which disrupts natural tab order`,\n fix: 'Use tabindex=\"0\" to add to natural tab order, or tabindex=\"-1\" to make focusable via JS only',\n details: positiveTabindex.slice(0, 10),\n });\n }\n\n // Check for autoplay videos without muted\n const autoplayVideos: string[] = [];\n $('video[autoplay]').each((_, el) => {\n const $video = $(el);\n if (!$video.attr('muted')) {\n const src = $video.attr('src') || $video.find('source').first().attr('src') || 'unknown';\n autoplayVideos.push(src.substring(0, 50));\n }\n });\n \n if (autoplayVideos.length > 0) {\n results.push({\n checkId: 'a11y-autoplay-audio',\n name: 'Autoplay Video With Audio',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `${autoplayVideos.length} video(s) autoplay without being muted`,\n fix: 'Add the muted attribute to autoplay videos: <video autoplay muted>',\n details: autoplayVideos,\n });\n }\n\n // Check for empty table headers\n const emptyTableHeaders: number[] = [];\n $('th').each((index, el) => {\n const text = $(el).text().trim();\n if (!text) {\n emptyTableHeaders.push(index + 1);\n }\n });\n \n if (emptyTableHeaders.length > 0) {\n results.push({\n checkId: 'a11y-empty-th',\n name: 'Empty Table Headers',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `${emptyTableHeaders.length} table header(s) are empty`,\n fix: 'Add descriptive text to all <th> elements, or use scope attribute',\n });\n }\n\n // Check for document language (already in meta-tags.ts but important for a11y)\n // This is a duplicate check but important enough to surface in accessibility context\n\n return results;\n}\n\n/**\n * Check color contrast (basic check - looks for common anti-patterns)\n */\nexport function checkColorContrast(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n const $ = cheerio.load(page.html);\n\n // Look for inline styles with potentially low contrast colors\n const potentialIssues: string[] = [];\n \n $('[style*=\"color\"]').each((_, el) => {\n const style = $(el).attr('style') || '';\n \n // Check for light gray text (common accessibility issue)\n const colorMatch = style.match(/color:\\s*(#[a-fA-F0-9]{3,6}|rgb[a]?\\([^)]+\\)|[a-z]+)/i);\n if (colorMatch) {\n const color = colorMatch[1].toLowerCase();\n // Flag very light colors\n if (color.match(/^#[c-f][c-f][c-f]$/i) || // Light hex shorthand\n color.match(/^#[c-f]{2}[c-f]{2}[c-f]{2}$/i) || // Light hex\n color === 'lightgray' || color === 'lightgrey' ||\n color === 'silver' || color === 'gainsboro') {\n potentialIssues.push(`Light text color: ${color}`);\n }\n }\n });\n\n if (potentialIssues.length > 0) {\n results.push({\n checkId: 'a11y-color-contrast',\n name: 'Potential Color Contrast Issues',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: `${potentialIssues.length} element(s) may have low color contrast`,\n fix: 'Ensure text has at least 4.5:1 contrast ratio (3:1 for large text). Use a contrast checker tool.',\n details: potentialIssues.slice(0, 5),\n });\n }\n\n return results;\n}\n\n/**\n * Check for focus visibility issues\n */\nexport function checkFocusIndicators(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n const $ = cheerio.load(page.html);\n\n // Look for outline:none or outline:0 in inline styles\n const outlineNone: string[] = [];\n $('[style*=\"outline\"]').each((_, el) => {\n const style = $(el).attr('style') || '';\n if (style.match(/outline:\\s*(none|0)/i)) {\n const tagName = (el as Element).tagName;\n outlineNone.push(tagName);\n }\n });\n\n if (outlineNone.length > 0) {\n results.push({\n checkId: 'a11y-focus-outline',\n name: 'Focus Outline Removed',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `${outlineNone.length} element(s) have outline:none which may hide focus indicators`,\n fix: 'Provide custom focus styles instead of removing outlines: :focus { outline: 2px solid blue; }',\n details: outlineNone,\n });\n }\n\n return results;\n}\n","import type { ParsedPage, CheckResult } from '../types/index.js';\nimport {\n checkMetaTitle,\n checkMetaDescription,\n checkViewport,\n checkLang,\n checkCanonical,\n} from './meta-tags.js';\nimport { checkH1, checkHeadingHierarchy } from './headings.js';\nimport { checkImageAlt } from './images.js';\nimport { checkInternalLinks } from './links.js';\nimport { \n checkSchema, \n checkSchemaJsonValidity,\n checkSpeakableSchema,\n checkOfferSchema,\n checkFAQSchema,\n checkHowToSchema,\n} from './schema.js';\nimport { checkOpenGraph, checkTwitterCards, checkRobotsMeta } from './social.js';\nimport { checkAccessibility, checkColorContrast, checkFocusIndicators } from './accessibility.js';\n\nexport interface CheckRegistry {\n id: string;\n name: string;\n description: string;\n severity: 'critical' | 'warning' | 'info';\n run: (page: ParsedPage, allPages: ParsedPage[], basePath: string) => CheckResult[];\n}\n\n/**\n * All available checks\n */\nexport const checks: CheckRegistry[] = [\n // Meta tags\n {\n id: 'meta-title',\n name: 'Title Tag',\n description: 'Check for missing, short, long, or duplicate title tags',\n severity: 'critical',\n run: (page, allPages) => checkMetaTitle(page, allPages),\n },\n {\n id: 'meta-description',\n name: 'Meta Description',\n description: 'Check for missing, short, long, or duplicate meta descriptions',\n severity: 'warning',\n run: (page, allPages) => checkMetaDescription(page, allPages),\n },\n {\n id: 'viewport',\n name: 'Viewport Meta Tag',\n description: 'Check for missing viewport meta tag',\n severity: 'critical',\n run: (page) => checkViewport(page),\n },\n {\n id: 'lang',\n name: 'Language Attribute',\n description: 'Check for missing lang attribute on html tag',\n severity: 'warning',\n run: (page) => checkLang(page),\n },\n {\n id: 'canonical',\n name: 'Canonical URL',\n description: 'Check for missing canonical URL',\n severity: 'warning',\n run: (page) => checkCanonical(page),\n },\n\n // Headings\n {\n id: 'h1',\n name: 'H1 Tag',\n description: 'Check for missing or multiple H1 tags',\n severity: 'critical',\n run: (page) => checkH1(page),\n },\n {\n id: 'heading-hierarchy',\n name: 'Heading Hierarchy',\n description: 'Check for skipped heading levels',\n severity: 'warning',\n run: (page) => checkHeadingHierarchy(page),\n },\n\n // Images\n {\n id: 'image-alt',\n name: 'Image Alt Text',\n description: 'Check for images missing alt attributes',\n severity: 'warning',\n run: (page) => checkImageAlt(page),\n },\n\n // Links\n {\n id: 'internal-links',\n name: 'Internal Links',\n description: 'Check for broken internal links',\n severity: 'critical',\n run: (page, allPages, basePath) => checkInternalLinks(page, allPages, basePath),\n },\n\n // Schema\n {\n id: 'schema',\n name: 'Structured Data',\n description: 'Check JSON-LD structured data for validity',\n severity: 'warning',\n run: (page) => [...checkSchemaJsonValidity(page), ...checkSchema(page)],\n },\n {\n id: 'schema-speakable',\n name: 'Speakable Schema (AI/Voice)',\n description: 'Check for speakable schema for voice search and AI discoverability',\n severity: 'info',\n run: (page) => checkSpeakableSchema(page),\n },\n {\n id: 'schema-offers',\n name: 'Offer/Pricing Schema',\n description: 'Check Product/Service schemas for proper pricing markup',\n severity: 'warning',\n run: (page) => checkOfferSchema(page),\n },\n {\n id: 'schema-faq',\n name: 'FAQ Schema',\n description: 'Check for FAQ schema on pages with Q&A content',\n severity: 'info',\n run: (page) => checkFAQSchema(page),\n },\n {\n id: 'schema-howto',\n name: 'HowTo Schema',\n description: 'Check for HowTo schema on tutorial/guide pages',\n severity: 'info',\n run: (page) => checkHowToSchema(page),\n },\n\n // Social / Open Graph\n {\n id: 'open-graph',\n name: 'Open Graph Tags',\n description: 'Check for Open Graph meta tags for social sharing',\n severity: 'warning',\n run: (page) => checkOpenGraph(page),\n },\n {\n id: 'twitter-cards',\n name: 'Twitter Cards',\n description: 'Check for Twitter Card meta tags',\n severity: 'warning',\n run: (page) => checkTwitterCards(page),\n },\n {\n id: 'robots-meta',\n name: 'Robots Meta',\n description: 'Check for robots meta tag issues',\n severity: 'warning',\n run: (page) => checkRobotsMeta(page),\n },\n\n // Accessibility\n {\n id: 'accessibility',\n name: 'Accessibility',\n description: 'Check for common accessibility issues (WCAG)',\n severity: 'warning',\n run: (page) => checkAccessibility(page),\n },\n {\n id: 'color-contrast',\n name: 'Color Contrast',\n description: 'Check for potential color contrast issues',\n severity: 'info',\n run: (page) => checkColorContrast(page),\n },\n {\n id: 'focus-indicators',\n name: 'Focus Indicators',\n description: 'Check for removed focus outlines',\n severity: 'warning',\n run: (page) => checkFocusIndicators(page),\n },\n];\n\n/**\n * Run all enabled checks on a page\n */\nexport function runChecks(\n page: ParsedPage,\n allPages: ParsedPage[],\n basePath: string,\n enabledChecks?: Set<string>\n): CheckResult[] {\n const results: CheckResult[] = [];\n\n for (const check of checks) {\n // Skip if check is disabled\n if (enabledChecks && !enabledChecks.has(check.id)) {\n continue;\n }\n\n const checkResults = check.run(page, allPages, basePath);\n if (checkResults.every((r) => r.passed)) {\n results.push({\n checkId: check.id,\n name: check.name,\n severity: check.severity,\n passed: true,\n file: page.filePath,\n message: `${check.name}: no issues found`,\n });\n }\n results.push(...checkResults);\n }\n\n return results;\n}\n\n/**\n * Get list of all available check IDs\n */\nexport function getAvailableChecks(): string[] {\n return checks.map((c) => c.id);\n}\n","import chalk from 'chalk';\nimport type { CheckReport, CheckResult } from '../types/index.js';\n\n/**\n * Format check results for terminal output\n */\nexport function formatTerminal(report: CheckReport): string {\n const lines: string[] = [];\n\n // Header\n lines.push('');\n lines.push(chalk.bold.cyan(' Rankture SEO Check'));\n lines.push(chalk.gray(' ' + '─'.repeat(40)));\n lines.push('');\n lines.push(chalk.gray(` Checking ${report.path} (${report.summary.totalFiles} files)...`));\n lines.push('');\n\n // Group results by severity\n const critical = report.results.filter((r) => !r.passed && r.severity === 'critical');\n const warnings = report.results.filter((r) => !r.passed && r.severity === 'warning');\n const info = report.results.filter((r) => !r.passed && r.severity === 'info');\n\n // Print critical issues\n if (critical.length > 0) {\n for (const result of critical) {\n lines.push(formatResult(result));\n }\n }\n\n // Print warnings\n if (warnings.length > 0) {\n for (const result of warnings) {\n lines.push(formatResult(result));\n }\n }\n\n // Print info\n if (info.length > 0) {\n for (const result of info) {\n lines.push(formatResult(result));\n }\n }\n\n // Summary\n lines.push('');\n lines.push(chalk.gray(' ' + '─'.repeat(40)));\n \n const summaryParts: string[] = [];\n if (report.summary.critical > 0) {\n summaryParts.push(chalk.red.bold(`${report.summary.critical} critical`));\n }\n if (report.summary.warning > 0) {\n summaryParts.push(chalk.yellow.bold(`${report.summary.warning} warnings`));\n }\n if (report.summary.info > 0) {\n summaryParts.push(chalk.blue(`${report.summary.info} info`));\n }\n \n summaryParts.push(chalk.green(`${report.summary.passed} passed`));\n\n lines.push(` Results: ${summaryParts.join(', ')}`);\n lines.push('');\n\n // Final status\n if (report.summary.critical > 0) {\n lines.push(chalk.red.bold(' ✗ Check failed (critical issues found)'));\n } else if (report.summary.warning > 0) {\n lines.push(chalk.yellow(' ⚠ Check completed with warnings'));\n } else {\n lines.push(chalk.green.bold(' ✓ All checks passed!'));\n }\n lines.push('');\n\n return lines.join('\\n');\n}\n\n/**\n * Format a single check result\n */\nfunction formatResult(result: CheckResult): string {\n const lines: string[] = [];\n \n // Severity icon and color\n let icon: string;\n let color: typeof chalk;\n \n switch (result.severity) {\n case 'critical':\n icon = '✗';\n color = chalk.red;\n break;\n case 'warning':\n icon = '⚠';\n color = chalk.yellow;\n break;\n case 'info':\n default:\n icon = 'ℹ';\n color = chalk.blue;\n break;\n }\n\n // Main line\n lines.push(\n ` ${color(icon)} ${color.bold(result.severity.toUpperCase().padEnd(8))} ${chalk.gray(result.checkId)}`\n );\n \n // File and message\n if (result.file) {\n lines.push(` ${chalk.cyan(result.file)} - ${result.message}`);\n } else {\n lines.push(` ${result.message}`);\n }\n\n // Details (if any)\n if (result.details && result.details.length > 0) {\n const maxDetails = 5;\n const showDetails = result.details.slice(0, maxDetails);\n \n for (const detail of showDetails) {\n lines.push(chalk.gray(` - ${detail}`));\n }\n \n if (result.details.length > maxDetails) {\n lines.push(chalk.gray(` ... and ${result.details.length - maxDetails} more`));\n }\n }\n\n lines.push('');\n return lines.join('\\n');\n}\n\n/**\n * Print report to console\n */\nexport function printReport(report: CheckReport): void {\n console.log(formatTerminal(report));\n}\n","import type { CheckReport } from '../types/index.js';\n\n/**\n * Format check results as JSON\n */\nexport function formatJson(report: CheckReport): string {\n return JSON.stringify(report, null, 2);\n}\n","import type { CheckReport } from '../types/index.js';\n\n/**\n * Generate HTML report from check results\n */\nexport function formatHtml(report: CheckReport): string {\n const { summary, results } = report;\n \n // Group results by file\n const byFile = new Map<string, typeof results>();\n results.forEach(r => {\n const file = r.file || 'Unknown';\n if (!byFile.has(file)) {\n byFile.set(file, []);\n }\n byFile.get(file)!.push(r);\n });\n\n // Calculate score (simple: passed / total * 100)\n const totalChecks = summary.passed + summary.critical + summary.warning + summary.info;\n const score = totalChecks > 0 ? Math.round((summary.passed / totalChecks) * 100) : 100;\n\n // Determine score color\n const scoreColor = score >= 90 ? '#22c55e' : score >= 70 ? '#eab308' : score >= 50 ? '#f97316' : '#ef4444';\n\n const html = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>SEO Audit Report - ${new Date(report.timestamp).toLocaleDateString()}</title>\n <style>\n * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n }\n \n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n background: #f8fafc;\n color: #1e293b;\n line-height: 1.6;\n }\n \n .container {\n max-width: 1200px;\n margin: 0 auto;\n padding: 2rem;\n }\n \n header {\n background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);\n color: white;\n padding: 2rem;\n border-radius: 1rem;\n margin-bottom: 2rem;\n }\n \n header h1 {\n font-size: 1.875rem;\n margin-bottom: 0.5rem;\n }\n \n header p {\n opacity: 0.9;\n font-size: 0.875rem;\n }\n \n .score-ring {\n display: flex;\n align-items: center;\n gap: 2rem;\n margin-top: 1.5rem;\n }\n \n .score-circle {\n width: 120px;\n height: 120px;\n border-radius: 50%;\n background: conic-gradient(${scoreColor} ${score * 3.6}deg, rgba(255,255,255,0.2) 0deg);\n display: flex;\n align-items: center;\n justify-content: center;\n position: relative;\n }\n \n .score-circle::before {\n content: '';\n position: absolute;\n width: 90px;\n height: 90px;\n background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);\n border-radius: 50%;\n }\n \n .score-value {\n position: relative;\n font-size: 2rem;\n font-weight: bold;\n }\n \n .score-stats {\n display: flex;\n gap: 1.5rem;\n }\n \n .stat {\n text-align: center;\n }\n \n .stat-value {\n font-size: 1.5rem;\n font-weight: bold;\n }\n \n .stat-label {\n font-size: 0.75rem;\n opacity: 0.8;\n text-transform: uppercase;\n }\n \n .summary-cards {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 1rem;\n margin-bottom: 2rem;\n }\n \n .card {\n background: white;\n border-radius: 0.75rem;\n padding: 1.5rem;\n box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n }\n \n .card-critical {\n border-left: 4px solid #ef4444;\n }\n \n .card-warning {\n border-left: 4px solid #eab308;\n }\n \n .card-info {\n border-left: 4px solid #3b82f6;\n }\n \n .card-passed {\n border-left: 4px solid #22c55e;\n }\n \n .card h3 {\n font-size: 2rem;\n margin-bottom: 0.25rem;\n }\n \n .card p {\n color: #64748b;\n font-size: 0.875rem;\n }\n \n .section {\n background: white;\n border-radius: 0.75rem;\n padding: 1.5rem;\n margin-bottom: 1.5rem;\n box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n }\n \n .section h2 {\n font-size: 1.25rem;\n margin-bottom: 1rem;\n padding-bottom: 0.75rem;\n border-bottom: 1px solid #e2e8f0;\n }\n \n .file-group {\n margin-bottom: 1.5rem;\n }\n \n .file-group:last-child {\n margin-bottom: 0;\n }\n \n .file-name {\n font-weight: 600;\n color: #475569;\n font-size: 0.875rem;\n margin-bottom: 0.75rem;\n padding: 0.5rem;\n background: #f1f5f9;\n border-radius: 0.375rem;\n font-family: monospace;\n }\n \n .issue {\n display: flex;\n gap: 1rem;\n padding: 1rem;\n border-radius: 0.5rem;\n margin-bottom: 0.5rem;\n background: #fafafa;\n }\n \n .issue:hover {\n background: #f1f5f9;\n }\n \n .issue-severity {\n flex-shrink: 0;\n width: 80px;\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n padding: 0.25rem 0.5rem;\n border-radius: 0.25rem;\n text-align: center;\n height: fit-content;\n }\n \n .severity-critical {\n background: #fef2f2;\n color: #dc2626;\n }\n \n .severity-warning {\n background: #fefce8;\n color: #ca8a04;\n }\n \n .severity-info {\n background: #eff6ff;\n color: #2563eb;\n }\n \n .issue-content {\n flex: 1;\n }\n \n .issue-name {\n font-weight: 600;\n margin-bottom: 0.25rem;\n }\n \n .issue-message {\n color: #64748b;\n font-size: 0.875rem;\n }\n \n .issue-fix {\n margin-top: 0.5rem;\n padding: 0.75rem;\n background: #f0fdf4;\n border-radius: 0.375rem;\n font-size: 0.875rem;\n color: #166534;\n }\n \n .issue-fix strong {\n display: block;\n margin-bottom: 0.25rem;\n }\n \n .issue-details {\n margin-top: 0.5rem;\n font-size: 0.75rem;\n color: #94a3b8;\n }\n \n .issue-details ul {\n margin-left: 1rem;\n margin-top: 0.25rem;\n }\n \n footer {\n text-align: center;\n padding: 2rem;\n color: #94a3b8;\n font-size: 0.875rem;\n }\n \n footer a {\n color: #3b82f6;\n text-decoration: none;\n }\n \n footer a:hover {\n text-decoration: underline;\n }\n \n .no-issues {\n text-align: center;\n padding: 3rem;\n color: #22c55e;\n }\n \n .no-issues svg {\n width: 64px;\n height: 64px;\n margin-bottom: 1rem;\n }\n \n @media (max-width: 640px) {\n .container {\n padding: 1rem;\n }\n \n .score-ring {\n flex-direction: column;\n align-items: flex-start;\n }\n \n .summary-cards {\n grid-template-columns: 1fr 1fr;\n }\n }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <header>\n <h1>🔍 SEO Audit Report</h1>\n <p>Generated on ${new Date(report.timestamp).toLocaleString()} • Path: ${report.path}</p>\n \n <div class=\"score-ring\">\n <div class=\"score-circle\">\n <span class=\"score-value\">${score}</span>\n </div>\n <div class=\"score-stats\">\n <div class=\"stat\">\n <div class=\"stat-value\">${summary.totalFiles}</div>\n <div class=\"stat-label\">Files</div>\n </div>\n <div class=\"stat\">\n <div class=\"stat-value\">${totalChecks}</div>\n <div class=\"stat-label\">Checks</div>\n </div>\n <div class=\"stat\">\n <div class=\"stat-value\">${summary.passed}</div>\n <div class=\"stat-label\">Passed</div>\n </div>\n </div>\n </div>\n </header>\n \n <div class=\"summary-cards\">\n <div class=\"card card-critical\">\n <h3>${summary.critical}</h3>\n <p>Critical Issues</p>\n </div>\n <div class=\"card card-warning\">\n <h3>${summary.warning}</h3>\n <p>Warnings</p>\n </div>\n <div class=\"card card-info\">\n <h3>${summary.info}</h3>\n <p>Info</p>\n </div>\n <div class=\"card card-passed\">\n <h3>${summary.passed}</h3>\n <p>Passed</p>\n </div>\n </div>\n \n ${results.length === 0 ? `\n <div class=\"section\">\n <div class=\"no-issues\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <h2>All Checks Passed!</h2>\n <p>No SEO issues found. Great job!</p>\n </div>\n </div>\n ` : `\n <div class=\"section\">\n <h2>Issues Found</h2>\n ${Array.from(byFile.entries()).map(([file, issues]) => `\n <div class=\"file-group\">\n <div class=\"file-name\">${escapeHtml(file)}</div>\n ${issues.map(issue => `\n <div class=\"issue\">\n <span class=\"issue-severity severity-${issue.severity}\">${issue.severity}</span>\n <div class=\"issue-content\">\n <div class=\"issue-name\">${escapeHtml(issue.name)}</div>\n <div class=\"issue-message\">${escapeHtml(issue.message)}</div>\n ${issue.fix ? `\n <div class=\"issue-fix\">\n <strong>How to fix:</strong>\n ${escapeHtml(issue.fix)}\n </div>\n ` : ''}\n ${issue.details && issue.details.length > 0 ? `\n <div class=\"issue-details\">\n <strong>Affected:</strong>\n <ul>\n ${issue.details.slice(0, 5).map(d => `<li>${escapeHtml(d)}</li>`).join('')}\n ${issue.details.length > 5 ? `<li>...and ${issue.details.length - 5} more</li>` : ''}\n </ul>\n </div>\n ` : ''}\n </div>\n </div>\n `).join('')}\n </div>\n `).join('')}\n </div>\n `}\n \n <footer>\n <p>Generated by <a href=\"https://rankture.com\">Rankture CLI</a> v${report.version}</p>\n <p>For full audit with Core Web Vitals and AI suggestions, visit <a href=\"https://rankture.com/free-seo-audit/\">rankture.com</a></p>\n </footer>\n </div>\n</body>\n</html>`;\n\n return html;\n}\n\n/**\n * Escape HTML special characters\n */\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport chalk from 'chalk';\nimport { XMLParser } from 'fast-xml-parser';\n\nexport interface ValidateResult {\n valid: boolean;\n errors: string[];\n warnings: string[];\n info: string[];\n}\n\n/**\n * Validate a robots.txt file\n */\nexport async function validateRobotsTxt(filePath: string): Promise<ValidateResult> {\n const result: ValidateResult = {\n valid: true,\n errors: [],\n warnings: [],\n info: [],\n };\n\n const absolutePath = path.resolve(filePath);\n\n if (!fs.existsSync(absolutePath)) {\n result.valid = false;\n result.errors.push(`File not found: ${absolutePath}`);\n return result;\n }\n\n const content = fs.readFileSync(absolutePath, 'utf-8');\n const lines = content.split('\\n');\n\n let hasUserAgent = false;\n let hasSitemap = false;\n let currentUserAgent = '';\n let lineNum = 0;\n\n for (const rawLine of lines) {\n lineNum++;\n const line = rawLine.trim();\n\n // Skip empty lines and comments\n if (!line || line.startsWith('#')) {\n continue;\n }\n\n // Check for valid directives\n const colonIndex = line.indexOf(':');\n if (colonIndex === -1) {\n result.warnings.push(`Line ${lineNum}: Invalid format (missing colon): \"${line}\"`);\n continue;\n }\n\n const directive = line.substring(0, colonIndex).trim().toLowerCase();\n const value = line.substring(colonIndex + 1).trim();\n\n switch (directive) {\n case 'user-agent':\n hasUserAgent = true;\n currentUserAgent = value;\n if (!value) {\n result.errors.push(`Line ${lineNum}: User-agent directive has no value`);\n result.valid = false;\n }\n break;\n\n case 'disallow':\n if (!currentUserAgent) {\n result.errors.push(`Line ${lineNum}: Disallow before User-agent directive`);\n result.valid = false;\n }\n // Empty disallow is valid (allows everything)\n if (value && !value.startsWith('/') && value !== '*') {\n result.warnings.push(`Line ${lineNum}: Disallow path should start with /`);\n }\n break;\n\n case 'allow':\n if (!currentUserAgent) {\n result.errors.push(`Line ${lineNum}: Allow before User-agent directive`);\n result.valid = false;\n }\n if (value && !value.startsWith('/') && value !== '*') {\n result.warnings.push(`Line ${lineNum}: Allow path should start with /`);\n }\n break;\n\n case 'sitemap':\n hasSitemap = true;\n if (!value.startsWith('http://') && !value.startsWith('https://')) {\n result.errors.push(`Line ${lineNum}: Sitemap URL must be absolute (start with http:// or https://)`);\n result.valid = false;\n }\n break;\n\n case 'crawl-delay':\n {\n const delay = parseFloat(value);\n if (isNaN(delay) || delay < 0) {\n result.warnings.push(`Line ${lineNum}: Invalid crawl-delay value: \"${value}\"`);\n } else if (delay > 10) {\n result.warnings.push(\n `Line ${lineNum}: Crawl-delay of ${delay}s is very high - may slow indexing`\n );\n }\n break;\n }\n\n case 'host':\n // Yandex directive\n result.info.push(`Line ${lineNum}: Host directive (Yandex-specific)`);\n break;\n\n case 'clean-param':\n // Yandex directive\n result.info.push(`Line ${lineNum}: Clean-param directive (Yandex-specific)`);\n break;\n\n default:\n result.warnings.push(`Line ${lineNum}: Unknown directive: \"${directive}\"`);\n }\n }\n\n // Check for required elements\n if (!hasUserAgent) {\n result.errors.push('Missing User-agent directive (required)');\n result.valid = false;\n }\n\n if (!hasSitemap) {\n result.warnings.push('No Sitemap directive found - recommended to include sitemap URL');\n }\n\n // Check for common issues\n if (content.includes('Disallow: /') && !content.includes('Allow:')) {\n const disallowAll = lines.some(l => {\n const trimmed = l.trim().toLowerCase();\n return trimmed === 'disallow: /' || trimmed === 'disallow:/' ;\n });\n if (disallowAll) {\n result.warnings.push('Found \"Disallow: /\" which blocks all crawling - ensure this is intentional');\n }\n }\n\n // Summary info\n result.info.push(`Total lines: ${lines.length}`);\n result.info.push(`User-agents defined: ${lines.filter(l => l.trim().toLowerCase().startsWith('user-agent')).length}`);\n\n return result;\n}\n\n/**\n * Validate a sitemap.xml file\n */\nexport async function validateSitemap(filePath: string): Promise<ValidateResult> {\n const result: ValidateResult = {\n valid: true,\n errors: [],\n warnings: [],\n info: [],\n };\n\n const absolutePath = path.resolve(filePath);\n\n if (!fs.existsSync(absolutePath)) {\n result.valid = false;\n result.errors.push(`File not found: ${absolutePath}`);\n return result;\n }\n\n const content = fs.readFileSync(absolutePath, 'utf-8');\n\n // Check XML declaration\n if (!content.trim().startsWith('<?xml')) {\n result.warnings.push('Missing XML declaration (<?xml version=\"1.0\" encoding=\"UTF-8\"?>)');\n }\n\n // Parse XML\n const parser = new XMLParser({\n ignoreAttributes: false,\n attributeNamePrefix: '@_',\n });\n\n // fast-xml-parser produces a loosely-typed object; keep it permissive here.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let parsed: any;\n try {\n parsed = parser.parse(content);\n } catch (error) {\n result.valid = false;\n result.errors.push(`Invalid XML: ${error}`);\n return result;\n }\n\n // Check for sitemap index vs urlset\n const isSitemapIndex = !!parsed.sitemapindex;\n const isUrlset = !!parsed.urlset;\n\n if (!isSitemapIndex && !isUrlset) {\n result.valid = false;\n result.errors.push('Missing root element: expected <urlset> or <sitemapindex>');\n return result;\n }\n\n if (isSitemapIndex) {\n // Validate sitemap index\n const sitemaps = parsed.sitemapindex.sitemap;\n const sitemapArray = Array.isArray(sitemaps) ? sitemaps : sitemaps ? [sitemaps] : [];\n\n result.info.push(`Sitemap index with ${sitemapArray.length} child sitemap(s)`);\n\n for (let i = 0; i < sitemapArray.length; i++) {\n const sitemap = sitemapArray[i];\n if (!sitemap.loc) {\n result.errors.push(`Sitemap ${i + 1}: Missing <loc> element (required)`);\n result.valid = false;\n } else if (!sitemap.loc.startsWith('http')) {\n result.errors.push(`Sitemap ${i + 1}: <loc> must be absolute URL`);\n result.valid = false;\n }\n }\n } else {\n // Validate urlset\n const urls = parsed.urlset.url;\n const urlArray = Array.isArray(urls) ? urls : urls ? [urls] : [];\n\n result.info.push(`Sitemap with ${urlArray.length} URL(s)`);\n\n if (urlArray.length === 0) {\n result.warnings.push('Sitemap is empty (no URLs)');\n }\n\n if (urlArray.length > 50000) {\n result.errors.push(`Sitemap has ${urlArray.length} URLs - maximum allowed is 50,000`);\n result.valid = false;\n }\n\n // Check file size (uncompressed max is 50MB)\n const fileSize = Buffer.byteLength(content, 'utf-8');\n const fileSizeMB = fileSize / (1024 * 1024);\n if (fileSizeMB > 50) {\n result.errors.push(`Sitemap is ${fileSizeMB.toFixed(1)}MB - maximum allowed is 50MB`);\n result.valid = false;\n }\n\n // Validate individual URLs\n const priorities = new Set<string>();\n const changefreqs = new Set<string>();\n let urlsWithoutLoc = 0;\n let urlsWithRelativeLoc = 0;\n let urlsWithLastmod = 0;\n let urlsWithPriority = 0;\n let urlsWithChangefreq = 0;\n\n const validChangefreqs = ['always', 'hourly', 'daily', 'weekly', 'monthly', 'yearly', 'never'];\n const seenUrls = new Set<string>();\n const duplicateUrls: string[] = [];\n\n for (let i = 0; i < Math.min(urlArray.length, 1000); i++) { // Check first 1000 URLs\n const url = urlArray[i];\n\n if (!url.loc) {\n urlsWithoutLoc++;\n } else {\n // Check for duplicates\n if (seenUrls.has(url.loc)) {\n duplicateUrls.push(url.loc);\n }\n seenUrls.add(url.loc);\n\n if (!url.loc.startsWith('http')) {\n urlsWithRelativeLoc++;\n }\n }\n\n if (url.lastmod) {\n urlsWithLastmod++;\n // Validate date format\n const datePattern = /^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}([+-]\\d{2}:\\d{2}|Z)?)?$/;\n if (!datePattern.test(url.lastmod)) {\n result.warnings.push(`URL ${i + 1}: Invalid lastmod date format: \"${url.lastmod}\"`);\n }\n }\n\n if (url.priority !== undefined) {\n urlsWithPriority++;\n priorities.add(String(url.priority));\n const priority = parseFloat(url.priority);\n if (isNaN(priority) || priority < 0 || priority > 1) {\n result.warnings.push(`URL ${i + 1}: Invalid priority value: \"${url.priority}\" (must be 0.0-1.0)`);\n }\n }\n\n if (url.changefreq) {\n urlsWithChangefreq++;\n changefreqs.add(url.changefreq);\n if (!validChangefreqs.includes(url.changefreq.toLowerCase())) {\n result.warnings.push(`URL ${i + 1}: Invalid changefreq: \"${url.changefreq}\"`);\n }\n }\n }\n\n // Report issues\n if (urlsWithoutLoc > 0) {\n result.errors.push(`${urlsWithoutLoc} URL(s) missing required <loc> element`);\n result.valid = false;\n }\n\n if (urlsWithRelativeLoc > 0) {\n result.errors.push(`${urlsWithRelativeLoc} URL(s) have relative URLs - must be absolute`);\n result.valid = false;\n }\n\n if (duplicateUrls.length > 0) {\n result.warnings.push(`${duplicateUrls.length} duplicate URL(s) found`);\n if (duplicateUrls.length <= 5) {\n duplicateUrls.forEach(url => result.warnings.push(` Duplicate: ${url}`));\n }\n }\n\n // Info about optional elements\n if (urlsWithLastmod === 0) {\n result.info.push('No lastmod dates - consider adding for better crawling');\n } else {\n result.info.push(`${urlsWithLastmod} URL(s) have lastmod dates`);\n }\n\n if (priorities.size === 1) {\n result.info.push(`All URLs have same priority (${[...priorities][0]}) - consider varying for important pages`);\n }\n\n // Note: priority and changefreq are largely ignored by Google now\n if (urlsWithPriority > 0 || urlsWithChangefreq > 0) {\n result.info.push('Note: Google largely ignores priority and changefreq - focus on lastmod instead');\n }\n }\n\n return result;\n}\n\n/**\n * Print validation results\n */\nexport function printValidationResult(type: string, filePath: string, result: ValidateResult): void {\n console.log('');\n console.log(chalk.bold(` ${type.toUpperCase()} Validation: ${filePath}`));\n console.log(' ' + '─'.repeat(50));\n\n if (result.valid) {\n console.log(chalk.green(' ✓ Valid'));\n } else {\n console.log(chalk.red(' ✗ Invalid'));\n }\n\n if (result.errors.length > 0) {\n console.log('');\n console.log(chalk.red(' Errors:'));\n result.errors.forEach(e => console.log(chalk.red(` • ${e}`)));\n }\n\n if (result.warnings.length > 0) {\n console.log('');\n console.log(chalk.yellow(' Warnings:'));\n result.warnings.forEach(w => console.log(chalk.yellow(` • ${w}`)));\n }\n\n if (result.info.length > 0) {\n console.log('');\n console.log(chalk.blue(' Info:'));\n result.info.forEach(i => console.log(chalk.blue(` • ${i}`)));\n }\n\n console.log('');\n}\n"],"mappings":"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","names":["fs","path","cheerio","runChecks","fs","path","chalk","fs"]}
|
package/dist/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/checks/meta-tags.ts","../src/checks/headings.ts","../src/checks/images.ts","../src/checks/links.ts","../src/checks/schema.ts","../src/checks/social.ts","../src/checks/accessibility.ts","../src/checks/index.ts","../src/parsers/html.ts","../src/lib/config.ts","../src/reporters/terminal.ts","../src/reporters/json.ts","../src/reporters/html.ts","../src/commands/validate.ts","../src/index.ts"],"sourcesContent":["import type { ParsedPage, CheckResult } from '../types/index.js';\n\n/**\n * Check for missing or problematic title tags\n */\nexport function checkMetaTitle(page: ParsedPage, allPages: ParsedPage[]): CheckResult[] {\n const results: CheckResult[] = [];\n\n // Check for missing title\n if (!page.title) {\n results.push({\n checkId: 'meta-title-missing',\n name: 'Missing Title Tag',\n severity: 'critical',\n passed: false,\n file: page.filePath,\n message: 'Page has no <title> tag',\n fix: 'Add a unique, descriptive <title> tag in the <head> section',\n });\n return results; // No point checking length if missing\n }\n\n // Check title length\n const titleLength = page.title.length;\n if (titleLength < 30) {\n results.push({\n checkId: 'meta-title-length',\n name: 'Title Too Short',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `Title is too short (${titleLength} chars, recommended 30-60)`,\n fix: 'Expand your title to be more descriptive (30-60 characters)',\n });\n } else if (titleLength > 60) {\n results.push({\n checkId: 'meta-title-length',\n name: 'Title Too Long',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `Title is too long (${titleLength} chars, recommended 30-60)`,\n fix: 'Shorten your title to under 60 characters to prevent truncation in search results',\n });\n }\n\n // Check for duplicate titles\n const duplicates = allPages.filter(\n (p) => p.filePath !== page.filePath && p.title === page.title\n );\n if (duplicates.length > 0) {\n results.push({\n checkId: 'meta-title-duplicate',\n name: 'Duplicate Title',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `Title is duplicated on ${duplicates.length} other page(s)`,\n fix: 'Each page should have a unique title',\n details: duplicates.map((p) => p.filePath),\n });\n }\n\n return results;\n}\n\n/**\n * Check for missing or problematic meta descriptions\n */\nexport function checkMetaDescription(page: ParsedPage, allPages: ParsedPage[]): CheckResult[] {\n const results: CheckResult[] = [];\n\n // Check for missing description\n if (!page.metaDescription) {\n results.push({\n checkId: 'meta-description-missing',\n name: 'Missing Meta Description',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Page has no meta description',\n fix: 'Add a <meta name=\"description\" content=\"...\"> tag in the <head> section',\n });\n return results;\n }\n\n // Check description length\n const descLength = page.metaDescription.length;\n if (descLength < 120) {\n results.push({\n checkId: 'meta-description-length',\n name: 'Meta Description Too Short',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `Meta description is too short (${descLength} chars, recommended 120-160)`,\n fix: 'Expand your meta description to be more descriptive (120-160 characters)',\n });\n } else if (descLength > 160) {\n results.push({\n checkId: 'meta-description-length',\n name: 'Meta Description Too Long',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `Meta description is too long (${descLength} chars, recommended 120-160)`,\n fix: 'Shorten your meta description to under 160 characters to prevent truncation',\n });\n }\n\n // Check for duplicate descriptions\n const duplicates = allPages.filter(\n (p) => p.filePath !== page.filePath && p.metaDescription === page.metaDescription\n );\n if (duplicates.length > 0) {\n results.push({\n checkId: 'meta-description-duplicate',\n name: 'Duplicate Meta Description',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `Meta description is duplicated on ${duplicates.length} other page(s)`,\n fix: 'Each page should have a unique meta description',\n details: duplicates.map((p) => p.filePath),\n });\n }\n\n return results;\n}\n\n/**\n * Check for missing viewport meta tag\n * Note: Skipped for source files since viewport is typically in layouts\n */\nexport function checkViewport(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n\n // Skip for source files - viewport is typically in layout files\n if (page.isSourceFile) {\n return results;\n }\n\n if (!page.viewport) {\n results.push({\n checkId: 'viewport-missing',\n name: 'Missing Viewport Meta Tag',\n severity: 'critical',\n passed: false,\n file: page.filePath,\n message: 'Page has no viewport meta tag',\n fix: 'Add <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"> in the <head>',\n });\n }\n\n return results;\n}\n\n/**\n * Check for missing lang attribute\n * Note: Skipped for source files since lang is typically in layouts\n */\nexport function checkLang(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n\n // Skip for source files - lang is typically on the root <html> in layouts\n if (page.isSourceFile) {\n return results;\n }\n\n if (!page.lang) {\n results.push({\n checkId: 'lang-missing',\n name: 'Missing Language Attribute',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Page has no lang attribute on <html> tag',\n fix: 'Add lang=\"en\" (or appropriate language code) to the <html> tag',\n });\n }\n\n return results;\n}\n\n/**\n * Check for canonical URL issues\n * Note: Skipped for source files since canonical is typically set dynamically\n */\nexport function checkCanonical(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n\n // Skip for source files - canonical is typically set in layouts or dynamically\n if (page.isSourceFile) {\n return results;\n }\n\n if (!page.canonical) {\n results.push({\n checkId: 'canonical-missing',\n name: 'Missing Canonical URL',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Page has no canonical URL defined',\n fix: 'Add <link rel=\"canonical\" href=\"...\"> in the <head> section',\n });\n }\n\n return results;\n}\n","import type { ParsedPage, CheckResult } from '../types/index.js';\n\n/**\n * Check for missing or multiple H1 tags\n */\nexport function checkH1(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n\n if (page.h1s.length === 0) {\n results.push({\n checkId: 'h1-missing',\n name: 'Missing H1 Tag',\n severity: 'critical',\n passed: false,\n file: page.filePath,\n message: 'Page has no H1 tag',\n fix: 'Add a single H1 tag that describes the main content of the page',\n });\n } else if (page.h1s.length > 1) {\n results.push({\n checkId: 'h1-multiple',\n name: 'Multiple H1 Tags',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `Page has ${page.h1s.length} H1 tags (should have exactly 1)`,\n fix: 'Use only one H1 tag per page. Use H2-H6 for subheadings.',\n details: page.h1s,\n });\n }\n\n return results;\n}\n\n/**\n * Check heading hierarchy (no skipped levels)\n */\nexport function checkHeadingHierarchy(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n \n if (page.headings.length === 0) {\n return results; // No headings to check\n }\n\n let prevLevel = 0;\n const skippedLevels: string[] = [];\n\n for (const heading of page.headings) {\n // Allow going from 0 to any level (first heading)\n // Allow going to same level or lower (sibling or parent)\n // Allow going to next level (child)\n // Don't allow skipping levels (e.g., H1 -> H3)\n if (prevLevel > 0 && heading.level > prevLevel + 1) {\n skippedLevels.push(`H${prevLevel} → H${heading.level} (\"${heading.text.substring(0, 30)}...\")`);\n }\n prevLevel = heading.level;\n }\n\n if (skippedLevels.length > 0) {\n results.push({\n checkId: 'heading-hierarchy',\n name: 'Skipped Heading Levels',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `Heading hierarchy skips levels in ${skippedLevels.length} place(s)`,\n fix: 'Use headings in order (H1 → H2 → H3). Don\\'t skip levels.',\n details: skippedLevels,\n });\n }\n\n return results;\n}\n","import type { ParsedPage, CheckResult } from '../types/index.js';\n\n/**\n * Check for images missing alt text\n */\nexport function checkImageAlt(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n\n // Find images with no alt attribute at all\n const missingAlt = page.images.filter((img) => img.alt === undefined);\n \n if (missingAlt.length > 0) {\n results.push({\n checkId: 'image-alt-missing',\n name: 'Images Missing Alt Text',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `${missingAlt.length} image(s) missing alt attribute`,\n fix: 'Add descriptive alt text to all images for accessibility and SEO',\n details: missingAlt.map((img) => img.src),\n });\n }\n\n // Find images with empty alt (this is okay for decorative images, just info)\n const emptyAlt = page.images.filter((img) => img.alt === '');\n \n if (emptyAlt.length > 0) {\n results.push({\n checkId: 'image-alt-empty',\n name: 'Images With Empty Alt Text',\n severity: 'info',\n passed: true, // Empty alt is valid for decorative images\n file: page.filePath,\n message: `${emptyAlt.length} image(s) have empty alt=\"\" (okay for decorative images)`,\n details: emptyAlt.map((img) => img.src),\n });\n }\n\n return results;\n}\n","import * as path from 'path';\nimport * as fs from 'fs';\nimport type { ParsedPage, CheckResult } from '../types/index.js';\n\n/**\n * Check for broken internal links (links to files that don't exist)\n */\nexport function checkInternalLinks(\n page: ParsedPage,\n allPages: ParsedPage[],\n basePath: string\n): CheckResult[] {\n const results: CheckResult[] = [];\n const brokenLinks: string[] = [];\n\n // Get all file paths that exist\n const existingPaths = new Set(\n allPages.map((p) => {\n // Normalize to relative path from base\n const rel = path.relative(basePath, p.filePath);\n // Convert to URL-like path\n return '/' + rel.replace(/\\\\/g, '/').replace(/index\\.html$/, '').replace(/\\.html$/, '');\n })\n );\n\n // Also add the raw file paths\n allPages.forEach((p) => {\n const rel = path.relative(basePath, p.filePath);\n existingPaths.add('/' + rel.replace(/\\\\/g, '/'));\n });\n\n for (const link of page.internalLinks) {\n let href = link.href;\n\n // Skip anchors, empty, or special links\n if (!href || href.startsWith('#') || href.startsWith('javascript:')) {\n continue;\n }\n\n // Handle relative links\n if (!href.startsWith('/')) {\n const pageDir = path.dirname(page.filePath);\n const absolutePath = path.resolve(pageDir, href);\n href = '/' + path.relative(basePath, absolutePath).replace(/\\\\/g, '/');\n }\n\n // Normalize the href\n const normalizedHref = href\n .split('#')[0] // Remove anchor\n .split('?')[0] // Remove query string\n .replace(/\\/$/, ''); // Remove trailing slash\n\n // Check if the target exists\n const targetExists =\n existingPaths.has(normalizedHref) ||\n existingPaths.has(normalizedHref + '/') ||\n existingPaths.has(normalizedHref + '/index.html') ||\n existingPaths.has(normalizedHref + '.html') ||\n // Check if actual file exists (for non-HTML assets)\n fs.existsSync(path.join(basePath, normalizedHref));\n\n if (!targetExists && normalizedHref !== '' && normalizedHref !== '/') {\n brokenLinks.push(link.href);\n }\n }\n\n if (brokenLinks.length > 0) {\n results.push({\n checkId: 'link-broken-internal',\n name: 'Broken Internal Links',\n severity: 'critical',\n passed: false,\n file: page.filePath,\n message: `${brokenLinks.length} internal link(s) point to non-existent pages`,\n fix: 'Fix or remove links to pages that don\\'t exist',\n details: [...new Set(brokenLinks)], // Dedupe\n });\n }\n\n // Check for empty hrefs\n const emptyLinks = page.internalLinks.filter(\n (link) => !link.href || link.href === '#'\n );\n\n if (emptyLinks.length > 0) {\n results.push({\n checkId: 'link-empty-href',\n name: 'Empty Link Href',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `${emptyLinks.length} link(s) have empty or \"#\" href`,\n fix: 'Add proper href values to all links or use buttons for non-navigation actions',\n });\n }\n\n return results;\n}\n","import type { ParsedPage, CheckResult } from '../types/index.js';\n\n// Type for JSON-LD schema objects\ntype JsonLdSchema = Record<string, unknown>;\n\n/**\n * Check JSON-LD structured data for validity\n */\nexport function checkSchema(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n\n // Check if JSON-LD was parseable\n // Note: Invalid JSON is already filtered out in the parser,\n // but we can check for common issues in valid JSON\n\n for (const schema of page.jsonLd as JsonLdSchema[]) {\n // Check for missing @context\n if (!('@context' in schema)) {\n results.push({\n checkId: 'schema-missing-context',\n name: 'Schema Missing @context',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'JSON-LD is missing @context property',\n fix: 'Add \"@context\": \"https://schema.org\" to your JSON-LD',\n });\n }\n\n // Check for missing @type\n if (!('@type' in schema)) {\n results.push({\n checkId: 'schema-missing-type',\n name: 'Schema Missing @type',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'JSON-LD is missing @type property',\n fix: 'Add \"@type\": \"YourSchemaType\" to your JSON-LD',\n });\n }\n }\n\n return results;\n}\n\n/**\n * Validate JSON-LD syntax by attempting to find invalid scripts\n * This runs on the raw HTML to catch JSON parse errors\n */\nexport function checkSchemaJsonValidity(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n\n // Use regex to find JSON-LD scripts\n const jsonLdRegex = /<script[^>]*type=[\"']application\\/ld\\+json[\"'][^>]*>([\\s\\S]*?)<\\/script>/gi;\n let match;\n let index = 0;\n\n while ((match = jsonLdRegex.exec(page.html)) !== null) {\n index++;\n const content = match[1].trim();\n \n if (!content) {\n results.push({\n checkId: 'schema-empty',\n name: 'Empty JSON-LD Script',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `JSON-LD script #${index} is empty`,\n fix: 'Add valid JSON-LD content or remove the empty script tag',\n });\n continue;\n }\n\n try {\n JSON.parse(content);\n } catch (error) {\n results.push({\n checkId: 'schema-invalid-json',\n name: 'Invalid JSON-LD Syntax',\n severity: 'critical',\n passed: false,\n file: page.filePath,\n message: `JSON-LD script #${index} has invalid JSON syntax`,\n fix: 'Fix the JSON syntax error in your structured data',\n details: [error instanceof Error ? error.message : 'Unknown error'],\n });\n }\n }\n\n return results;\n}\n\n/**\n * Check for Speakable schema (important for voice search and AI discoverability)\n */\nexport function checkSpeakableSchema(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n const schemas = page.jsonLd as JsonLdSchema[];\n \n // Look for speakable in any schema\n const hasSpeakable = schemas.some(schema => {\n if ('speakable' in schema) return true;\n // Check nested schemas (like WebPage with speakable)\n if (typeof schema === 'object') {\n return JSON.stringify(schema).includes('\"speakable\"');\n }\n return false;\n });\n\n // Check if this is a content page that should have speakable\n const isContentPage = schemas.some(schema => {\n const type = schema['@type'];\n return ['Article', 'NewsArticle', 'BlogPosting', 'WebPage', 'FAQPage', 'Product', 'Service'].includes(type as string);\n });\n\n if (isContentPage && !hasSpeakable) {\n results.push({\n checkId: 'schema-speakable-missing',\n name: 'Speakable Schema Missing',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Content page lacks speakable schema for voice search/AI optimization',\n fix: 'Add speakable specification to help voice assistants and AI find key content:\\n' +\n ' \"speakable\": {\\n' +\n ' \"@type\": \"SpeakableSpecification\",\\n' +\n ' \"cssSelector\": [\"h1\", \".main-content\", \".key-points\"]\\n' +\n ' }',\n });\n }\n\n // Validate speakable structure if present\n for (const schema of schemas) {\n if ('speakable' in schema) {\n const speakable = schema.speakable as JsonLdSchema;\n \n if (!speakable['@type'] || speakable['@type'] !== 'SpeakableSpecification') {\n results.push({\n checkId: 'schema-speakable-invalid-type',\n name: 'Invalid Speakable Type',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Speakable schema has incorrect or missing @type',\n fix: 'Set \"@type\": \"SpeakableSpecification\" in the speakable object',\n });\n }\n\n if (!speakable.cssSelector && !speakable.xpath) {\n results.push({\n checkId: 'schema-speakable-no-selector',\n name: 'Speakable Missing Selector',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Speakable schema needs cssSelector or xpath to identify content',\n fix: 'Add \"cssSelector\": [\"h1\", \".content\"] or \"xpath\": [\"/html/body/article\"]',\n });\n }\n }\n }\n\n return results;\n}\n\n/**\n * Check Offer/Pricing schema for e-commerce and SaaS pages\n */\nexport function checkOfferSchema(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n const schemas = page.jsonLd as JsonLdSchema[];\n\n // Check Product/SoftwareApplication schemas for offers\n const productSchemas = schemas.filter(schema => {\n const type = schema['@type'];\n return ['Product', 'SoftwareApplication', 'Service'].includes(type as string);\n });\n\n for (const product of productSchemas) {\n if (!product.offers) {\n results.push({\n checkId: 'schema-product-no-offers',\n name: 'Product Missing Offers',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `${product['@type']} schema is missing offers/pricing information`,\n fix: 'Add \"offers\" property with price, priceCurrency, and availability',\n });\n continue;\n }\n\n // Validate offer structure\n const offersRaw = product.offers;\n const offers = (Array.isArray(offersRaw) ? offersRaw : [offersRaw]) as JsonLdSchema[];\n for (const offer of offers) {\n if (!offer.price && offer.price !== 0) {\n results.push({\n checkId: 'schema-offer-no-price',\n name: 'Offer Missing Price',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Offer schema is missing price property',\n fix: 'Add \"price\": \"29.99\" or \"price\": \"0\" for free items',\n });\n }\n\n if (!offer.priceCurrency) {\n results.push({\n checkId: 'schema-offer-no-currency',\n name: 'Offer Missing Currency',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Offer schema is missing priceCurrency property',\n fix: 'Add \"priceCurrency\": \"USD\" (use ISO 4217 currency code)',\n });\n }\n }\n }\n\n // Check for Sale/Discount schema opportunities\n const hasSaleSchema = schemas.some(schema => schema['@type'] === 'Sale');\n const hasDiscountedOffers = schemas.some(schema => {\n if (schema.offers) {\n const offersRaw = schema.offers;\n const offers = (Array.isArray(offersRaw) ? offersRaw : [offersRaw]) as JsonLdSchema[];\n return offers.some(o => o.priceSpecification || o.discount);\n }\n return false;\n });\n\n // Look for discount indicators in HTML (common patterns)\n const htmlLower = page.html.toLowerCase();\n const hasDiscountContent = /sale|discount|% off|save \\$|was \\$|original price|strike|line-through/i.test(htmlLower);\n\n if (hasDiscountContent && !hasSaleSchema && !hasDiscountedOffers) {\n results.push({\n checkId: 'schema-sale-missing',\n name: 'Sale Schema Recommended',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Page appears to have discounted pricing but no Sale or discount schema',\n fix: 'Add Sale schema or priceSpecification with validThrough date:\\n' +\n ' {\\n' +\n ' \"@type\": \"Sale\",\\n' +\n ' \"name\": \"Holiday Sale\",\\n' +\n ' \"description\": \"20% off all plans\",\\n' +\n ' \"validThrough\": \"2025-12-31\"\\n' +\n ' }',\n });\n }\n\n return results;\n}\n\n/**\n * Check for FAQ schema (great for AI/voice search)\n */\nexport function checkFAQSchema(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n const schemas = page.jsonLd as JsonLdSchema[];\n\n const faqSchema = schemas.find(schema => schema['@type'] === 'FAQPage');\n\n // Check if page has FAQ-like content but no schema\n const hasFAQContent = /<(dt|summary|h[2-4])[^>]*>[^<]*(faq|question|q:|q\\.|ask|how|what|why|when|where|who)/i.test(page.html) ||\n /class=[\"'][^\"']*faq/i.test(page.html);\n\n if (hasFAQContent && !faqSchema) {\n results.push({\n checkId: 'schema-faq-missing',\n name: 'FAQ Schema Recommended',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Page has FAQ content but no FAQPage schema',\n fix: 'Add FAQPage schema to get rich results and improve AI discoverability:\\n' +\n ' {\\n' +\n ' \"@type\": \"FAQPage\",\\n' +\n ' \"mainEntity\": [{\\n' +\n ' \"@type\": \"Question\",\\n' +\n ' \"name\": \"Your question?\",\\n' +\n ' \"acceptedAnswer\": {\\n' +\n ' \"@type\": \"Answer\",\\n' +\n ' \"text\": \"Your answer\"\\n' +\n ' }\\n' +\n ' }]\\n' +\n ' }',\n });\n }\n\n // Validate FAQ schema structure\n if (faqSchema) {\n const mainEntity = faqSchema.mainEntity as JsonLdSchema[] | undefined;\n \n if (!mainEntity || !Array.isArray(mainEntity) || mainEntity.length === 0) {\n results.push({\n checkId: 'schema-faq-empty',\n name: 'FAQ Schema Empty',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'FAQPage schema has no questions in mainEntity',\n fix: 'Add Question/Answer pairs to the mainEntity array',\n });\n } else {\n // Validate each question\n for (let i = 0; i < mainEntity.length; i++) {\n const qa = mainEntity[i];\n \n if (qa['@type'] !== 'Question') {\n results.push({\n checkId: 'schema-faq-invalid-question',\n name: 'FAQ Invalid Question Type',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `FAQ item ${i + 1} is not a Question type`,\n fix: 'Set \"@type\": \"Question\" for each FAQ item',\n });\n }\n\n if (!qa.name) {\n results.push({\n checkId: 'schema-faq-no-question-text',\n name: 'FAQ Missing Question Text',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `FAQ Question ${i + 1} is missing the question text (name property)`,\n fix: 'Add \"name\": \"Your question?\" to each Question',\n });\n }\n\n const answer = qa.acceptedAnswer as JsonLdSchema | undefined;\n if (!answer || !answer.text) {\n results.push({\n checkId: 'schema-faq-no-answer',\n name: 'FAQ Missing Answer',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `FAQ Question ${i + 1} is missing an answer`,\n fix: 'Add acceptedAnswer with @type \"Answer\" and \"text\" property',\n });\n }\n }\n }\n }\n\n return results;\n}\n\n/**\n * Check for HowTo schema (great for AI featured snippets)\n */\nexport function checkHowToSchema(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n const schemas = page.jsonLd as JsonLdSchema[];\n\n const howToSchema = schemas.find(schema => schema['@type'] === 'HowTo');\n\n // Check if page has how-to content but no schema\n const hasHowToContent = /how to|step[s]? [0-9]|guide:|tutorial|instruction/i.test(page.html) &&\n /<(ol|ul)[^>]*class=[\"'][^\"']*step/i.test(page.html);\n\n if (hasHowToContent && !howToSchema) {\n results.push({\n checkId: 'schema-howto-missing',\n name: 'HowTo Schema Recommended',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Page has step-by-step content but no HowTo schema',\n fix: 'Add HowTo schema for rich results:\\n' +\n ' {\\n' +\n ' \"@type\": \"HowTo\",\\n' +\n ' \"name\": \"How to ...\",\\n' +\n ' \"step\": [{\\n' +\n ' \"@type\": \"HowToStep\",\\n' +\n ' \"name\": \"Step 1\",\\n' +\n ' \"text\": \"Description...\"\\n' +\n ' }]\\n' +\n ' }',\n });\n }\n\n return results;\n}\n","import type { ParsedPage, CheckResult } from '../types/index.js';\n\n/**\n * Check for Open Graph meta tags\n */\nexport function checkOpenGraph(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n\n // Skip source files - OG tags are usually in layouts\n if (page.isSourceFile) {\n return results;\n }\n\n const og = page.ogTags;\n\n // Check og:title\n if (!og['og:title']) {\n results.push({\n checkId: 'og-title-missing',\n name: 'Missing og:title',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Page is missing og:title meta tag',\n fix: 'Add <meta property=\"og:title\" content=\"Your Page Title\" /> for better social sharing',\n });\n }\n\n // Check og:description\n if (!og['og:description']) {\n results.push({\n checkId: 'og-description-missing',\n name: 'Missing og:description',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Page is missing og:description meta tag',\n fix: 'Add <meta property=\"og:description\" content=\"Your description\" /> for better social sharing',\n });\n }\n\n // Check og:image\n if (!og['og:image']) {\n results.push({\n checkId: 'og-image-missing',\n name: 'Missing og:image',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Page is missing og:image meta tag - shared links will have no preview image',\n fix: 'Add <meta property=\"og:image\" content=\"https://example.com/image.jpg\" /> (use absolute URL, min 1200x630px recommended)',\n });\n } else {\n // Check if og:image is absolute URL\n const ogImage = og['og:image'];\n if (!ogImage.startsWith('http://') && !ogImage.startsWith('https://')) {\n results.push({\n checkId: 'og-image-relative',\n name: 'Relative og:image URL',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'og:image should use an absolute URL',\n fix: 'Change to absolute URL: https://yourdomain.com/path/to/image.jpg',\n });\n }\n }\n\n // Check og:type\n if (!og['og:type']) {\n results.push({\n checkId: 'og-type-missing',\n name: 'Missing og:type',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Page is missing og:type meta tag (defaults to \"website\")',\n fix: 'Add <meta property=\"og:type\" content=\"website\" /> or \"article\" for blog posts',\n });\n }\n\n // Check og:url\n if (!og['og:url']) {\n results.push({\n checkId: 'og-url-missing',\n name: 'Missing og:url',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Page is missing og:url meta tag',\n fix: 'Add <meta property=\"og:url\" content=\"https://example.com/page\" /> with the canonical URL',\n });\n }\n\n return results;\n}\n\n/**\n * Check for Twitter Card meta tags\n */\nexport function checkTwitterCards(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n\n // Skip source files - Twitter tags are usually in layouts\n if (page.isSourceFile) {\n return results;\n }\n\n const twitter = page.twitterTags;\n const og = page.ogTags;\n\n // Check twitter:card\n if (!twitter['twitter:card']) {\n results.push({\n checkId: 'twitter-card-missing',\n name: 'Missing twitter:card',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Page is missing twitter:card meta tag',\n fix: 'Add <meta name=\"twitter:card\" content=\"summary_large_image\" /> for large preview, or \"summary\" for small',\n });\n } else {\n // Validate card type\n const validTypes = ['summary', 'summary_large_image', 'app', 'player'];\n if (!validTypes.includes(twitter['twitter:card'])) {\n results.push({\n checkId: 'twitter-card-invalid',\n name: 'Invalid twitter:card value',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `Invalid twitter:card value: \"${twitter['twitter:card']}\"`,\n fix: `Use one of: ${validTypes.join(', ')}`,\n });\n }\n }\n\n // Check twitter:title (falls back to og:title)\n if (!twitter['twitter:title'] && !og['og:title']) {\n results.push({\n checkId: 'twitter-title-missing',\n name: 'Missing twitter:title',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Page has no twitter:title or og:title to fall back on',\n fix: 'Add <meta name=\"twitter:title\" content=\"Your Title\" /> or og:title',\n });\n }\n\n // Check twitter:description (falls back to og:description)\n if (!twitter['twitter:description'] && !og['og:description']) {\n results.push({\n checkId: 'twitter-description-missing',\n name: 'Missing twitter:description',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Page has no twitter:description or og:description to fall back on',\n fix: 'Add <meta name=\"twitter:description\" content=\"Your description\" /> or og:description',\n });\n }\n\n // Check twitter:image (falls back to og:image)\n if (!twitter['twitter:image'] && !og['og:image']) {\n results.push({\n checkId: 'twitter-image-missing',\n name: 'Missing twitter:image',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Page has no twitter:image or og:image to fall back on',\n fix: 'Add <meta name=\"twitter:image\" content=\"https://example.com/image.jpg\" /> or og:image',\n });\n }\n\n return results;\n}\n\n/**\n * Check for robots meta issues\n */\nexport function checkRobotsMeta(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n\n // Skip source files\n if (page.isSourceFile) {\n return results;\n }\n\n if (page.robots) {\n const robotsLower = page.robots.toLowerCase();\n\n // Check if page is blocking indexing\n if (robotsLower.includes('noindex')) {\n results.push({\n checkId: 'robots-noindex',\n name: 'Page blocked from indexing',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Page has \"noindex\" in robots meta tag - it will not appear in search results',\n fix: 'Remove noindex if you want this page to be indexed, or ignore if intentional',\n });\n }\n\n // Check if page is blocking following\n if (robotsLower.includes('nofollow')) {\n results.push({\n checkId: 'robots-nofollow',\n name: 'Links blocked from following',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Page has \"nofollow\" in robots meta tag - links will not pass PageRank',\n fix: 'Remove nofollow unless intentional (e.g., user-generated content pages)',\n });\n }\n\n // Check for conflicting directives\n if (robotsLower.includes('noindex') && robotsLower.includes('index')) {\n results.push({\n checkId: 'robots-conflicting',\n name: 'Conflicting robots directives',\n severity: 'critical',\n passed: false,\n file: page.filePath,\n message: 'Page has both \"index\" and \"noindex\" directives - this is confusing for crawlers',\n fix: 'Use either \"index\" or \"noindex\", not both',\n });\n }\n }\n\n return results;\n}\n","import type { ParsedPage, CheckResult } from '../types/index.js';\nimport * as cheerio from 'cheerio';\nimport type { Element } from 'domhandler';\n\n/**\n * Check for ARIA and accessibility issues\n */\nexport function checkAccessibility(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n const $ = cheerio.load(page.html);\n\n // Check for skip link\n const skipLink = $('a[href=\"#main\"], a[href=\"#content\"], a[href=\"#main-content\"], .skip-link, .skip-to-content');\n if (skipLink.length === 0) {\n results.push({\n checkId: 'a11y-skip-link',\n name: 'Missing Skip Link',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Page has no skip navigation link for keyboard users',\n fix: 'Add a skip link as the first focusable element: <a href=\"#main\" class=\"sr-only focus:not-sr-only\">Skip to content</a>',\n });\n }\n\n // Check for main landmark\n const mainLandmark = $('main, [role=\"main\"]');\n if (mainLandmark.length === 0) {\n results.push({\n checkId: 'a11y-main-landmark',\n name: 'Missing Main Landmark',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: 'Page has no <main> element or role=\"main\"',\n fix: 'Wrap your main content in a <main> element for screen reader navigation',\n });\n } else if (mainLandmark.length > 1) {\n results.push({\n checkId: 'a11y-multiple-main',\n name: 'Multiple Main Landmarks',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `Page has ${mainLandmark.length} main landmarks - there should only be one`,\n fix: 'Ensure only one <main> element exists per page',\n });\n }\n\n // Check for nav landmark\n const navLandmark = $('nav, [role=\"navigation\"]');\n if (navLandmark.length === 0) {\n results.push({\n checkId: 'a11y-nav-landmark',\n name: 'Missing Nav Landmark',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: 'Page has no <nav> element for navigation',\n fix: 'Wrap your navigation in a <nav> element',\n });\n }\n\n // Check for buttons without accessible names\n const buttonsWithoutText: string[] = [];\n $('button').each((_, el) => {\n const $btn = $(el);\n const text = $btn.text().trim();\n const ariaLabel = $btn.attr('aria-label');\n const ariaLabelledby = $btn.attr('aria-labelledby');\n const title = $btn.attr('title');\n \n if (!text && !ariaLabel && !ariaLabelledby && !title) {\n // Try to identify the button\n const className = $btn.attr('class') || '';\n const id = $btn.attr('id') || '';\n buttonsWithoutText.push(className || id || 'unnamed button');\n }\n });\n \n if (buttonsWithoutText.length > 0) {\n results.push({\n checkId: 'a11y-button-name',\n name: 'Buttons Without Accessible Name',\n severity: 'critical',\n passed: false,\n file: page.filePath,\n message: `${buttonsWithoutText.length} button(s) have no accessible name`,\n fix: 'Add text content, aria-label, or aria-labelledby to buttons',\n details: buttonsWithoutText.slice(0, 10),\n });\n }\n\n // Check for links without accessible names\n const linksWithoutText: string[] = [];\n $('a[href]').each((_, el) => {\n const $link = $(el);\n const text = $link.text().trim();\n const ariaLabel = $link.attr('aria-label');\n const ariaLabelledby = $link.attr('aria-labelledby');\n const title = $link.attr('title');\n const hasImg = $link.find('img[alt]').length > 0;\n \n if (!text && !ariaLabel && !ariaLabelledby && !title && !hasImg) {\n const href = $link.attr('href') || '';\n linksWithoutText.push(href.substring(0, 50));\n }\n });\n \n if (linksWithoutText.length > 0) {\n results.push({\n checkId: 'a11y-link-name',\n name: 'Links Without Accessible Name',\n severity: 'critical',\n passed: false,\n file: page.filePath,\n message: `${linksWithoutText.length} link(s) have no accessible name`,\n fix: 'Add text content, aria-label, or an image with alt text to links',\n details: linksWithoutText.slice(0, 10),\n });\n }\n\n // Check for form inputs without labels\n const inputsWithoutLabels: string[] = [];\n $('input:not([type=\"hidden\"]):not([type=\"submit\"]):not([type=\"button\"]):not([type=\"reset\"]), textarea, select').each((_, el) => {\n const $input = $(el);\n const id = $input.attr('id');\n const ariaLabel = $input.attr('aria-label');\n const ariaLabelledby = $input.attr('aria-labelledby');\n const placeholder = $input.attr('placeholder');\n const title = $input.attr('title');\n \n // Check for associated label\n let hasLabel = false;\n if (id) {\n hasLabel = $(`label[for=\"${id}\"]`).length > 0;\n }\n \n // Check if wrapped in label\n if (!hasLabel) {\n hasLabel = $input.closest('label').length > 0;\n }\n \n if (!hasLabel && !ariaLabel && !ariaLabelledby && !title) {\n const name = $input.attr('name') || $input.attr('id') || 'unnamed';\n const type = $input.attr('type') || 'text';\n inputsWithoutLabels.push(`${type}: ${name}${placeholder ? ` (placeholder: ${placeholder})` : ''}`);\n }\n });\n \n if (inputsWithoutLabels.length > 0) {\n results.push({\n checkId: 'a11y-input-label',\n name: 'Form Inputs Without Labels',\n severity: 'critical',\n passed: false,\n file: page.filePath,\n message: `${inputsWithoutLabels.length} form input(s) have no associated label`,\n fix: 'Add <label for=\"inputId\"> or wrap inputs in <label> elements. Placeholder is not a substitute for labels.',\n details: inputsWithoutLabels.slice(0, 10),\n });\n }\n\n // Check for tabindex > 0 (anti-pattern)\n const positiveTabindex: string[] = [];\n $('[tabindex]').each((_, el) => {\n const tabindex = parseInt($(el).attr('tabindex') || '0', 10);\n if (tabindex > 0) {\n const tagName = (el as Element).tagName;\n positiveTabindex.push(`${tagName} (tabindex=${tabindex})`);\n }\n });\n \n if (positiveTabindex.length > 0) {\n results.push({\n checkId: 'a11y-tabindex-positive',\n name: 'Positive Tabindex Values',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `${positiveTabindex.length} element(s) have tabindex > 0, which disrupts natural tab order`,\n fix: 'Use tabindex=\"0\" to add to natural tab order, or tabindex=\"-1\" to make focusable via JS only',\n details: positiveTabindex.slice(0, 10),\n });\n }\n\n // Check for autoplay videos without muted\n const autoplayVideos: string[] = [];\n $('video[autoplay]').each((_, el) => {\n const $video = $(el);\n if (!$video.attr('muted')) {\n const src = $video.attr('src') || $video.find('source').first().attr('src') || 'unknown';\n autoplayVideos.push(src.substring(0, 50));\n }\n });\n \n if (autoplayVideos.length > 0) {\n results.push({\n checkId: 'a11y-autoplay-audio',\n name: 'Autoplay Video With Audio',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `${autoplayVideos.length} video(s) autoplay without being muted`,\n fix: 'Add the muted attribute to autoplay videos: <video autoplay muted>',\n details: autoplayVideos,\n });\n }\n\n // Check for empty table headers\n const emptyTableHeaders: number[] = [];\n $('th').each((index, el) => {\n const text = $(el).text().trim();\n if (!text) {\n emptyTableHeaders.push(index + 1);\n }\n });\n \n if (emptyTableHeaders.length > 0) {\n results.push({\n checkId: 'a11y-empty-th',\n name: 'Empty Table Headers',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `${emptyTableHeaders.length} table header(s) are empty`,\n fix: 'Add descriptive text to all <th> elements, or use scope attribute',\n });\n }\n\n // Check for document language (already in meta-tags.ts but important for a11y)\n // This is a duplicate check but important enough to surface in accessibility context\n\n return results;\n}\n\n/**\n * Check color contrast (basic check - looks for common anti-patterns)\n */\nexport function checkColorContrast(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n const $ = cheerio.load(page.html);\n\n // Look for inline styles with potentially low contrast colors\n const potentialIssues: string[] = [];\n \n $('[style*=\"color\"]').each((_, el) => {\n const style = $(el).attr('style') || '';\n \n // Check for light gray text (common accessibility issue)\n const colorMatch = style.match(/color:\\s*(#[a-fA-F0-9]{3,6}|rgb[a]?\\([^)]+\\)|[a-z]+)/i);\n if (colorMatch) {\n const color = colorMatch[1].toLowerCase();\n // Flag very light colors\n if (color.match(/^#[c-f][c-f][c-f]$/i) || // Light hex shorthand\n color.match(/^#[c-f]{2}[c-f]{2}[c-f]{2}$/i) || // Light hex\n color === 'lightgray' || color === 'lightgrey' ||\n color === 'silver' || color === 'gainsboro') {\n potentialIssues.push(`Light text color: ${color}`);\n }\n }\n });\n\n if (potentialIssues.length > 0) {\n results.push({\n checkId: 'a11y-color-contrast',\n name: 'Potential Color Contrast Issues',\n severity: 'info',\n passed: false,\n file: page.filePath,\n message: `${potentialIssues.length} element(s) may have low color contrast`,\n fix: 'Ensure text has at least 4.5:1 contrast ratio (3:1 for large text). Use a contrast checker tool.',\n details: potentialIssues.slice(0, 5),\n });\n }\n\n return results;\n}\n\n/**\n * Check for focus visibility issues\n */\nexport function checkFocusIndicators(page: ParsedPage): CheckResult[] {\n const results: CheckResult[] = [];\n const $ = cheerio.load(page.html);\n\n // Look for outline:none or outline:0 in inline styles\n const outlineNone: string[] = [];\n $('[style*=\"outline\"]').each((_, el) => {\n const style = $(el).attr('style') || '';\n if (style.match(/outline:\\s*(none|0)/i)) {\n const tagName = (el as Element).tagName;\n outlineNone.push(tagName);\n }\n });\n\n if (outlineNone.length > 0) {\n results.push({\n checkId: 'a11y-focus-outline',\n name: 'Focus Outline Removed',\n severity: 'warning',\n passed: false,\n file: page.filePath,\n message: `${outlineNone.length} element(s) have outline:none which may hide focus indicators`,\n fix: 'Provide custom focus styles instead of removing outlines: :focus { outline: 2px solid blue; }',\n details: outlineNone,\n });\n }\n\n return results;\n}\n","import type { ParsedPage, CheckResult } from '../types/index.js';\nimport {\n checkMetaTitle,\n checkMetaDescription,\n checkViewport,\n checkLang,\n checkCanonical,\n} from './meta-tags.js';\nimport { checkH1, checkHeadingHierarchy } from './headings.js';\nimport { checkImageAlt } from './images.js';\nimport { checkInternalLinks } from './links.js';\nimport { \n checkSchema, \n checkSchemaJsonValidity,\n checkSpeakableSchema,\n checkOfferSchema,\n checkFAQSchema,\n checkHowToSchema,\n} from './schema.js';\nimport { checkOpenGraph, checkTwitterCards, checkRobotsMeta } from './social.js';\nimport { checkAccessibility, checkColorContrast, checkFocusIndicators } from './accessibility.js';\n\nexport interface CheckRegistry {\n id: string;\n name: string;\n description: string;\n severity: 'critical' | 'warning' | 'info';\n run: (page: ParsedPage, allPages: ParsedPage[], basePath: string) => CheckResult[];\n}\n\n/**\n * All available checks\n */\nexport const checks: CheckRegistry[] = [\n // Meta tags\n {\n id: 'meta-title',\n name: 'Title Tag',\n description: 'Check for missing, short, long, or duplicate title tags',\n severity: 'critical',\n run: (page, allPages) => checkMetaTitle(page, allPages),\n },\n {\n id: 'meta-description',\n name: 'Meta Description',\n description: 'Check for missing, short, long, or duplicate meta descriptions',\n severity: 'warning',\n run: (page, allPages) => checkMetaDescription(page, allPages),\n },\n {\n id: 'viewport',\n name: 'Viewport Meta Tag',\n description: 'Check for missing viewport meta tag',\n severity: 'critical',\n run: (page) => checkViewport(page),\n },\n {\n id: 'lang',\n name: 'Language Attribute',\n description: 'Check for missing lang attribute on html tag',\n severity: 'warning',\n run: (page) => checkLang(page),\n },\n {\n id: 'canonical',\n name: 'Canonical URL',\n description: 'Check for missing canonical URL',\n severity: 'warning',\n run: (page) => checkCanonical(page),\n },\n\n // Headings\n {\n id: 'h1',\n name: 'H1 Tag',\n description: 'Check for missing or multiple H1 tags',\n severity: 'critical',\n run: (page) => checkH1(page),\n },\n {\n id: 'heading-hierarchy',\n name: 'Heading Hierarchy',\n description: 'Check for skipped heading levels',\n severity: 'warning',\n run: (page) => checkHeadingHierarchy(page),\n },\n\n // Images\n {\n id: 'image-alt',\n name: 'Image Alt Text',\n description: 'Check for images missing alt attributes',\n severity: 'warning',\n run: (page) => checkImageAlt(page),\n },\n\n // Links\n {\n id: 'internal-links',\n name: 'Internal Links',\n description: 'Check for broken internal links',\n severity: 'critical',\n run: (page, allPages, basePath) => checkInternalLinks(page, allPages, basePath),\n },\n\n // Schema\n {\n id: 'schema',\n name: 'Structured Data',\n description: 'Check JSON-LD structured data for validity',\n severity: 'warning',\n run: (page) => [...checkSchemaJsonValidity(page), ...checkSchema(page)],\n },\n {\n id: 'schema-speakable',\n name: 'Speakable Schema (AI/Voice)',\n description: 'Check for speakable schema for voice search and AI discoverability',\n severity: 'info',\n run: (page) => checkSpeakableSchema(page),\n },\n {\n id: 'schema-offers',\n name: 'Offer/Pricing Schema',\n description: 'Check Product/Service schemas for proper pricing markup',\n severity: 'warning',\n run: (page) => checkOfferSchema(page),\n },\n {\n id: 'schema-faq',\n name: 'FAQ Schema',\n description: 'Check for FAQ schema on pages with Q&A content',\n severity: 'info',\n run: (page) => checkFAQSchema(page),\n },\n {\n id: 'schema-howto',\n name: 'HowTo Schema',\n description: 'Check for HowTo schema on tutorial/guide pages',\n severity: 'info',\n run: (page) => checkHowToSchema(page),\n },\n\n // Social / Open Graph\n {\n id: 'open-graph',\n name: 'Open Graph Tags',\n description: 'Check for Open Graph meta tags for social sharing',\n severity: 'warning',\n run: (page) => checkOpenGraph(page),\n },\n {\n id: 'twitter-cards',\n name: 'Twitter Cards',\n description: 'Check for Twitter Card meta tags',\n severity: 'warning',\n run: (page) => checkTwitterCards(page),\n },\n {\n id: 'robots-meta',\n name: 'Robots Meta',\n description: 'Check for robots meta tag issues',\n severity: 'warning',\n run: (page) => checkRobotsMeta(page),\n },\n\n // Accessibility\n {\n id: 'accessibility',\n name: 'Accessibility',\n description: 'Check for common accessibility issues (WCAG)',\n severity: 'warning',\n run: (page) => checkAccessibility(page),\n },\n {\n id: 'color-contrast',\n name: 'Color Contrast',\n description: 'Check for potential color contrast issues',\n severity: 'info',\n run: (page) => checkColorContrast(page),\n },\n {\n id: 'focus-indicators',\n name: 'Focus Indicators',\n description: 'Check for removed focus outlines',\n severity: 'warning',\n run: (page) => checkFocusIndicators(page),\n },\n];\n\n/**\n * Run all enabled checks on a page\n */\nexport function runChecks(\n page: ParsedPage,\n allPages: ParsedPage[],\n basePath: string,\n enabledChecks?: Set<string>\n): CheckResult[] {\n const results: CheckResult[] = [];\n\n for (const check of checks) {\n // Skip if check is disabled\n if (enabledChecks && !enabledChecks.has(check.id)) {\n continue;\n }\n\n const checkResults = check.run(page, allPages, basePath);\n if (checkResults.every((r) => r.passed)) {\n results.push({\n checkId: check.id,\n name: check.name,\n severity: check.severity,\n passed: true,\n file: page.filePath,\n message: `${check.name}: no issues found`,\n });\n }\n results.push(...checkResults);\n }\n\n return results;\n}\n\n/**\n * Get list of all available check IDs\n */\nexport function getAvailableChecks(): string[] {\n return checks.map((c) => c.id);\n}\n","import * as cheerio from 'cheerio';\nimport type { ParsedPage } from '../types/index.js';\nimport type { Element } from 'domhandler';\n\n/**\n * Supported file extensions by category\n */\nexport const SUPPORTED_EXTENSIONS = {\n // Built HTML output\n html: ['.html', '.htm'],\n // Source files that can contain HTML-like content\n source: [\n '.astro', // Astro\n '.jsx', '.tsx', // React/Next.js\n '.vue', // Vue/Nuxt\n '.svelte', // Svelte/SvelteKit\n '.md', '.mdx', // Markdown\n '.njk', // Nunjucks\n '.ejs', // EJS\n '.hbs', // Handlebars\n '.pug', // Pug/Jade\n '.liquid', // Liquid (Shopify, 11ty)\n ],\n};\n\n/**\n * Parse an HTML file and extract SEO-relevant data\n */\nexport function parseHtml(filePath: string, html: string): ParsedPage {\n const $ = cheerio.load(html);\n\n // Extract title\n const title = $('title').first().text().trim() || undefined;\n\n // Extract meta description\n const metaDescription =\n $('meta[name=\"description\"]').attr('content')?.trim() || undefined;\n\n // Extract canonical\n const canonical = $('link[rel=\"canonical\"]').attr('href')?.trim() || undefined;\n\n // Extract viewport\n const viewport = $('meta[name=\"viewport\"]').attr('content')?.trim() || undefined;\n\n // Extract lang\n const lang = $('html').attr('lang')?.trim() || undefined;\n\n // Extract H1s\n const h1s: string[] = [];\n $('h1').each((_, el) => {\n const text = $(el).text().trim();\n if (text) h1s.push(text);\n });\n\n // Extract all headings in order\n const headings: { level: number; text: string }[] = [];\n $('h1, h2, h3, h4, h5, h6').each((_, el) => {\n const tagName = (el as Element).tagName.toLowerCase();\n const level = parseInt(tagName.replace('h', ''), 10);\n const text = $(el).text().trim();\n if (text) headings.push({ level, text });\n });\n\n // Extract images\n const images: { src: string; alt?: string }[] = [];\n $('img').each((_, el) => {\n const src = $(el).attr('src') || '';\n const alt = $(el).attr('alt');\n images.push({ src, alt: alt !== undefined ? alt : undefined });\n });\n\n // Extract links\n const internalLinks: { href: string; text: string }[] = [];\n const externalLinks: { href: string; text: string }[] = [];\n \n $('a[href]').each((_, el) => {\n const href = $(el).attr('href') || '';\n const text = $(el).text().trim();\n \n // Skip javascript:, mailto:, tel:; keep empty and \"#\" hrefs so the\n // link-empty-href check can flag them (the broken-link check skips them)\n if (href.startsWith('javascript:') || href.startsWith('mailto:') || href.startsWith('tel:')) {\n return;\n }\n\n // Determine if internal or external\n if (href.startsWith('http://') || href.startsWith('https://') || href.startsWith('//')) {\n externalLinks.push({ href, text });\n } else {\n internalLinks.push({ href, text });\n }\n });\n\n // Extract JSON-LD\n const jsonLd: object[] = [];\n $('script[type=\"application/ld+json\"]').each((_, el) => {\n try {\n const content = $(el).html();\n if (content) {\n const parsed = JSON.parse(content);\n jsonLd.push(parsed);\n }\n } catch {\n // Invalid JSON-LD, will be caught by schema check\n }\n });\n\n // Extract Open Graph tags\n const ogTags: Record<string, string> = {};\n $('meta[property^=\"og:\"]').each((_, el) => {\n const property = $(el).attr('property');\n const content = $(el).attr('content');\n if (property && content) {\n ogTags[property] = content;\n }\n });\n\n // Extract Twitter Card tags\n const twitterTags: Record<string, string> = {};\n $('meta[name^=\"twitter:\"], meta[property^=\"twitter:\"]').each((_, el) => {\n const name = $(el).attr('name') || $(el).attr('property');\n const content = $(el).attr('content');\n if (name && content) {\n twitterTags[name] = content;\n }\n });\n\n // Extract robots meta\n const robots = $('meta[name=\"robots\"]').attr('content')?.trim() || undefined;\n\n return {\n filePath,\n html,\n title,\n metaDescription,\n canonical,\n viewport,\n lang,\n h1s,\n headings,\n images,\n internalLinks,\n externalLinks,\n jsonLd,\n ogTags,\n twitterTags,\n robots,\n isSourceFile: false, // This is a built HTML file\n };\n}\n\n/**\n * Parse source files (JSX, TSX, Astro, Vue, Svelte, MD, MDX, Nunjucks, EJS, etc.)\n * Extracts HTML-like content for SEO checking\n */\nexport function parseSourceFile(filePath: string, content: string): ParsedPage {\n const ext = filePath.toLowerCase().split('.').pop() || '';\n \n let htmlContent = content;\n \n switch (ext) {\n case 'astro':\n htmlContent = parseAstroFile(content);\n break;\n \n case 'vue':\n htmlContent = parseVueFile(content);\n break;\n \n case 'svelte':\n htmlContent = parseSvelteFile(content);\n break;\n \n case 'md':\n case 'mdx':\n htmlContent = parseMarkdownFile(content);\n break;\n \n case 'jsx':\n case 'tsx':\n htmlContent = extractJsxContent(content);\n break;\n \n case 'njk':\n htmlContent = parseNunjucksFile(content);\n break;\n \n case 'ejs':\n htmlContent = parseEjsFile(content);\n break;\n \n case 'hbs':\n htmlContent = parseHandlebarsFile(content);\n break;\n \n case 'pug':\n htmlContent = parsePugFile(content);\n break;\n \n case 'liquid':\n htmlContent = parseLiquidFile(content);\n break;\n \n default:\n // Try generic extraction\n htmlContent = content;\n }\n\n // Now parse the extracted HTML-like content\n return parseHtmlLikeContent(filePath, content, htmlContent);\n}\n\n/**\n * Parse Astro files - extract template after frontmatter\n */\nfunction parseAstroFile(content: string): string {\n // Astro files have frontmatter between --- markers\n const frontmatterMatch = content.match(/^---[\\s\\S]*?---\\n?([\\s\\S]*)$/);\n let htmlContent = frontmatterMatch ? frontmatterMatch[1] : content;\n \n // Normalize Image and Link components\n htmlContent = normalizeImageComponents(htmlContent);\n htmlContent = normalizeLinkComponents(htmlContent);\n \n return htmlContent;\n}\n\n/**\n * Parse Vue SFC files - extract template and handle script setup\n */\nfunction parseVueFile(content: string): string {\n let htmlContent = '';\n \n // Extract <template> section\n const templateMatch = content.match(/<template[^>]*>([\\s\\S]*?)<\\/template>/i);\n if (templateMatch) {\n htmlContent = templateMatch[1];\n }\n \n // Handle <script setup> - extract defineProps for meta info\n // Vue 3 Composition API with <script setup>\n const scriptSetupMatch = content.match(/<script\\s+setup[^>]*>([\\s\\S]*?)<\\/script>/i);\n if (scriptSetupMatch) {\n // Look for useSeoMeta or useHead from @unhead/vue or nuxt\n const seoMetaMatch = scriptSetupMatch[1].match(/useSeoMeta\\s*\\(\\s*{([^}]+)}/);\n if (seoMetaMatch) {\n // Extract title and description from useSeoMeta\n const titleMatch = seoMetaMatch[1].match(/title:\\s*['\"`]([^'\"`]+)['\"`]/);\n const descMatch = seoMetaMatch[1].match(/description:\\s*['\"`]([^'\"`]+)['\"`]/);\n if (titleMatch) {\n htmlContent = `<title>${titleMatch[1]}</title>` + htmlContent;\n }\n if (descMatch) {\n htmlContent = `<meta name=\"description\" content=\"${descMatch[1]}\">` + htmlContent;\n }\n }\n \n // Look for useHead\n const useHeadMatch = scriptSetupMatch[1].match(/useHead\\s*\\(\\s*{([^}]+)}/);\n if (useHeadMatch) {\n const titleMatch = useHeadMatch[1].match(/title:\\s*['\"`]([^'\"`]+)['\"`]/);\n if (titleMatch) {\n htmlContent = `<title>${titleMatch[1]}</title>` + htmlContent;\n }\n }\n }\n \n // Handle Nuxt-specific patterns\n // definePageMeta for Nuxt 3\n const pageMetaMatch = content.match(/definePageMeta\\s*\\(\\s*{([^}]+)}/);\n if (pageMetaMatch) {\n const titleMatch = pageMetaMatch[1].match(/title:\\s*['\"`]([^'\"`]+)['\"`]/);\n if (titleMatch) {\n htmlContent = `<title>${titleMatch[1]}</title>` + htmlContent;\n }\n }\n \n // Normalize Image and Link components (NuxtImg, NuxtLink)\n htmlContent = normalizeImageComponents(htmlContent);\n htmlContent = normalizeLinkComponents(htmlContent);\n \n // Handle NuxtImg specifically\n htmlContent = htmlContent.replace(\n /<NuxtImg\\s+([^>]*?)\\s*\\/>/gi,\n (match, attrs) => `<img ${attrs}>`\n );\n htmlContent = htmlContent.replace(\n /<NuxtImg\\s+([^>]*?)>([\\s\\S]*?)<\\/NuxtImg>/gi,\n (match, attrs) => `<img ${attrs}>`\n );\n \n return htmlContent;\n}\n\n/**\n * Parse Svelte files - handle SvelteKit patterns\n */\nfunction parseSvelteFile(content: string): string {\n // Remove script and style sections\n let htmlContent = content\n .replace(/<script[^>]*>[\\s\\S]*?<\\/script>/gi, '')\n .replace(/<style[^>]*>[\\s\\S]*?<\\/style>/gi, '');\n \n // Handle SvelteKit's <svelte:head> for SEO\n const headMatch = content.match(/<svelte:head[^>]*>([\\s\\S]*?)<\\/svelte:head>/i);\n if (headMatch) {\n // Prepend head content so title/meta are parsed\n htmlContent = headMatch[1] + htmlContent;\n }\n \n // Look for SvelteKit load function metadata\n const scriptMatch = content.match(/<script[^>]*>([\\s\\S]*?)<\\/script>/i);\n if (scriptMatch) {\n // Check for export const prerender, ssr, etc.\n // Also check for page data pattern\n scriptMatch[1].match(/export\\s+const\\s+\\w+\\s*=\\s*{([^}]+)}/g);\n // This is a simplified check - SvelteKit uses +page.ts for metadata\n }\n \n // Normalize Image and Link components\n htmlContent = normalizeImageComponents(htmlContent);\n htmlContent = normalizeLinkComponents(htmlContent);\n \n // Remove Svelte-specific syntax that might confuse cheerio\n htmlContent = htmlContent\n .replace(/{#if\\s+[^}]+}/g, '')\n .replace(/{:else\\s*(?:if\\s+[^}]+)?}/g, '')\n .replace(/{\\/if}/g, '')\n .replace(/{#each\\s+[^}]+}/g, '')\n .replace(/{\\/each}/g, '')\n .replace(/{#await\\s+[^}]+}/g, '')\n .replace(/{:then\\s*[^}]*}/g, '')\n .replace(/{:catch\\s*[^}]*}/g, '')\n .replace(/{\\/await}/g, '')\n .replace(/{@html\\s+[^}]+}/g, '')\n .replace(/{@const\\s+[^}]+}/g, '');\n \n return htmlContent;\n}\n\n/**\n * Parse Markdown/MDX files\n */\nfunction parseMarkdownFile(content: string): string {\n // Extract frontmatter\n const frontmatterMatch = content.match(/^---[\\s\\S]*?---\\n?([\\s\\S]*)$/);\n let htmlContent = frontmatterMatch ? frontmatterMatch[1] : content;\n \n // Convert markdown to HTML-like structure\n htmlContent = convertMarkdownHeadings(htmlContent);\n htmlContent = convertMarkdownImages(htmlContent);\n htmlContent = convertMarkdownLinks(htmlContent);\n \n return htmlContent;\n}\n\n/**\n * Parse Nunjucks (.njk) files\n */\nfunction parseNunjucksFile(content: string): string {\n let htmlContent = content;\n \n // Remove Nunjucks block tags but keep content\n htmlContent = htmlContent\n .replace(/{%\\s*block\\s+\\w+\\s*%}/g, '')\n .replace(/{%\\s*endblock\\s*%}/g, '')\n .replace(/{%\\s*extends\\s+['\"][^'\"]+['\"]\\s*%}/g, '')\n .replace(/{%\\s*include\\s+['\"][^'\"]+['\"]\\s*%}/g, '')\n .replace(/{%\\s*import\\s+['\"][^'\"]+['\"].*?%}/g, '')\n .replace(/{%\\s*from\\s+['\"][^'\"]+['\"].*?%}/g, '');\n \n // Keep if/for/set blocks content\n htmlContent = htmlContent\n .replace(/{%\\s*if\\s+.*?%}/g, '')\n .replace(/{%\\s*elif\\s+.*?%}/g, '')\n .replace(/{%\\s*else\\s*%}/g, '')\n .replace(/{%\\s*endif\\s*%}/g, '')\n .replace(/{%\\s*for\\s+.*?%}/g, '')\n .replace(/{%\\s*endfor\\s*%}/g, '')\n .replace(/{%\\s*set\\s+.*?%}/g, '');\n \n // Convert Nunjucks variables to markers\n htmlContent = htmlContent.replace(/{{\\s*([^}]+)\\s*}}/g, '[dynamic: $1]');\n \n return htmlContent;\n}\n\n/**\n * Parse EJS (.ejs) files\n */\nfunction parseEjsFile(content: string): string {\n let htmlContent = content;\n \n // Remove EJS scriptlets but keep HTML\n htmlContent = htmlContent\n .replace(/<%[-_]?\\s*[\\s\\S]*?[-_]?%>/g, '') // Remove <% ... %>\n .replace(/<%[-_]?=\\s*([^%]+)[-_]?%>/g, '[dynamic: $1]'); // Convert <%= ... %> to marker\n \n return htmlContent;\n}\n\n/**\n * Parse Handlebars (.hbs) files\n */\nfunction parseHandlebarsFile(content: string): string {\n let htmlContent = content;\n \n // Remove Handlebars block helpers but keep content\n htmlContent = htmlContent\n .replace(/{{#\\s*\\w+.*?}}/g, '')\n .replace(/{{\\/\\s*\\w+\\s*}}/g, '')\n .replace(/{{>\\s*[^}]+}}/g, ''); // Remove partials\n \n // Convert Handlebars expressions to markers\n htmlContent = htmlContent.replace(/{{\\s*([^}#/]+)\\s*}}/g, '[dynamic: $1]');\n \n return htmlContent;\n}\n\n/**\n * Parse Pug (.pug) files - basic conversion\n */\nfunction parsePugFile(content: string): string {\n let htmlContent = '';\n const lines = content.split('\\n');\n \n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('//') || trimmed.startsWith('-')) {\n continue;\n }\n \n // Match tag patterns: h1 text, h1.class text, h1#id text, h1(attr=\"val\") text\n const tagMatch = trimmed.match(/^(h[1-6]|p|a|img|title|meta)([.#(][^\\s]*)?\\s*(.*)?$/);\n if (tagMatch) {\n const [, tag, attrs, text] = tagMatch;\n \n if (tag === 'img') {\n // Parse img with attributes\n const srcMatch = (attrs || '').match(/src=['\"]([^'\"]+)['\"]/);\n const altMatch = (attrs || '').match(/alt=['\"]([^'\"]*)['\"]/);\n htmlContent += `<img src=\"${srcMatch?.[1] || ''}\" ${altMatch ? `alt=\"${altMatch[1]}\"` : ''}>\\n`;\n } else if (tag === 'a') {\n const hrefMatch = (attrs || '').match(/href=['\"]([^'\"]+)['\"]/);\n htmlContent += `<a href=\"${hrefMatch?.[1] || ''}\">${text || ''}</a>\\n`;\n } else if (tag === 'title') {\n htmlContent += `<title>${text || ''}</title>\\n`;\n } else if (tag === 'meta') {\n // Pass through meta tags\n htmlContent += `<meta ${attrs?.replace(/[()]/g, '') || ''}>\\n`;\n } else {\n htmlContent += `<${tag}>${text || ''}</${tag}>\\n`;\n }\n }\n }\n \n return htmlContent;\n}\n\n/**\n * Parse Liquid (.liquid) files - Shopify/11ty\n */\nfunction parseLiquidFile(content: string): string {\n let htmlContent = content;\n \n // Remove Liquid tags but keep content\n htmlContent = htmlContent\n .replace(/{%\\s*comment\\s*%}[\\s\\S]*?{%\\s*endcomment\\s*%}/g, '')\n .replace(/{%\\s*schema\\s*%}[\\s\\S]*?{%\\s*endschema\\s*%}/g, '')\n .replace(/{%\\s*style\\s*%}[\\s\\S]*?{%\\s*endstyle\\s*%}/g, '')\n .replace(/{%\\s*javascript\\s*%}[\\s\\S]*?{%\\s*endjavascript\\s*%}/g, '')\n .replace(/{%\\s*capture\\s+\\w+\\s*%}/g, '')\n .replace(/{%\\s*endcapture\\s*%}/g, '')\n .replace(/{%\\s*if\\s+.*?%}/g, '')\n .replace(/{%\\s*elsif\\s+.*?%}/g, '')\n .replace(/{%\\s*else\\s*%}/g, '')\n .replace(/{%\\s*endif\\s*%}/g, '')\n .replace(/{%\\s*for\\s+.*?%}/g, '')\n .replace(/{%\\s*endfor\\s*%}/g, '')\n .replace(/{%\\s*unless\\s+.*?%}/g, '')\n .replace(/{%\\s*endunless\\s*%}/g, '')\n .replace(/{%\\s*assign\\s+.*?%}/g, '')\n .replace(/{%\\s*render\\s+.*?%}/g, '')\n .replace(/{%\\s*include\\s+.*?%}/g, '')\n .replace(/{%\\s*section\\s+.*?%}/g, '');\n \n // Convert Liquid output to markers\n htmlContent = htmlContent.replace(/{{\\s*([^}|]+)(?:\\|[^}]*)?\\s*}}/g, '[dynamic: $1]');\n \n return htmlContent;\n}\n\n/**\n * Convert markdown headings to HTML\n */\nfunction convertMarkdownHeadings(content: string): string {\n return content\n .replace(/^######\\s+(.+)$/gm, '<h6>$1</h6>')\n .replace(/^#####\\s+(.+)$/gm, '<h5>$1</h5>')\n .replace(/^####\\s+(.+)$/gm, '<h4>$1</h4>')\n .replace(/^###\\s+(.+)$/gm, '<h3>$1</h3>')\n .replace(/^##\\s+(.+)$/gm, '<h2>$1</h2>')\n .replace(/^#\\s+(.+)$/gm, '<h1>$1</h1>');\n}\n\n/**\n * Convert markdown images to HTML\n */\nfunction convertMarkdownImages(content: string): string {\n // \n return content.replace(/!\\[([^\\]]*)\\]\\(([^)]+)\\)/g, '<img alt=\"$1\" src=\"$2\">');\n}\n\n/**\n * Convert markdown links to HTML\n */\nfunction convertMarkdownLinks(content: string): string {\n // [text](href)\n return content.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, '<a href=\"$2\">$1</a>');\n}\n\n/**\n * Extract JSX content from JSX/TSX files\n * Improved extraction for complex React/Next.js components\n */\nfunction extractJsxContent(content: string): string {\n let jsxContent = '';\n \n // Remove imports section\n const withoutImports = content.replace(/^import\\s+.*?;?\\s*$/gm, '');\n \n // Find all return statements with JSX (handles multi-line and nested)\n // Use a more robust regex that handles nested parens\n const returnBlocks: string[] = [];\n \n // Pattern 1: return ( ... ) - standard\n const standardReturns = withoutImports.match(/return\\s*\\([\\s\\S]*?\\n\\s*\\);/g);\n if (standardReturns) {\n returnBlocks.push(...standardReturns);\n }\n \n // Pattern 2: return <Component>...</Component> - without parens\n const directReturns = withoutImports.match(/return\\s+<[A-Z][a-zA-Z]*[\\s\\S]*?<\\/[A-Z][a-zA-Z]*>/g);\n if (directReturns) {\n returnBlocks.push(...directReturns);\n }\n \n // Pattern 3: Arrow function returns: => ( ... )\n const arrowReturns = withoutImports.match(/=>\\s*\\([\\s\\S]*?\\n\\s*\\)/g);\n if (arrowReturns) {\n returnBlocks.push(...arrowReturns);\n }\n \n // Pattern 4: Arrow function direct return: => <div>...</div>\n const arrowDirectReturns = withoutImports.match(/=>\\s*<[a-zA-Z][^;]+/g);\n if (arrowDirectReturns) {\n returnBlocks.push(...arrowDirectReturns);\n }\n \n if (returnBlocks.length > 0) {\n jsxContent = returnBlocks.join('\\n');\n } else {\n // Fallback: look for JSX-like content (starts with <)\n jsxContent = withoutImports;\n }\n \n // Extract Next.js Head component content\n const headMatch = content.match(/<Head[^>]*>([\\s\\S]*?)<\\/Head>/gi);\n if (headMatch) {\n jsxContent = headMatch.join('\\n') + jsxContent;\n }\n \n // Extract next/head import pattern: import Head from 'next/head' then <Head>\n // Also handle @next/head\n \n // Look for Next.js metadata export (App Router)\n // Handles: export const metadata = { ... } and export const metadata: Metadata = { ... }\n const metadataMatch = content.match(/export\\s+const\\s+metadata(?:\\s*:\\s*\\w+)?\\s*=\\s*\\{([\\s\\S]*?)\\n\\}/);\n if (metadataMatch) {\n const metaContent = metadataMatch[1];\n const titleMatch = metaContent.match(/title:\\s*['\"`]([^'\"`]+)['\"`]/);\n const descMatch = metaContent.match(/description:\\s*['\"`]([^'\"`]+)['\"`]/);\n if (titleMatch) {\n jsxContent = `<title>${titleMatch[1]}</title>` + jsxContent;\n }\n if (descMatch) {\n jsxContent = `<meta name=\"description\" content=\"${descMatch[1]}\">` + jsxContent;\n }\n }\n \n // Look for generateMetadata function (Next.js App Router dynamic)\n const generateMetadataMatch = content.match(/export\\s+(?:async\\s+)?function\\s+generateMetadata[\\s\\S]*?return\\s*\\{([\\s\\S]*?)\\n\\s*\\}/);\n if (generateMetadataMatch) {\n const metaContent = generateMetadataMatch[1];\n const titleMatch = metaContent.match(/title:\\s*['\"`]([^'\"`]+)['\"`]/);\n const descMatch = metaContent.match(/description:\\s*['\"`]([^'\"`]+)['\"`]/);\n if (titleMatch) {\n jsxContent = `<title>${titleMatch[1]}</title>` + jsxContent;\n }\n if (descMatch) {\n jsxContent = `<meta name=\"description\" content=\"${descMatch[1]}\">` + jsxContent;\n }\n }\n\n // Convert JSX className to class for cheerio\n jsxContent = jsxContent.replace(/className=/g, 'class=');\n \n // Handle self-closing JSX tags that might confuse cheerio\n jsxContent = jsxContent.replace(/<(\\w+)([^>]*)\\s*\\/>/g, '<$1$2></$1>');\n \n // Convert Image component to img for parsing\n jsxContent = normalizeImageComponents(jsxContent);\n \n // Convert Link component to a for parsing\n jsxContent = normalizeLinkComponents(jsxContent);\n \n return jsxContent;\n}\n\n/**\n * Normalize Image components from various frameworks to <img>\n * Handles: Next.js <Image>, Astro <Image>, Gatsby <Img>, etc.\n */\nfunction normalizeImageComponents(content: string): string {\n // Next.js/Astro Image component: <Image src=\"...\" alt=\"...\" />\n // Convert to standard <img> for parsing\n \n // Handle <Image ... /> self-closing\n let normalized = content.replace(\n /<Image\\s+([^>]*?)\\s*\\/>/gi,\n (match, attrs) => {\n return `<img ${attrs}>`;\n }\n );\n \n // Handle <Image ...>...</Image>\n normalized = normalized.replace(\n /<Image\\s+([^>]*?)>([\\s\\S]*?)<\\/Image>/gi,\n (match, attrs, _children) => {\n return `<img ${attrs}>`;\n }\n );\n \n // Gatsby's Img component\n normalized = normalized.replace(\n /<Img\\s+([^>]*?)\\s*\\/>/gi,\n (match, attrs) => {\n return `<img ${attrs}>`;\n }\n );\n \n // Gatsby's StaticImage\n normalized = normalized.replace(\n /<StaticImage\\s+([^>]*?)\\s*\\/>/gi,\n (match, attrs) => {\n return `<img ${attrs}>`;\n }\n );\n \n // Gatsby's GatsbyImage (wrapper component)\n normalized = normalized.replace(\n /<GatsbyImage\\s+([^>]*?)\\s*\\/>/gi,\n (match, attrs) => {\n // GatsbyImage uses 'image' prop instead of 'src', and 'alt' is required\n return `<img ${attrs}>`;\n }\n );\n \n // Handle picture/source patterns - extract img from picture\n const pictureMatch = normalized.match(/<picture[^>]*>[\\s\\S]*?<img\\s+([^>]*?)>[\\s\\S]*?<\\/picture>/gi);\n if (pictureMatch) {\n // Keep the img tags from picture elements\n // They're already captured in the above patterns\n }\n \n return normalized;\n}\n\n/**\n * Normalize Link components from various frameworks to <a>\n * Handles: Next.js <Link>, Gatsby <Link>, React Router <Link>, etc.\n */\nfunction normalizeLinkComponents(content: string): string {\n // Next.js Link: <Link href=\"...\">text</Link>\n let normalized = content.replace(\n /<Link\\s+([^>]*?)>([\\s\\S]*?)<\\/Link>/gi,\n (match, attrs, children) => {\n // Convert 'to' prop to 'href' for React Router compatibility\n const normalizedAttrs = attrs.replace(/\\bto=/g, 'href=');\n return `<a ${normalizedAttrs}>${children}</a>`;\n }\n );\n \n // Self-closing Link (rare but possible)\n normalized = normalized.replace(\n /<Link\\s+([^>]*?)\\s*\\/>/gi,\n (match, attrs) => {\n const normalizedAttrs = attrs.replace(/\\bto=/g, 'href=');\n return `<a ${normalizedAttrs}></a>`;\n }\n );\n \n // Astro client:* directives - remove them\n normalized = normalized.replace(/client:\\w+/g, '');\n \n // Nuxt's NuxtLink\n normalized = normalized.replace(\n /<NuxtLink\\s+([^>]*?)>([\\s\\S]*?)<\\/NuxtLink>/gi,\n (match, attrs, children) => {\n const normalizedAttrs = attrs.replace(/\\bto=/g, 'href=');\n return `<a ${normalizedAttrs}>${children}</a>`;\n }\n );\n \n // SvelteKit's sveltekit:prefetch and similar\n normalized = normalized.replace(/sveltekit:\\w+/g, '');\n normalized = normalized.replace(/data-sveltekit-\\w+=\"[^\"]*\"/g, '');\n \n return normalized;\n}\n\n/**\n * Parse HTML-like content (handles JSX, Astro, Vue templates)\n */\nfunction parseHtmlLikeContent(filePath: string, originalContent: string, htmlContent: string): ParsedPage {\n const $ = cheerio.load(htmlContent, { xml: false });\n\n // Extract H1s (including JSX expressions like {title})\n const h1s: string[] = [];\n $('h1').each((_, el) => {\n let text = $(el).text().trim();\n // Check for dynamic content markers\n const html = $(el).html() || '';\n if (html.includes('{') && html.includes('}')) {\n text = `[dynamic: ${html.replace(/<[^>]+>/g, '').trim()}]`;\n }\n if (text) h1s.push(text);\n });\n\n // Also check for markdown-style H1 in the original content\n const mdH1Match = originalContent.match(/^#\\s+(.+)$/m);\n if (mdH1Match && h1s.length === 0) {\n h1s.push(mdH1Match[1]);\n }\n\n // Extract all headings\n const headings: { level: number; text: string }[] = [];\n $('h1, h2, h3, h4, h5, h6').each((_, el) => {\n const tagName = (el as Element).tagName.toLowerCase();\n const level = parseInt(tagName.replace('h', ''), 10);\n let text = $(el).text().trim();\n const html = $(el).html() || '';\n if (html.includes('{') && html.includes('}')) {\n text = `[dynamic: ${html.replace(/<[^>]+>/g, '').trim()}]`;\n }\n if (text) headings.push({ level, text });\n });\n\n // Extract images (handle both src and dynamic {src})\n const images: { src: string; alt?: string }[] = [];\n $('img').each((_, el) => {\n let src = $(el).attr('src') || '';\n const alt = $(el).attr('alt');\n \n // Handle dynamic src\n if (!src) {\n const srcAttr = $(el).attr(':src') || $(el).attr('v-bind:src'); // Vue\n if (srcAttr) src = `[dynamic: ${srcAttr}]`;\n }\n \n images.push({ src, alt: alt !== undefined ? alt : undefined });\n });\n\n // Also extract Image components (Next.js, Astro)\n $('Image').each((_, el) => {\n const src = $(el).attr('src') || '[dynamic]';\n const alt = $(el).attr('alt');\n images.push({ src, alt: alt !== undefined ? alt : undefined });\n });\n\n // Extract links\n const internalLinks: { href: string; text: string }[] = [];\n const externalLinks: { href: string; text: string }[] = [];\n \n $('a[href], Link[href], Link[to]').each((_, el) => {\n let href = $(el).attr('href') || $(el).attr('to') || '';\n const text = $(el).text().trim();\n \n if (!href || href === '#' || href.startsWith('javascript:') || \n href.startsWith('mailto:') || href.startsWith('tel:')) {\n return;\n }\n\n // Handle dynamic hrefs\n if (href.startsWith('{') || href.includes('${')) {\n href = `[dynamic: ${href}]`;\n }\n\n if (href.startsWith('http://') || href.startsWith('https://') || href.startsWith('//')) {\n externalLinks.push({ href, text });\n } else {\n internalLinks.push({ href, text });\n }\n });\n\n // Try to extract title - first from parsed HTML content\n let title: string | undefined;\n const parsedTitle = $('title').first().text().trim();\n if (parsedTitle) {\n title = parsedTitle;\n }\n \n // Fallback to frontmatter\n if (!title) {\n const titleMatch = originalContent.match(/^title:\\s*[\"']?([^\"'\\n]+)[\"']?/m);\n if (titleMatch) {\n title = titleMatch[1].trim();\n }\n }\n\n // Try to extract description - first from parsed HTML content\n let metaDescription: string | undefined;\n const parsedDesc = $('meta[name=\"description\"]').attr('content')?.trim();\n if (parsedDesc) {\n metaDescription = parsedDesc;\n }\n \n // Fallback to frontmatter\n if (!metaDescription) {\n const descMatch = originalContent.match(/^description:\\s*[\"']?([^\"'\\n]+)[\"']?/m);\n if (descMatch) {\n metaDescription = descMatch[1].trim();\n }\n }\n\n return {\n filePath,\n html: originalContent,\n title,\n metaDescription,\n canonical: undefined,\n viewport: undefined, // Source files usually don't have viewport\n lang: undefined,\n h1s,\n headings,\n images,\n internalLinks,\n externalLinks,\n jsonLd: [],\n ogTags: {},\n twitterTags: {},\n robots: undefined,\n isSourceFile: true, // This is a source file\n };\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport type { RanktureConfig } from '../types/index.js';\n\n/**\n * Config file names to search for (in priority order)\n */\nconst CONFIG_FILES = [\n 'rankture.config.json',\n 'rankture.config.js',\n 'rankture.config.mjs',\n '.rankturerc',\n '.rankturerc.json',\n '.rankturerc.js',\n];\n\n/**\n * Default configuration\n */\nexport const defaultConfig: RanktureConfig = {\n checks: {},\n ignore: [],\n rules: {},\n thresholds: {\n titleLength: { min: 30, max: 60 },\n descriptionLength: { min: 120, max: 160 },\n },\n};\n\n/**\n * Find and load config file from directory\n */\nexport async function loadConfig(basePath: string, configPath?: string): Promise<RanktureConfig> {\n // If explicit config path provided, use that\n if (configPath) {\n const absolutePath = path.resolve(basePath, configPath);\n if (!fs.existsSync(absolutePath)) {\n throw new Error(`Config file not found: ${absolutePath}`);\n }\n return parseConfigFile(absolutePath);\n }\n\n // Search for config file in directory and parent directories\n let currentDir = path.resolve(basePath);\n const root = path.parse(currentDir).root;\n\n while (currentDir !== root) {\n for (const configName of CONFIG_FILES) {\n const configFilePath = path.join(currentDir, configName);\n if (fs.existsSync(configFilePath)) {\n return parseConfigFile(configFilePath);\n }\n }\n \n // Also check package.json for \"rankture\" key\n const packageJsonPath = path.join(currentDir, 'package.json');\n if (fs.existsSync(packageJsonPath)) {\n try {\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));\n if (packageJson.rankture) {\n return mergeConfig(defaultConfig, packageJson.rankture);\n }\n } catch {\n // Invalid JSON, skip\n }\n }\n\n currentDir = path.dirname(currentDir);\n }\n\n // No config found, return defaults\n return defaultConfig;\n}\n\n/**\n * Parse a config file\n */\nasync function parseConfigFile(filePath: string): Promise<RanktureConfig> {\n const ext = path.extname(filePath).toLowerCase();\n\n if (ext === '.js' || ext === '.mjs') {\n // Dynamic import for JS config\n try {\n const config = await import(filePath);\n return mergeConfig(defaultConfig, config.default || config);\n } catch (error) {\n throw new Error(`Failed to load config from ${filePath}: ${error}`);\n }\n } else {\n // JSON config\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n const config = JSON.parse(content);\n return mergeConfig(defaultConfig, config);\n } catch (error) {\n throw new Error(`Failed to parse config from ${filePath}: ${error}`);\n }\n }\n}\n\n/**\n * Merge user config with defaults\n */\nfunction mergeConfig(defaults: RanktureConfig, userConfig: Partial<RanktureConfig>): RanktureConfig {\n return {\n ...defaults,\n ...userConfig,\n checks: { ...defaults.checks, ...userConfig.checks },\n ignore: [...(defaults.ignore || []), ...(userConfig.ignore || [])],\n rules: { ...defaults.rules, ...userConfig.rules },\n thresholds: {\n ...defaults.thresholds,\n ...userConfig.thresholds,\n },\n };\n}\n\n/**\n * Validate config structure\n */\nexport function validateConfig(config: unknown): config is RanktureConfig {\n if (typeof config !== 'object' || config === null) {\n return false;\n }\n\n const c = config as Record<string, unknown>;\n\n // Validate checks (should be object of booleans)\n if (c.checks !== undefined) {\n if (typeof c.checks !== 'object' || c.checks === null) {\n return false;\n }\n }\n\n // Validate ignore (should be array of strings)\n if (c.ignore !== undefined) {\n if (!Array.isArray(c.ignore)) {\n return false;\n }\n if (!c.ignore.every((item: unknown) => typeof item === 'string')) {\n return false;\n }\n }\n\n // Validate rules (should be object of severity levels)\n if (c.rules !== undefined) {\n if (typeof c.rules !== 'object' || c.rules === null) {\n return false;\n }\n const validSeverities = ['critical', 'warning', 'info'];\n for (const value of Object.values(c.rules as Record<string, unknown>)) {\n if (!validSeverities.includes(value as string)) {\n return false;\n }\n }\n }\n\n return true;\n}\n\n/**\n * Get enabled checks from config\n */\nexport function getEnabledChecks(config: RanktureConfig, allChecks: string[]): Set<string> {\n const enabled = new Set<string>();\n\n for (const checkId of allChecks) {\n // Check if explicitly disabled\n if (config.checks?.[checkId] === false) {\n continue;\n }\n enabled.add(checkId);\n }\n\n return enabled;\n}\n","import chalk from 'chalk';\nimport type { CheckReport, CheckResult } from '../types/index.js';\n\n/**\n * Format check results for terminal output\n */\nexport function formatTerminal(report: CheckReport): string {\n const lines: string[] = [];\n\n // Header\n lines.push('');\n lines.push(chalk.bold.cyan(' Rankture SEO Check'));\n lines.push(chalk.gray(' ' + '─'.repeat(40)));\n lines.push('');\n lines.push(chalk.gray(` Checking ${report.path} (${report.summary.totalFiles} files)...`));\n lines.push('');\n\n // Group results by severity\n const critical = report.results.filter((r) => !r.passed && r.severity === 'critical');\n const warnings = report.results.filter((r) => !r.passed && r.severity === 'warning');\n const info = report.results.filter((r) => !r.passed && r.severity === 'info');\n\n // Print critical issues\n if (critical.length > 0) {\n for (const result of critical) {\n lines.push(formatResult(result));\n }\n }\n\n // Print warnings\n if (warnings.length > 0) {\n for (const result of warnings) {\n lines.push(formatResult(result));\n }\n }\n\n // Print info\n if (info.length > 0) {\n for (const result of info) {\n lines.push(formatResult(result));\n }\n }\n\n // Summary\n lines.push('');\n lines.push(chalk.gray(' ' + '─'.repeat(40)));\n \n const summaryParts: string[] = [];\n if (report.summary.critical > 0) {\n summaryParts.push(chalk.red.bold(`${report.summary.critical} critical`));\n }\n if (report.summary.warning > 0) {\n summaryParts.push(chalk.yellow.bold(`${report.summary.warning} warnings`));\n }\n if (report.summary.info > 0) {\n summaryParts.push(chalk.blue(`${report.summary.info} info`));\n }\n \n summaryParts.push(chalk.green(`${report.summary.passed} passed`));\n\n lines.push(` Results: ${summaryParts.join(', ')}`);\n lines.push('');\n\n // Final status\n if (report.summary.critical > 0) {\n lines.push(chalk.red.bold(' ✗ Check failed (critical issues found)'));\n } else if (report.summary.warning > 0) {\n lines.push(chalk.yellow(' ⚠ Check completed with warnings'));\n } else {\n lines.push(chalk.green.bold(' ✓ All checks passed!'));\n }\n lines.push('');\n\n return lines.join('\\n');\n}\n\n/**\n * Format a single check result\n */\nfunction formatResult(result: CheckResult): string {\n const lines: string[] = [];\n \n // Severity icon and color\n let icon: string;\n let color: typeof chalk;\n \n switch (result.severity) {\n case 'critical':\n icon = '✗';\n color = chalk.red;\n break;\n case 'warning':\n icon = '⚠';\n color = chalk.yellow;\n break;\n case 'info':\n default:\n icon = 'ℹ';\n color = chalk.blue;\n break;\n }\n\n // Main line\n lines.push(\n ` ${color(icon)} ${color.bold(result.severity.toUpperCase().padEnd(8))} ${chalk.gray(result.checkId)}`\n );\n \n // File and message\n if (result.file) {\n lines.push(` ${chalk.cyan(result.file)} - ${result.message}`);\n } else {\n lines.push(` ${result.message}`);\n }\n\n // Details (if any)\n if (result.details && result.details.length > 0) {\n const maxDetails = 5;\n const showDetails = result.details.slice(0, maxDetails);\n \n for (const detail of showDetails) {\n lines.push(chalk.gray(` - ${detail}`));\n }\n \n if (result.details.length > maxDetails) {\n lines.push(chalk.gray(` ... and ${result.details.length - maxDetails} more`));\n }\n }\n\n lines.push('');\n return lines.join('\\n');\n}\n\n/**\n * Print report to console\n */\nexport function printReport(report: CheckReport): void {\n console.log(formatTerminal(report));\n}\n","import type { CheckReport } from '../types/index.js';\n\n/**\n * Format check results as JSON\n */\nexport function formatJson(report: CheckReport): string {\n return JSON.stringify(report, null, 2);\n}\n","import type { CheckReport } from '../types/index.js';\n\n/**\n * Generate HTML report from check results\n */\nexport function formatHtml(report: CheckReport): string {\n const { summary, results } = report;\n \n // Group results by file\n const byFile = new Map<string, typeof results>();\n results.forEach(r => {\n const file = r.file || 'Unknown';\n if (!byFile.has(file)) {\n byFile.set(file, []);\n }\n byFile.get(file)!.push(r);\n });\n\n // Calculate score (simple: passed / total * 100)\n const totalChecks = summary.passed + summary.critical + summary.warning + summary.info;\n const score = totalChecks > 0 ? Math.round((summary.passed / totalChecks) * 100) : 100;\n\n // Determine score color\n const scoreColor = score >= 90 ? '#22c55e' : score >= 70 ? '#eab308' : score >= 50 ? '#f97316' : '#ef4444';\n\n const html = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>SEO Audit Report - ${new Date(report.timestamp).toLocaleDateString()}</title>\n <style>\n * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n }\n \n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n background: #f8fafc;\n color: #1e293b;\n line-height: 1.6;\n }\n \n .container {\n max-width: 1200px;\n margin: 0 auto;\n padding: 2rem;\n }\n \n header {\n background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);\n color: white;\n padding: 2rem;\n border-radius: 1rem;\n margin-bottom: 2rem;\n }\n \n header h1 {\n font-size: 1.875rem;\n margin-bottom: 0.5rem;\n }\n \n header p {\n opacity: 0.9;\n font-size: 0.875rem;\n }\n \n .score-ring {\n display: flex;\n align-items: center;\n gap: 2rem;\n margin-top: 1.5rem;\n }\n \n .score-circle {\n width: 120px;\n height: 120px;\n border-radius: 50%;\n background: conic-gradient(${scoreColor} ${score * 3.6}deg, rgba(255,255,255,0.2) 0deg);\n display: flex;\n align-items: center;\n justify-content: center;\n position: relative;\n }\n \n .score-circle::before {\n content: '';\n position: absolute;\n width: 90px;\n height: 90px;\n background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);\n border-radius: 50%;\n }\n \n .score-value {\n position: relative;\n font-size: 2rem;\n font-weight: bold;\n }\n \n .score-stats {\n display: flex;\n gap: 1.5rem;\n }\n \n .stat {\n text-align: center;\n }\n \n .stat-value {\n font-size: 1.5rem;\n font-weight: bold;\n }\n \n .stat-label {\n font-size: 0.75rem;\n opacity: 0.8;\n text-transform: uppercase;\n }\n \n .summary-cards {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 1rem;\n margin-bottom: 2rem;\n }\n \n .card {\n background: white;\n border-radius: 0.75rem;\n padding: 1.5rem;\n box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n }\n \n .card-critical {\n border-left: 4px solid #ef4444;\n }\n \n .card-warning {\n border-left: 4px solid #eab308;\n }\n \n .card-info {\n border-left: 4px solid #3b82f6;\n }\n \n .card-passed {\n border-left: 4px solid #22c55e;\n }\n \n .card h3 {\n font-size: 2rem;\n margin-bottom: 0.25rem;\n }\n \n .card p {\n color: #64748b;\n font-size: 0.875rem;\n }\n \n .section {\n background: white;\n border-radius: 0.75rem;\n padding: 1.5rem;\n margin-bottom: 1.5rem;\n box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n }\n \n .section h2 {\n font-size: 1.25rem;\n margin-bottom: 1rem;\n padding-bottom: 0.75rem;\n border-bottom: 1px solid #e2e8f0;\n }\n \n .file-group {\n margin-bottom: 1.5rem;\n }\n \n .file-group:last-child {\n margin-bottom: 0;\n }\n \n .file-name {\n font-weight: 600;\n color: #475569;\n font-size: 0.875rem;\n margin-bottom: 0.75rem;\n padding: 0.5rem;\n background: #f1f5f9;\n border-radius: 0.375rem;\n font-family: monospace;\n }\n \n .issue {\n display: flex;\n gap: 1rem;\n padding: 1rem;\n border-radius: 0.5rem;\n margin-bottom: 0.5rem;\n background: #fafafa;\n }\n \n .issue:hover {\n background: #f1f5f9;\n }\n \n .issue-severity {\n flex-shrink: 0;\n width: 80px;\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n padding: 0.25rem 0.5rem;\n border-radius: 0.25rem;\n text-align: center;\n height: fit-content;\n }\n \n .severity-critical {\n background: #fef2f2;\n color: #dc2626;\n }\n \n .severity-warning {\n background: #fefce8;\n color: #ca8a04;\n }\n \n .severity-info {\n background: #eff6ff;\n color: #2563eb;\n }\n \n .issue-content {\n flex: 1;\n }\n \n .issue-name {\n font-weight: 600;\n margin-bottom: 0.25rem;\n }\n \n .issue-message {\n color: #64748b;\n font-size: 0.875rem;\n }\n \n .issue-fix {\n margin-top: 0.5rem;\n padding: 0.75rem;\n background: #f0fdf4;\n border-radius: 0.375rem;\n font-size: 0.875rem;\n color: #166534;\n }\n \n .issue-fix strong {\n display: block;\n margin-bottom: 0.25rem;\n }\n \n .issue-details {\n margin-top: 0.5rem;\n font-size: 0.75rem;\n color: #94a3b8;\n }\n \n .issue-details ul {\n margin-left: 1rem;\n margin-top: 0.25rem;\n }\n \n footer {\n text-align: center;\n padding: 2rem;\n color: #94a3b8;\n font-size: 0.875rem;\n }\n \n footer a {\n color: #3b82f6;\n text-decoration: none;\n }\n \n footer a:hover {\n text-decoration: underline;\n }\n \n .no-issues {\n text-align: center;\n padding: 3rem;\n color: #22c55e;\n }\n \n .no-issues svg {\n width: 64px;\n height: 64px;\n margin-bottom: 1rem;\n }\n \n @media (max-width: 640px) {\n .container {\n padding: 1rem;\n }\n \n .score-ring {\n flex-direction: column;\n align-items: flex-start;\n }\n \n .summary-cards {\n grid-template-columns: 1fr 1fr;\n }\n }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <header>\n <h1>🔍 SEO Audit Report</h1>\n <p>Generated on ${new Date(report.timestamp).toLocaleString()} • Path: ${report.path}</p>\n \n <div class=\"score-ring\">\n <div class=\"score-circle\">\n <span class=\"score-value\">${score}</span>\n </div>\n <div class=\"score-stats\">\n <div class=\"stat\">\n <div class=\"stat-value\">${summary.totalFiles}</div>\n <div class=\"stat-label\">Files</div>\n </div>\n <div class=\"stat\">\n <div class=\"stat-value\">${totalChecks}</div>\n <div class=\"stat-label\">Checks</div>\n </div>\n <div class=\"stat\">\n <div class=\"stat-value\">${summary.passed}</div>\n <div class=\"stat-label\">Passed</div>\n </div>\n </div>\n </div>\n </header>\n \n <div class=\"summary-cards\">\n <div class=\"card card-critical\">\n <h3>${summary.critical}</h3>\n <p>Critical Issues</p>\n </div>\n <div class=\"card card-warning\">\n <h3>${summary.warning}</h3>\n <p>Warnings</p>\n </div>\n <div class=\"card card-info\">\n <h3>${summary.info}</h3>\n <p>Info</p>\n </div>\n <div class=\"card card-passed\">\n <h3>${summary.passed}</h3>\n <p>Passed</p>\n </div>\n </div>\n \n ${results.length === 0 ? `\n <div class=\"section\">\n <div class=\"no-issues\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <h2>All Checks Passed!</h2>\n <p>No SEO issues found. Great job!</p>\n </div>\n </div>\n ` : `\n <div class=\"section\">\n <h2>Issues Found</h2>\n ${Array.from(byFile.entries()).map(([file, issues]) => `\n <div class=\"file-group\">\n <div class=\"file-name\">${escapeHtml(file)}</div>\n ${issues.map(issue => `\n <div class=\"issue\">\n <span class=\"issue-severity severity-${issue.severity}\">${issue.severity}</span>\n <div class=\"issue-content\">\n <div class=\"issue-name\">${escapeHtml(issue.name)}</div>\n <div class=\"issue-message\">${escapeHtml(issue.message)}</div>\n ${issue.fix ? `\n <div class=\"issue-fix\">\n <strong>How to fix:</strong>\n ${escapeHtml(issue.fix)}\n </div>\n ` : ''}\n ${issue.details && issue.details.length > 0 ? `\n <div class=\"issue-details\">\n <strong>Affected:</strong>\n <ul>\n ${issue.details.slice(0, 5).map(d => `<li>${escapeHtml(d)}</li>`).join('')}\n ${issue.details.length > 5 ? `<li>...and ${issue.details.length - 5} more</li>` : ''}\n </ul>\n </div>\n ` : ''}\n </div>\n </div>\n `).join('')}\n </div>\n `).join('')}\n </div>\n `}\n \n <footer>\n <p>Generated by <a href=\"https://rankture.com\">Rankture CLI</a> v${report.version}</p>\n <p>For full audit with Core Web Vitals and AI suggestions, visit <a href=\"https://rankture.com/free-seo-audit/\">rankture.com</a></p>\n </footer>\n </div>\n</body>\n</html>`;\n\n return html;\n}\n\n/**\n * Escape HTML special characters\n */\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport chalk from 'chalk';\nimport { XMLParser } from 'fast-xml-parser';\n\nexport interface ValidateResult {\n valid: boolean;\n errors: string[];\n warnings: string[];\n info: string[];\n}\n\n/**\n * Validate a robots.txt file\n */\nexport async function validateRobotsTxt(filePath: string): Promise<ValidateResult> {\n const result: ValidateResult = {\n valid: true,\n errors: [],\n warnings: [],\n info: [],\n };\n\n const absolutePath = path.resolve(filePath);\n\n if (!fs.existsSync(absolutePath)) {\n result.valid = false;\n result.errors.push(`File not found: ${absolutePath}`);\n return result;\n }\n\n const content = fs.readFileSync(absolutePath, 'utf-8');\n const lines = content.split('\\n');\n\n let hasUserAgent = false;\n let hasSitemap = false;\n let currentUserAgent = '';\n let lineNum = 0;\n\n for (const rawLine of lines) {\n lineNum++;\n const line = rawLine.trim();\n\n // Skip empty lines and comments\n if (!line || line.startsWith('#')) {\n continue;\n }\n\n // Check for valid directives\n const colonIndex = line.indexOf(':');\n if (colonIndex === -1) {\n result.warnings.push(`Line ${lineNum}: Invalid format (missing colon): \"${line}\"`);\n continue;\n }\n\n const directive = line.substring(0, colonIndex).trim().toLowerCase();\n const value = line.substring(colonIndex + 1).trim();\n\n switch (directive) {\n case 'user-agent':\n hasUserAgent = true;\n currentUserAgent = value;\n if (!value) {\n result.errors.push(`Line ${lineNum}: User-agent directive has no value`);\n result.valid = false;\n }\n break;\n\n case 'disallow':\n if (!currentUserAgent) {\n result.errors.push(`Line ${lineNum}: Disallow before User-agent directive`);\n result.valid = false;\n }\n // Empty disallow is valid (allows everything)\n if (value && !value.startsWith('/') && value !== '*') {\n result.warnings.push(`Line ${lineNum}: Disallow path should start with /`);\n }\n break;\n\n case 'allow':\n if (!currentUserAgent) {\n result.errors.push(`Line ${lineNum}: Allow before User-agent directive`);\n result.valid = false;\n }\n if (value && !value.startsWith('/') && value !== '*') {\n result.warnings.push(`Line ${lineNum}: Allow path should start with /`);\n }\n break;\n\n case 'sitemap':\n hasSitemap = true;\n if (!value.startsWith('http://') && !value.startsWith('https://')) {\n result.errors.push(`Line ${lineNum}: Sitemap URL must be absolute (start with http:// or https://)`);\n result.valid = false;\n }\n break;\n\n case 'crawl-delay':\n {\n const delay = parseFloat(value);\n if (isNaN(delay) || delay < 0) {\n result.warnings.push(`Line ${lineNum}: Invalid crawl-delay value: \"${value}\"`);\n } else if (delay > 10) {\n result.warnings.push(\n `Line ${lineNum}: Crawl-delay of ${delay}s is very high - may slow indexing`\n );\n }\n break;\n }\n\n case 'host':\n // Yandex directive\n result.info.push(`Line ${lineNum}: Host directive (Yandex-specific)`);\n break;\n\n case 'clean-param':\n // Yandex directive\n result.info.push(`Line ${lineNum}: Clean-param directive (Yandex-specific)`);\n break;\n\n default:\n result.warnings.push(`Line ${lineNum}: Unknown directive: \"${directive}\"`);\n }\n }\n\n // Check for required elements\n if (!hasUserAgent) {\n result.errors.push('Missing User-agent directive (required)');\n result.valid = false;\n }\n\n if (!hasSitemap) {\n result.warnings.push('No Sitemap directive found - recommended to include sitemap URL');\n }\n\n // Check for common issues\n if (content.includes('Disallow: /') && !content.includes('Allow:')) {\n const disallowAll = lines.some(l => {\n const trimmed = l.trim().toLowerCase();\n return trimmed === 'disallow: /' || trimmed === 'disallow:/' ;\n });\n if (disallowAll) {\n result.warnings.push('Found \"Disallow: /\" which blocks all crawling - ensure this is intentional');\n }\n }\n\n // Summary info\n result.info.push(`Total lines: ${lines.length}`);\n result.info.push(`User-agents defined: ${lines.filter(l => l.trim().toLowerCase().startsWith('user-agent')).length}`);\n\n return result;\n}\n\n/**\n * Validate a sitemap.xml file\n */\nexport async function validateSitemap(filePath: string): Promise<ValidateResult> {\n const result: ValidateResult = {\n valid: true,\n errors: [],\n warnings: [],\n info: [],\n };\n\n const absolutePath = path.resolve(filePath);\n\n if (!fs.existsSync(absolutePath)) {\n result.valid = false;\n result.errors.push(`File not found: ${absolutePath}`);\n return result;\n }\n\n const content = fs.readFileSync(absolutePath, 'utf-8');\n\n // Check XML declaration\n if (!content.trim().startsWith('<?xml')) {\n result.warnings.push('Missing XML declaration (<?xml version=\"1.0\" encoding=\"UTF-8\"?>)');\n }\n\n // Parse XML\n const parser = new XMLParser({\n ignoreAttributes: false,\n attributeNamePrefix: '@_',\n });\n\n // fast-xml-parser produces a loosely-typed object; keep it permissive here.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let parsed: any;\n try {\n parsed = parser.parse(content);\n } catch (error) {\n result.valid = false;\n result.errors.push(`Invalid XML: ${error}`);\n return result;\n }\n\n // Check for sitemap index vs urlset\n const isSitemapIndex = !!parsed.sitemapindex;\n const isUrlset = !!parsed.urlset;\n\n if (!isSitemapIndex && !isUrlset) {\n result.valid = false;\n result.errors.push('Missing root element: expected <urlset> or <sitemapindex>');\n return result;\n }\n\n if (isSitemapIndex) {\n // Validate sitemap index\n const sitemaps = parsed.sitemapindex.sitemap;\n const sitemapArray = Array.isArray(sitemaps) ? sitemaps : sitemaps ? [sitemaps] : [];\n\n result.info.push(`Sitemap index with ${sitemapArray.length} child sitemap(s)`);\n\n for (let i = 0; i < sitemapArray.length; i++) {\n const sitemap = sitemapArray[i];\n if (!sitemap.loc) {\n result.errors.push(`Sitemap ${i + 1}: Missing <loc> element (required)`);\n result.valid = false;\n } else if (!sitemap.loc.startsWith('http')) {\n result.errors.push(`Sitemap ${i + 1}: <loc> must be absolute URL`);\n result.valid = false;\n }\n }\n } else {\n // Validate urlset\n const urls = parsed.urlset.url;\n const urlArray = Array.isArray(urls) ? urls : urls ? [urls] : [];\n\n result.info.push(`Sitemap with ${urlArray.length} URL(s)`);\n\n if (urlArray.length === 0) {\n result.warnings.push('Sitemap is empty (no URLs)');\n }\n\n if (urlArray.length > 50000) {\n result.errors.push(`Sitemap has ${urlArray.length} URLs - maximum allowed is 50,000`);\n result.valid = false;\n }\n\n // Check file size (uncompressed max is 50MB)\n const fileSize = Buffer.byteLength(content, 'utf-8');\n const fileSizeMB = fileSize / (1024 * 1024);\n if (fileSizeMB > 50) {\n result.errors.push(`Sitemap is ${fileSizeMB.toFixed(1)}MB - maximum allowed is 50MB`);\n result.valid = false;\n }\n\n // Validate individual URLs\n const priorities = new Set<string>();\n const changefreqs = new Set<string>();\n let urlsWithoutLoc = 0;\n let urlsWithRelativeLoc = 0;\n let urlsWithLastmod = 0;\n let urlsWithPriority = 0;\n let urlsWithChangefreq = 0;\n\n const validChangefreqs = ['always', 'hourly', 'daily', 'weekly', 'monthly', 'yearly', 'never'];\n const seenUrls = new Set<string>();\n const duplicateUrls: string[] = [];\n\n for (let i = 0; i < Math.min(urlArray.length, 1000); i++) { // Check first 1000 URLs\n const url = urlArray[i];\n\n if (!url.loc) {\n urlsWithoutLoc++;\n } else {\n // Check for duplicates\n if (seenUrls.has(url.loc)) {\n duplicateUrls.push(url.loc);\n }\n seenUrls.add(url.loc);\n\n if (!url.loc.startsWith('http')) {\n urlsWithRelativeLoc++;\n }\n }\n\n if (url.lastmod) {\n urlsWithLastmod++;\n // Validate date format\n const datePattern = /^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}([+-]\\d{2}:\\d{2}|Z)?)?$/;\n if (!datePattern.test(url.lastmod)) {\n result.warnings.push(`URL ${i + 1}: Invalid lastmod date format: \"${url.lastmod}\"`);\n }\n }\n\n if (url.priority !== undefined) {\n urlsWithPriority++;\n priorities.add(String(url.priority));\n const priority = parseFloat(url.priority);\n if (isNaN(priority) || priority < 0 || priority > 1) {\n result.warnings.push(`URL ${i + 1}: Invalid priority value: \"${url.priority}\" (must be 0.0-1.0)`);\n }\n }\n\n if (url.changefreq) {\n urlsWithChangefreq++;\n changefreqs.add(url.changefreq);\n if (!validChangefreqs.includes(url.changefreq.toLowerCase())) {\n result.warnings.push(`URL ${i + 1}: Invalid changefreq: \"${url.changefreq}\"`);\n }\n }\n }\n\n // Report issues\n if (urlsWithoutLoc > 0) {\n result.errors.push(`${urlsWithoutLoc} URL(s) missing required <loc> element`);\n result.valid = false;\n }\n\n if (urlsWithRelativeLoc > 0) {\n result.errors.push(`${urlsWithRelativeLoc} URL(s) have relative URLs - must be absolute`);\n result.valid = false;\n }\n\n if (duplicateUrls.length > 0) {\n result.warnings.push(`${duplicateUrls.length} duplicate URL(s) found`);\n if (duplicateUrls.length <= 5) {\n duplicateUrls.forEach(url => result.warnings.push(` Duplicate: ${url}`));\n }\n }\n\n // Info about optional elements\n if (urlsWithLastmod === 0) {\n result.info.push('No lastmod dates - consider adding for better crawling');\n } else {\n result.info.push(`${urlsWithLastmod} URL(s) have lastmod dates`);\n }\n\n if (priorities.size === 1) {\n result.info.push(`All URLs have same priority (${[...priorities][0]}) - consider varying for important pages`);\n }\n\n // Note: priority and changefreq are largely ignored by Google now\n if (urlsWithPriority > 0 || urlsWithChangefreq > 0) {\n result.info.push('Note: Google largely ignores priority and changefreq - focus on lastmod instead');\n }\n }\n\n return result;\n}\n\n/**\n * Print validation results\n */\nexport function printValidationResult(type: string, filePath: string, result: ValidateResult): void {\n console.log('');\n console.log(chalk.bold(` ${type.toUpperCase()} Validation: ${filePath}`));\n console.log(' ' + '─'.repeat(50));\n\n if (result.valid) {\n console.log(chalk.green(' ✓ Valid'));\n } else {\n console.log(chalk.red(' ✗ Invalid'));\n }\n\n if (result.errors.length > 0) {\n console.log('');\n console.log(chalk.red(' Errors:'));\n result.errors.forEach(e => console.log(chalk.red(` • ${e}`)));\n }\n\n if (result.warnings.length > 0) {\n console.log('');\n console.log(chalk.yellow(' Warnings:'));\n result.warnings.forEach(w => console.log(chalk.yellow(` • ${w}`)));\n }\n\n if (result.info.length > 0) {\n console.log('');\n console.log(chalk.blue(' Info:'));\n result.info.forEach(i => console.log(chalk.blue(` • ${i}`)));\n }\n\n console.log('');\n}\n","/**\n * @rankture/cli - SEO audit tool for developers\n *\n * This is the public API for programmatic usage.\n * For CLI usage, run: npx @rankture/cli check ./dist\n */\n\nimport type { CheckResult, ParsedPage } from './types/index.js';\nimport { runChecks } from './checks/index.js';\nimport { parseHtml } from './parsers/html.js';\n\n// Types\nexport type {\n CheckResult,\n ParsedPage,\n CheckOptions,\n CheckReport,\n CheckSummary,\n RanktureConfig,\n} from './types/index.js';\n\n// Parsers\nexport { parseHtml, parseSourceFile, SUPPORTED_EXTENSIONS } from './parsers/html.js';\n\n// Checks\nexport { runChecks, checks, getAvailableChecks } from './checks/index.js';\nexport {\n checkMetaTitle,\n checkMetaDescription,\n checkViewport,\n checkLang,\n checkCanonical,\n} from './checks/meta-tags.js';\nexport { checkH1, checkHeadingHierarchy } from './checks/headings.js';\nexport { checkImageAlt } from './checks/images.js';\nexport { checkInternalLinks } from './checks/links.js';\nexport { checkSchema, checkSchemaJsonValidity } from './checks/schema.js';\nexport { checkOpenGraph, checkTwitterCards, checkRobotsMeta } from './checks/social.js';\nexport { checkAccessibility, checkColorContrast, checkFocusIndicators } from './checks/accessibility.js';\n\n// Config\nexport { loadConfig, defaultConfig, getEnabledChecks } from './lib/config.js';\n\n// Reporters\nexport { formatTerminal } from './reporters/terminal.js';\nexport { formatJson } from './reporters/json.js';\nexport { formatHtml } from './reporters/html.js';\n\n// Validators\nexport { validateRobotsTxt, validateSitemap } from './commands/validate.js';\nexport type { ValidateResult } from './commands/validate.js';\n\n/**\n * Page check result for programmatic API\n */\nexport interface PageCheckResult {\n url: string;\n results: import('./types/index.js').CheckResult[];\n summary: {\n total: number;\n passed: number;\n failed: number;\n critical: number;\n warnings: number;\n score: number;\n };\n}\n\n/**\n * Run checks on a single HTML file/string programmatically\n */\nexport function checkPage(html: string, url = 'file://local', basePath = '.'): PageCheckResult {\n const parsed: ParsedPage = parseHtml(url, html);\n const results: CheckResult[] = runChecks(parsed, [parsed], basePath);\n\n const passed = results.filter((r) => r.passed).length;\n const failed = results.filter((r) => !r.passed).length;\n const critical = results.filter((r) => !r.passed && r.severity === 'critical').length;\n const warnings = results.filter((r) => !r.passed && r.severity === 'warning').length;\n\n // Calculate score (passed checks / total checks * 100)\n const score = results.length > 0 ? Math.round((passed / results.length) * 100) : 100;\n\n return {\n url,\n results,\n summary: {\n total: results.length,\n passed,\n failed,\n critical,\n warnings,\n score,\n },\n };\n}\n"],"mappings":"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","names":["cheerio","fs","path","fs","path","chalk"]}
|