lintpage 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.cjs","names":["dns","JSDOM","path","format"],"sources":["../../core/dist/index.mjs","../../pro/dist/index.mjs","../src/cli.ts"],"sourcesContent":["// src/rules/title.ts\nvar titleRule = {\n meta: {\n id: \"title\",\n name: \"Page Title\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Checks for the presence and length of the <title> tag\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const titleElement = document.querySelector(\"title\");\n const value = titleElement?.textContent?.trim() || \"\";\n const length = value.length;\n if (!value) {\n results.push({\n ruleId: \"title\",\n ruleName: \"Page Title\",\n message: \"Missing title tag\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Add a <title>Your Page Title</title> tag inside your <head> element. Aim for 50-60 characters to avoid truncation in search results.\",\n data: { value, length }\n });\n } else if (length < 30) {\n results.push({\n ruleId: \"title\",\n ruleName: \"Page Title\",\n message: \"Title may be too short - under 30 characters may not be descriptive enough\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Expand your title to 50-60 characters to avoid truncation. Google does not enforce a character limit but truncates based on pixel width (~600px on desktop).\",\n data: { value, length }\n });\n } else if (length > 60) {\n results.push({\n ruleId: \"title\",\n ruleName: \"Page Title\",\n message: \"Title is over 60 characters - likely to be truncated in search results\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Shorten your title to under 60 characters to avoid truncation. Google truncates based on pixel width (~600px on desktop), which is roughly 60 characters.\",\n data: { value, length }\n });\n }\n return results;\n }\n};\n\n// src/rules/meta-description.ts\nvar metaDescriptionRule = {\n meta: {\n id: \"meta-description\",\n name: \"Meta Description\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Checks for the presence and length of the meta description tag\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const metaDesc = document.querySelector('meta[name=\"description\"]');\n const value = metaDesc?.getAttribute(\"content\")?.trim() || \"\";\n const length = value.length;\n if (!value) {\n results.push({\n ruleId: \"meta-description\",\n ruleName: \"Meta Description\",\n message: \"Missing meta description\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: 'Add <meta name=\"description\" content=\"Your description here\" /> to your <head> tag. Aim for 150-160 characters to avoid truncation.',\n data: { value, length }\n });\n } else if (length < 120) {\n results.push({\n ruleId: \"meta-description\",\n ruleName: \"Meta Description\",\n message: \"Meta description may be too short - under 120 characters may not fully utilize the available snippet space\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Expand your meta description to 150-160 characters. Google does not enforce a character limit but typically truncates around 160 characters on desktop (~120 on mobile).\",\n data: { value, length }\n });\n } else if (length > 160) {\n results.push({\n ruleId: \"meta-description\",\n ruleName: \"Meta Description\",\n message: \"Meta description is over 160 characters - likely to be truncated in search results\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Shorten your meta description to under 160 characters. Google truncates snippets based on device width, typically around 160 characters on desktop.\",\n data: { value, length }\n });\n }\n return results;\n }\n};\n\n// src/rules/og-title.ts\nvar ogTitleRule = {\n meta: {\n id: \"og-title\",\n name: \"Open Graph Title\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Checks for the og:title meta tag\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const ogTitle = document.querySelector('meta[property=\"og:title\"]');\n const value = ogTitle?.getAttribute(\"content\")?.trim() || \"\";\n if (!value) {\n results.push({\n ruleId: \"og-title\",\n ruleName: \"Open Graph Title\",\n message: \"Missing og:title tag - social media shares will have no title preview\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: 'Add <meta property=\"og:title\" content=\"Your Page Title\" /> to your <head> tag.'\n });\n } else if (value.length > 60) {\n results.push({\n ruleId: \"og-title\",\n ruleName: \"Open Graph Title\",\n message: `og:title is long (${value.length} characters). Optimal: 50-60 characters`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Shorten your og:title to under 60 characters. Longer titles get truncated on most social platforms.\",\n data: { value, length: value.length }\n });\n } else if (value.length < 30) {\n results.push({\n ruleId: \"og-title\",\n ruleName: \"Open Graph Title\",\n message: `og:title is short (${value.length} characters). Optimal: 50-60 characters`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Consider expanding your og:title to 50-60 characters to make social shares more compelling.\",\n data: { value, length: value.length }\n });\n }\n return results;\n }\n};\n\n// src/rules/og-description.ts\nvar ogDescriptionRule = {\n meta: {\n id: \"og-description\",\n name: \"Open Graph Description\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Checks for the og:description meta tag\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const ogDesc = document.querySelector('meta[property=\"og:description\"]');\n const value = ogDesc?.getAttribute(\"content\")?.trim() || \"\";\n if (!value) {\n results.push({\n ruleId: \"og-description\",\n ruleName: \"Open Graph Description\",\n message: \"Missing og:description tag - social media shares will have no description preview\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: 'Add <meta property=\"og:description\" content=\"Your description\" /> to your <head> tag.'\n });\n } else if (value.length > 200) {\n results.push({\n ruleId: \"og-description\",\n ruleName: \"Open Graph Description\",\n message: `og:description is long (${value.length} characters). Optimal: 110-160 characters`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Shorten your og:description to under 200 characters. Most platforms truncate longer descriptions.\",\n data: { value, length: value.length }\n });\n } else if (value.length < 70) {\n results.push({\n ruleId: \"og-description\",\n ruleName: \"Open Graph Description\",\n message: `og:description is short (${value.length} characters). Optimal: 110-160 characters`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Consider expanding your og:description to 110-160 characters to make social shares more engaging.\",\n data: { value, length: value.length }\n });\n }\n return results;\n }\n};\n\n// src/rules/og-image.ts\nvar ogImageRule = {\n meta: {\n id: \"og-image\",\n name: \"Open Graph Image\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Checks for the og:image meta tag\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const ogImage = document.querySelector('meta[property=\"og:image\"]');\n if (!ogImage?.getAttribute(\"content\")) {\n results.push({\n ruleId: \"og-image\",\n ruleName: \"Open Graph Image\",\n message: \"Missing og:image tag - social media shares will have no image preview\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: 'Add <meta property=\"og:image\" content=\"https://yoursite.com/image.jpg\" /> to your <head> tag.'\n });\n }\n return results;\n }\n};\n\n// src/rules/og-url.ts\nvar ogUrlRule = {\n meta: {\n id: \"og-url\",\n name: \"Open Graph URL\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Checks for the og:url meta tag\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const ogUrl = document.querySelector('meta[property=\"og:url\"]');\n if (!ogUrl?.getAttribute(\"content\")) {\n results.push({\n ruleId: \"og-url\",\n ruleName: \"Open Graph URL\",\n message: \"Missing og:url tag - social media may not show the correct URL\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: 'Add <meta property=\"og:url\" content=\"https://yoursite.com/page\" /> to your <head> tag.'\n });\n }\n return results;\n }\n};\n\n// src/rules/twitter-card.ts\nvar twitterCardRule = {\n meta: {\n id: \"twitter-card\",\n name: \"Twitter Card\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Checks for Twitter Card meta tags\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const twitterCard = document.querySelector('meta[name=\"twitter:card\"]');\n if (!twitterCard?.getAttribute(\"content\")) {\n results.push({\n ruleId: \"twitter-card\",\n ruleName: \"Twitter Card\",\n message: \"Missing Twitter Card tags - tweets with your URL will have no preview card\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: 'Add <meta name=\"twitter:card\" content=\"summary_large_image\" />, <meta name=\"twitter:title\" content=\"...\" />, and <meta name=\"twitter:image\" content=\"...\" /> to your <head>.'\n });\n }\n return results;\n }\n};\n\n// src/rules/canonical-url.ts\nvar canonicalUrlRule = {\n meta: {\n id: \"canonical-url\",\n name: \"Canonical URL\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Checks for a canonical link tag and validates the URL\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const canonical = document.querySelector('link[rel=\"canonical\"]');\n const value = canonical?.getAttribute(\"href\") || void 0;\n if (!canonical) {\n results.push({\n ruleId: \"canonical-url\",\n ruleName: \"Canonical URL\",\n message: \"No canonical link found (recommended for SEO)\",\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"free\",\n fix: 'Add <link rel=\"canonical\" href=\"https://yoursite.com/this-page\" /> to your <head> tag to prevent duplicate content issues.',\n data: { present: false }\n });\n } else if (value && !value.startsWith(\"http\")) {\n results.push({\n ruleId: \"canonical-url\",\n ruleName: \"Canonical URL\",\n message: \"Canonical URL should be absolute (include protocol and domain)\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: 'Change your canonical href to an absolute URL starting with https:// (e.g., href=\"https://yoursite.com/page\").',\n data: { present: true, value }\n });\n }\n return results;\n }\n};\n\n// src/rules/robots-noindex.ts\nvar robotsNoindexRule = {\n meta: {\n id: \"robots-noindex\",\n name: \"Robots Noindex\",\n category: \"Pre-Launch\",\n tier: \"free\",\n description: \"Checks for noindex/nofollow in the robots meta tag\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const metaRobots = document.querySelector('meta[name=\"robots\"]');\n const content = metaRobots?.getAttribute(\"content\") || \"\";\n if (content.includes(\"noindex\")) {\n results.push({\n ruleId: \"robots-noindex\",\n ruleName: \"Robots Noindex\",\n message: \"Page has noindex meta tag - WILL NOT BE INDEXED by search engines! Remove this before launch or you'll get ZERO organic traffic.\",\n severity: \"CRITICAL\",\n category: \"Pre-Launch\",\n tier: \"free\",\n fix: 'Remove the <meta name=\"robots\" content=\"noindex\" /> tag from your <head>, or change it to content=\"index, follow\".',\n data: { metaRobots: content }\n });\n }\n if (content.includes(\"nofollow\")) {\n results.push({\n ruleId: \"robots-noindex\",\n ruleName: \"Robots Noindex\",\n message: \"Page has nofollow meta tag - links will not be followed\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: 'Remove \"nofollow\" from your <meta name=\"robots\"> content if you want search engines to follow your links.',\n data: { metaRobots: content }\n });\n }\n return results;\n }\n};\n\n// src/rules/heading-structure.ts\nvar headingStructureRule = {\n meta: {\n id: \"heading-structure\",\n name: \"Heading Structure\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Validates H1 tag presence, count, and heading hierarchy\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const h1Elements = document.querySelectorAll(\"h1\");\n const count = h1Elements.length;\n const values = Array.from(h1Elements).map(\n (h1) => h1.textContent?.trim() || \"\"\n );\n if (count === 0) {\n results.push({\n ruleId: \"heading-structure\",\n ruleName: \"Heading Structure\",\n message: \"No H1 tag found\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Add a single <h1> tag to your page with a clear, descriptive heading that includes your primary keyword.\",\n data: { h1Count: count }\n });\n } else if (count > 1) {\n results.push({\n ruleId: \"heading-structure\",\n ruleName: \"Heading Structure\",\n message: `Multiple H1 tags found (${count}). Best practice is 1 per page`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"While Google does not penalize multiple H1 tags, using a single H1 per page is a widely recommended best practice for clarity and accessibility.\",\n data: { h1Count: count, h1Values: values }\n });\n }\n values.forEach((value, index) => {\n if (!value) {\n results.push({\n ruleId: \"heading-structure\",\n ruleName: \"Heading Structure\",\n message: `H1 #${index + 1} is empty`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Add descriptive text content to your <h1> tag.\"\n });\n } else if (value.length > 70) {\n results.push({\n ruleId: \"heading-structure\",\n ruleName: \"Heading Structure\",\n message: `H1 #${index + 1} is too long (${value.length} characters)`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Shorten your H1 to under 70 characters for better readability and SEO.\"\n });\n }\n });\n const headings = document.querySelectorAll(\"h1, h2, h3, h4, h5, h6\");\n let lastLevel = 0;\n Array.from(headings).forEach((heading) => {\n const level = Number.parseInt(heading.tagName[1] ?? \"1\", 10);\n if (level - lastLevel > 1) {\n const text = heading.textContent?.trim().substring(0, 40) || \"...\";\n results.push({\n ruleId: \"heading-structure\",\n ruleName: \"Heading Structure\",\n message: `${heading.tagName} skips heading level from h${lastLevel} (content: \"${text}\")`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"free\",\n fix: `Don't skip heading levels. Use h${lastLevel + 1} instead of ${heading.tagName} to maintain proper hierarchy.`\n });\n }\n lastLevel = level;\n });\n return results;\n }\n};\n\n// src/rules/html-lang.ts\nvar htmlLangRule = {\n meta: {\n id: \"html-lang\",\n name: \"HTML Lang Attribute\",\n category: \"Accessibility\",\n tier: \"free\",\n description: \"Checks for the lang attribute on the <html> tag\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const html = document.documentElement;\n const lang = html.getAttribute(\"lang\");\n if (!lang) {\n results.push({\n ruleId: \"html-lang\",\n ruleName: \"HTML Lang Attribute\",\n message: \"Missing lang attribute on <html> tag\",\n severity: \"WARNING\",\n category: \"Accessibility\",\n tier: \"free\",\n fix: 'Add lang=\"en\" (or your language code) to your <html> tag: <html lang=\"en\">.',\n data: { present: false }\n });\n }\n return results;\n }\n};\n\n// src/rules/viewport.ts\nvar viewportRule = {\n meta: {\n id: \"viewport\",\n name: \"Viewport Meta Tag\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Checks for the viewport meta tag for mobile responsiveness\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const viewport = document.querySelector('meta[name=\"viewport\"]');\n if (!viewport) {\n results.push({\n ruleId: \"viewport\",\n ruleName: \"Viewport Meta Tag\",\n message: \"Missing viewport meta tag - page will not render properly on mobile devices\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: 'Add <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" /> to your <head> tag.',\n data: { present: false }\n });\n } else {\n const content = viewport.getAttribute(\"content\") || \"\";\n const hasUserScalableNo = /user-scalable\\s*=\\s*no/i.test(content);\n const maxScaleMatch = content.match(/maximum-scale\\s*=\\s*([\\d.]+)/i);\n const hasRestrictiveMaxScale = maxScaleMatch && parseFloat(maxScaleMatch[1]) < 2;\n if (hasUserScalableNo || hasRestrictiveMaxScale) {\n results.push({\n ruleId: \"viewport\",\n ruleName: \"Viewport Meta Tag\",\n message: \"Viewport disables or restricts user zoom - this fails WCAG 1.4.4 (Resize text) which requires at least 200% zoom\",\n severity: \"WARNING\",\n category: \"Accessibility\",\n tier: \"free\",\n fix: \"Remove user-scalable=no and ensure maximum-scale is at least 2.0 (or remove it entirely) to allow users to zoom.\"\n });\n }\n }\n return results;\n }\n};\n\n// src/rules/favicon.ts\nvar faviconRule = {\n meta: {\n id: \"favicon\",\n name: \"Favicon\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Checks for the presence of a favicon link tag\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const favicon = document.querySelector('link[rel*=\"icon\"]');\n if (!favicon) {\n results.push({\n ruleId: \"favicon\",\n ruleName: \"Favicon\",\n message: \"No favicon found - browsers will show a default icon in tabs and bookmarks\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: 'Add <link rel=\"icon\" href=\"/favicon.ico\" /> to your <head> tag. Include multiple sizes for best results.',\n data: { present: false }\n });\n }\n return results;\n }\n};\n\n// src/rules/anchor-missing-href.ts\nvar anchorMissingHrefRule = {\n meta: {\n id: \"anchor-missing-href\",\n name: \"Anchor Missing Href\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Checks that all <a> elements have a valid href attribute\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const anchors = document.querySelectorAll(\"a\");\n const missing = [];\n for (const anchor of anchors) {\n const href = anchor.getAttribute(\"href\");\n if (!href || href.trim() === \"\") {\n const text = anchor.textContent?.trim() || \"\";\n const preview = text.length > 50 ? text.slice(0, 50) + \"\\u2026\" : text;\n missing.push(preview || \"<empty>\");\n }\n }\n if (missing.length > 0) {\n results.push({\n ruleId: \"anchor-missing-href\",\n ruleName: \"Anchor Missing Href\",\n message: `${missing.length} <a> element(s) missing a valid href attribute: ${missing.join(\", \")}`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Add a valid href attribute to all <a> elements. Links without href are not crawlable by search engines and inaccessible to keyboard/screen reader users. If the element is not a link, use a <button> or <span> instead.\",\n data: { count: missing.length, anchors: missing }\n });\n }\n return results;\n }\n};\n\n// src/rules/index.ts\nvar coreRules = [\n titleRule,\n metaDescriptionRule,\n ogTitleRule,\n ogDescriptionRule,\n ogImageRule,\n ogUrlRule,\n twitterCardRule,\n canonicalUrlRule,\n robotsNoindexRule,\n headingStructureRule,\n htmlLangRule,\n viewportRule,\n faviconRule,\n anchorMissingHrefRule\n];\nvar ruleRegistry = new Map(\n coreRules.map((rule) => [rule.meta.id, rule])\n);\n\n// src/fetcher.ts\nimport { JSDOM } from \"jsdom\";\nimport dns from \"dns/promises\";\nfunction isPrivateOrReservedIPv4(ip) {\n const ipv4Match = ip.match(\n /^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/\n );\n if (!ipv4Match) return false;\n const [, a, b] = ipv4Match.map(Number);\n if (a === 10) return true;\n if (a === 172 && b >= 16 && b <= 31) return true;\n if (a === 192 && b === 168) return true;\n if (a === 127) return true;\n if (a === 169 && b === 254) return true;\n if (a === 0) return true;\n if (a === 100 && b >= 64 && b <= 127) return true;\n if (a === 198 && (b === 18 || b === 19)) return true;\n if (a >= 224) return true;\n return false;\n}\nfunction isBlockedHostname(hostname) {\n if (hostname === \"localhost\" || hostname === \"127.0.0.1\" || hostname === \"[::1]\" || hostname === \"0.0.0.0\") {\n return true;\n }\n if (hostname.endsWith(\".internal\") || hostname.endsWith(\".local\") || hostname.endsWith(\".localhost\")) {\n return true;\n }\n if (isPrivateOrReservedIPv4(hostname)) return true;\n if (hostname.startsWith(\"[\") && (hostname === \"[::1]\" || hostname.startsWith(\"[fc\") || hostname.startsWith(\"[fd\") || hostname.startsWith(\"[fe80:\"))) {\n return true;\n }\n return false;\n}\nasync function resolveAndValidateHostname(hostname) {\n const cleanHostname = hostname.replace(/^\\[|\\]$/g, \"\");\n try {\n const { address } = await dns.lookup(cleanHostname);\n if (isPrivateOrReservedIPv4(address)) {\n throw new Error(\"URLs pointing to private or internal addresses are not allowed\");\n }\n } catch (err) {\n if (err instanceof Error && err.message.includes(\"private or internal\")) {\n throw err;\n }\n throw new Error(\"Could not resolve hostname\");\n }\n}\nfunction validateUrl(url) {\n let parsed;\n try {\n parsed = new URL(url);\n } catch {\n throw new Error(\"Invalid URL\");\n }\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n throw new Error(\"Only HTTP and HTTPS URLs are allowed\");\n }\n if (isBlockedHostname(parsed.hostname)) {\n throw new Error(\"URLs pointing to private or internal addresses are not allowed\");\n }\n}\nasync function validateUrlWithDns(url) {\n validateUrl(url);\n const parsed = new URL(url);\n await resolveAndValidateHostname(parsed.hostname);\n}\nasync function fetchPage(url) {\n await validateUrlWithDns(url);\n const fetchStart = Date.now();\n const response = await fetch(url, {\n headers: {\n \"User-Agent\": \"LintPage-Bot/1.0\"\n },\n signal: AbortSignal.timeout(3e4)\n });\n const ttfbMs = Date.now() - fetchStart;\n if (!response.ok) {\n throw new Error(\n `Failed to fetch URL: ${response.status} ${response.statusText}`\n );\n }\n const html = await response.text();\n const dom = new JSDOM(html);\n return {\n document: dom.window.document,\n response,\n html,\n ttfbMs\n };\n}\n\n// src/runner.ts\nvar CATEGORY_WEIGHTS = {\n \"Pre-Launch\": 30,\n SEO: 35,\n Accessibility: 20,\n Performance: 15\n};\nfunction calculateCategoryScores(results) {\n const categoryIssues = {};\n for (const category of Object.keys(CATEGORY_WEIGHTS)) {\n categoryIssues[category] = { critical: 0, warning: 0, info: 0 };\n }\n for (const result of results) {\n const cat = result.category;\n if (!categoryIssues[cat]) {\n categoryIssues[cat] = { critical: 0, warning: 0, info: 0 };\n }\n if (result.severity === \"CRITICAL\") categoryIssues[cat].critical++;\n else if (result.severity === \"WARNING\") categoryIssues[cat].warning++;\n else categoryIssues[cat].info++;\n }\n const scores = {};\n for (const [category, weight] of Object.entries(CATEGORY_WEIGHTS)) {\n const counts = categoryIssues[category] || {\n critical: 0,\n warning: 0,\n info: 0\n };\n const deductionPercent = Math.min(\n 100,\n counts.critical * 30 + counts.warning * 5 + counts.info * 1\n );\n scores[category] = {\n score: Math.round(weight * (1 - deductionPercent / 100) * 10) / 10,\n max: weight,\n deductionPercent\n };\n }\n return scores;\n}\nfunction calculateScore(results) {\n const categoryScores = calculateCategoryScores(results);\n const total = Object.values(categoryScores).reduce(\n (sum, cat) => sum + cat.score,\n 0\n );\n return Math.round(total);\n}\nfunction runRules(rules, context, config) {\n const results = [];\n for (const rule of rules) {\n if (config?.rules) {\n const ruleConfig = config.rules[rule.meta.id];\n if (ruleConfig === false) continue;\n if (typeof ruleConfig === \"object\" && ruleConfig.enabled === false)\n continue;\n }\n try {\n const ruleResults = rule.run(context);\n results.push(...ruleResults);\n } catch (err) {\n console.warn(\n `[lintpage] Rule \"${rule.meta.id}\" threw an error: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n return results;\n}\nasync function runAsyncRules(rules, context, config) {\n const results = [];\n for (const rule of rules) {\n if (config?.rules) {\n const ruleConfig = config.rules[rule.meta.id];\n if (ruleConfig === false) continue;\n if (typeof ruleConfig === \"object\" && ruleConfig.enabled === false)\n continue;\n }\n try {\n const ruleResults = await rule.run(context);\n results.push(...ruleResults);\n } catch (err) {\n console.warn(\n `[lintpage] Async rule \"${rule.meta.id}\" threw an error: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n return results;\n}\nasync function runStandaloneRules(rules, url, config) {\n const results = [];\n for (const rule of rules) {\n if (config?.rules) {\n const ruleConfig = config.rules[rule.meta.id];\n if (ruleConfig === false) continue;\n if (typeof ruleConfig === \"object\" && ruleConfig.enabled === false)\n continue;\n }\n try {\n const ruleResults = await rule.run(url);\n results.push(...ruleResults);\n } catch (err) {\n console.warn(\n `[lintpage] Standalone rule \"${rule.meta.id}\" threw an error: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n return results;\n}\nasync function auditPage(url, options) {\n const { document, response, ttfbMs } = await fetchPage(url);\n const isHttps = url.startsWith(\"https://\");\n const context = {\n document,\n url,\n response,\n isHttps\n };\n const allRules = [...coreRules];\n const allAsyncRules = [];\n const allStandaloneRules = [];\n if (options?.plugins) {\n for (const plugin of options.plugins) {\n allRules.push(...plugin.rules);\n if (plugin.asyncRules) {\n allAsyncRules.push(...plugin.asyncRules);\n }\n if (plugin.standaloneRules) {\n allStandaloneRules.push(...plugin.standaloneRules);\n }\n }\n }\n const results = runRules(allRules, context, options?.config);\n if (allAsyncRules.length > 0) {\n const asyncResults = await runAsyncRules(\n allAsyncRules,\n context,\n options?.config\n );\n results.push(...asyncResults);\n }\n if (allStandaloneRules.length > 0) {\n const standaloneResults = await runStandaloneRules(\n allStandaloneRules,\n url,\n options?.config\n );\n results.push(...standaloneResults);\n }\n if (ttfbMs > 1800) {\n results.push({\n ruleId: \"ttfb\",\n ruleName: \"Time to First Byte\",\n message: `Slow server response time (TTFB: ${ttfbMs}ms) - aim for under 800ms`,\n severity: \"WARNING\",\n category: \"Performance\",\n tier: \"free\",\n fix: \"Optimize server response time: enable caching, use a CDN, optimize database queries, or upgrade hosting.\",\n data: { ms: ttfbMs }\n });\n } else if (ttfbMs > 800) {\n results.push({\n ruleId: \"ttfb\",\n ruleName: \"Time to First Byte\",\n message: `Server response time could be improved (TTFB: ${ttfbMs}ms) - aim for under 800ms`,\n severity: \"INFO\",\n category: \"Performance\",\n tier: \"free\",\n fix: \"Consider enabling server-side caching or using a CDN to reduce response time.\",\n data: { ms: ttfbMs }\n });\n }\n const categoryScores = calculateCategoryScores(results);\n const score = Object.values(categoryScores).reduce(\n (sum, cat) => sum + cat.score,\n 0\n );\n const hasCritical = results.some((r) => r.severity === \"CRITICAL\");\n return {\n url,\n timestamp: (/* @__PURE__ */ new Date()).toISOString(),\n results,\n score: Math.round(score),\n overallStatus: hasCritical ? \"FAIL\" : \"PASS\",\n categoryScores\n };\n}\nasync function audit(urls, options) {\n const pages = [];\n for (const url of urls) {\n const page = await auditPage(url, options);\n pages.push(page);\n }\n return {\n pages,\n timestamp: (/* @__PURE__ */ new Date()).toISOString()\n };\n}\n\n// src/config.ts\nimport { readFileSync, existsSync, statSync } from \"fs\";\nimport { join } from \"path\";\nvar CONFIG_FILES = [\n \".lintpagerc.json\",\n \".lintpagerc\",\n \"lintpage.config.json\"\n];\nfunction loadConfig(pathOrCwd) {\n const resolved = pathOrCwd || process.cwd();\n if (pathOrCwd && existsSync(pathOrCwd) && statSync(pathOrCwd).isFile()) {\n try {\n const content = readFileSync(pathOrCwd, \"utf-8\");\n return JSON.parse(content);\n } catch {\n return null;\n }\n }\n const dir = resolved;\n for (const file of CONFIG_FILES) {\n const path = join(dir, file);\n if (existsSync(path)) {\n try {\n const content = readFileSync(path, \"utf-8\");\n return JSON.parse(content);\n } catch {\n return null;\n }\n }\n }\n return null;\n}\nfunction createDefaultConfig() {\n return {\n rules: {}\n };\n}\n\n// src/utils.ts\nfunction getElementIdentifier(element, index, tagName) {\n const parts = [`${tagName} #${index + 1}`];\n const id = element.getAttribute(\"id\");\n if (id) {\n parts.push(`id=\"${id}\"`);\n }\n const classes = element.getAttribute(\"class\");\n if (classes) {\n const firstClass = classes.trim().split(/\\s+/)[0];\n if (firstClass) {\n parts.push(`class=\"${firstClass}\"`);\n }\n }\n const text = element.textContent?.trim();\n if (text && text.length > 0) {\n const preview = text.length > 40 ? text.substring(0, 40) + \"...\" : text;\n parts.push(`text=\"${preview}\"`);\n }\n return parts.join(\", \");\n}\nexport {\n audit,\n auditPage,\n calculateCategoryScores,\n calculateScore,\n canonicalUrlRule,\n coreRules,\n createDefaultConfig,\n faviconRule,\n fetchPage,\n getElementIdentifier,\n headingStructureRule,\n htmlLangRule,\n loadConfig,\n metaDescriptionRule,\n ogDescriptionRule,\n ogImageRule,\n ogTitleRule,\n ogUrlRule,\n robotsNoindexRule,\n ruleRegistry,\n runAsyncRules,\n runRules,\n runStandaloneRules,\n titleRule,\n twitterCardRule,\n validateUrl,\n viewportRule\n};\n//# sourceMappingURL=index.mjs.map","// src/rules/ssl.ts\nvar sslRule = {\n meta: {\n id: \"ssl\",\n name: \"SSL / HTTPS\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n description: \"Checks that the site is served over HTTPS\"\n },\n run(context) {\n const results = [];\n if (!context.isHttps) {\n results.push({\n ruleId: \"ssl\",\n ruleName: \"SSL / HTTPS\",\n message: \"Site is not using HTTPS - required for SEO and user trust. Search engines penalize HTTP sites.\",\n severity: \"CRITICAL\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Install an SSL certificate and redirect all HTTP traffic to HTTPS. Most hosting providers offer free SSL via Let's Encrypt.\"\n });\n }\n return results;\n }\n};\n\n// src/rules/robots-txt-check.ts\nvar robotsTxtCheckRule = {\n meta: {\n id: \"robots-txt-check\",\n name: \"robots.txt Check\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n description: \"Fetches and validates robots.txt for proper directives\"\n },\n async run(url) {\n const results = [];\n try {\n const robotsUrl = new URL(\"/robots.txt\", url).href;\n const response = await fetch(robotsUrl, {\n headers: { \"User-Agent\": \"LintPage-Bot/1.0\" }\n });\n if (!response.ok) {\n results.push({\n ruleId: \"robots-txt-check\",\n ruleName: \"robots.txt Check\",\n message: \"No robots.txt file found - recommended to have one\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: 'Create a robots.txt file at your site root with at least \"User-Agent: *\" and \"Allow: /\" directives.'\n });\n return results;\n }\n const content = await response.text();\n const lines = content.split(\"\\n\").map((line) => line.trim());\n const rules = /* @__PURE__ */ new Map();\n let currentUserAgent = \"*\";\n for (const line of lines) {\n if (!line || line.startsWith(\"#\")) continue;\n const [directive, ...valueParts] = line.split(\":\").map((part) => part.trim());\n const value = valueParts.join(\":\").trim();\n if (!directive || !value) continue;\n const upper = directive.toUpperCase();\n if (upper === \"USER-AGENT\") {\n currentUserAgent = value;\n if (!rules.has(currentUserAgent)) {\n rules.set(currentUserAgent, { disallow: [], allow: [] });\n }\n } else if (upper === \"DISALLOW\") {\n const r = rules.get(currentUserAgent) || {\n disallow: [],\n allow: []\n };\n r.disallow.push(value);\n rules.set(currentUserAgent, r);\n } else if (upper === \"ALLOW\") {\n const r = rules.get(currentUserAgent) || {\n disallow: [],\n allow: []\n };\n r.allow.push(value);\n rules.set(currentUserAgent, r);\n }\n }\n const wildcard = rules.get(\"*\");\n if (wildcard && wildcard.disallow.includes(\"/\")) {\n results.push({\n ruleId: \"robots-txt-check\",\n ruleName: \"robots.txt Check\",\n message: 'robots.txt contains \"Disallow: /\" for User-Agent: * - this blocks ALL search engines from crawling your entire site!',\n severity: \"CRITICAL\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: 'Change \"Disallow: /\" to \"Allow: /\" in your robots.txt, or remove the Disallow directive entirely.'\n });\n }\n if (!content.toLowerCase().includes(\"sitemap\")) {\n results.push({\n ruleId: \"robots-txt-check\",\n ruleName: \"robots.txt Check\",\n message: \"robots.txt does not reference sitemap.xml - consider adding a Sitemap directive\",\n severity: \"INFO\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: 'Add \"Sitemap: https://yoursite.com/sitemap.xml\" to the end of your robots.txt file.'\n });\n }\n const hasMalformedLines = lines.some((line) => {\n if (!line || line.startsWith(\"#\")) return false;\n return !line.includes(\":\") && line.length > 0;\n });\n if (hasMalformedLines) {\n results.push({\n ruleId: \"robots-txt-check\",\n ruleName: \"robots.txt Check\",\n message: 'robots.txt may have syntax errors - ensure each directive follows \"Directive: value\" format',\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: 'Review each line in robots.txt. Every directive must follow the \"Directive: value\" format (e.g., \"User-Agent: *\").'\n });\n }\n if (rules.size === 0 || rules.size === 1 && !rules.has(\"*\")) {\n results.push({\n ruleId: \"robots-txt-check\",\n ruleName: \"robots.txt Check\",\n message: \"robots.txt exists but has no rules defined - add User-Agent and Disallow/Allow directives\",\n severity: \"INFO\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: 'Add at minimum \"User-Agent: *\" followed by \"Allow: /\" to your robots.txt.'\n });\n }\n } catch {\n results.push({\n ruleId: \"robots-txt-check\",\n ruleName: \"robots.txt Check\",\n message: \"Could not fetch robots.txt - ensure it exists at root domain\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Create a robots.txt file at your domain root (e.g., https://yoursite.com/robots.txt).\"\n });\n }\n return results;\n }\n};\n\n// src/rules/sitemap-presence.ts\nvar sitemapPresenceRule = {\n meta: {\n id: \"sitemap-presence\",\n name: \"Sitemap Presence\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n description: \"Checks for the existence and validity of sitemap.xml\"\n },\n async run(url) {\n const results = [];\n try {\n const sitemapUrl = new URL(\"/sitemap.xml\", url).href;\n const response = await fetch(sitemapUrl, {\n headers: { \"User-Agent\": \"LintPage-Bot/1.0\" }\n });\n if (!response.ok) {\n results.push({\n ruleId: \"sitemap-presence\",\n ruleName: \"Sitemap Presence\",\n message: \"No sitemap.xml found - recommended for search engines to discover your pages\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Generate a sitemap.xml and place it at your domain root. Most frameworks (Next.js, WordPress) have built-in sitemap generation.\"\n });\n return results;\n }\n const content = await response.text();\n const isUrlset = content.includes(\"<urlset\");\n const isSitemapIndex = content.includes(\"<sitemapindex\");\n if (!content.includes(\"<?xml\") || !isUrlset && !isSitemapIndex) {\n results.push({\n ruleId: \"sitemap-presence\",\n ruleName: \"Sitemap Presence\",\n message: \"sitemap.xml exists but may not be valid XML format\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: 'Ensure your sitemap.xml starts with <?xml version=\"1.0\"?> and uses the <urlset> or <sitemapindex> element with proper namespace.'\n });\n }\n if (isSitemapIndex) {\n const sitemapMatches = content.match(/<sitemap>/g);\n if (!sitemapMatches || sitemapMatches.length === 0) {\n results.push({\n ruleId: \"sitemap-presence\",\n ruleName: \"Sitemap Presence\",\n message: \"Sitemap index file is empty - add child sitemap references\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Add <sitemap><loc>https://yoursite.com/sitemap-pages.xml</loc></sitemap> entries to your sitemap index.\"\n });\n }\n return results;\n }\n const urlMatches = content.match(/<loc>/g);\n const urlCount = urlMatches ? urlMatches.length : 0;\n if (urlCount === 0) {\n results.push({\n ruleId: \"sitemap-presence\",\n ruleName: \"Sitemap Presence\",\n message: \"sitemap.xml is empty - add URLs to help search engines discover content\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Add <url><loc>https://yoursite.com/page</loc></url> entries to your sitemap for each page you want indexed.\"\n });\n }\n } catch {\n results.push({\n ruleId: \"sitemap-presence\",\n ruleName: \"Sitemap Presence\",\n message: \"Could not fetch sitemap.xml - create one at /sitemap.xml\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Create a sitemap.xml at your domain root. Use a sitemap generator or your framework's built-in sitemap feature.\"\n });\n }\n return results;\n }\n};\n\n// src/rules/tracking.ts\nvar trackingRule = {\n meta: {\n id: \"tracking\",\n name: \"Analytics Tracking\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n description: \"Checks for Google Analytics, Google Tag Manager, or Facebook Pixel\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n let foundAnalytics = false;\n const scripts = document.querySelectorAll(\"script\");\n const html = document.documentElement?.outerHTML || \"\";\n scripts.forEach((script) => {\n const src = script.getAttribute(\"src\") || \"\";\n const content = script.textContent || \"\";\n if (src.includes(\"googletagmanager.com/gtag/js\") || content.includes(\"gtag(\")) {\n foundAnalytics = true;\n }\n if (src.includes(\"googletagmanager.com/gtm.js\") || content.includes(\"GTM-\")) {\n foundAnalytics = true;\n }\n if (src.includes(\"plausible.io/js/\")) {\n foundAnalytics = true;\n }\n if (src.includes(\"usefathom.com/script.js\") || src.includes(\"cdn.usefathom.com\")) {\n foundAnalytics = true;\n }\n if (src.includes(\"matomo.js\") || src.includes(\"matomo.php\") || src.includes(\"piwik.js\")) {\n foundAnalytics = true;\n }\n if (src.includes(\"posthog-js\") || src.includes(\"i.posthog.com\")) {\n foundAnalytics = true;\n }\n if (src.includes(\"cdn.mxpnl.com\") || src.includes(\"mixpanel.com\")) {\n foundAnalytics = true;\n }\n if (src.includes(\"va.vercel-scripts.com\") || src.includes(\"vitals.vercel-insights.com\")) {\n foundAnalytics = true;\n }\n if (src.includes(\"static.cloudflareinsights.com\")) {\n foundAnalytics = true;\n }\n if (src.includes(\"umami.js\") || src.includes(\"umami.is/script.js\")) {\n foundAnalytics = true;\n }\n if (src.includes(\"clarity.ms/tag\")) {\n foundAnalytics = true;\n }\n });\n if (!foundAnalytics && (html.includes(\"@vercel/analytics\") || html.includes(\"vercel-analytics\"))) {\n foundAnalytics = true;\n }\n if (!foundAnalytics) {\n results.push({\n ruleId: \"tracking\",\n ruleName: \"Analytics Tracking\",\n message: \"No analytics tracking found - you won't be able to measure traffic after launch\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Add an analytics solution to your site. Options include Google Analytics, Plausible, Fathom, Matomo, PostHog, Vercel Analytics, Umami, or Cloudflare Web Analytics.\",\n data: { foundAnalytics }\n });\n }\n return results;\n }\n};\n\n// src/rules/x-robots-tag.ts\nvar xRobotsTagRule = {\n meta: {\n id: \"x-robots-tag\",\n name: \"X-Robots-Tag Header\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n description: \"Checks the X-Robots-Tag HTTP header for noindex/nofollow\"\n },\n run(context) {\n const { response } = context;\n const results = [];\n const value = response.headers.get(\"x-robots-tag\");\n if (!value) return results;\n const lower = value.toLowerCase();\n if (lower.includes(\"noindex\")) {\n results.push({\n ruleId: \"x-robots-tag\",\n ruleName: \"X-Robots-Tag Header\",\n message: 'X-Robots-Tag HTTP header contains \"noindex\" - page will NOT be indexed by search engines!',\n severity: \"CRITICAL\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: 'Remove the X-Robots-Tag header from your server configuration, or change its value to \"index, follow\".',\n data: { value }\n });\n }\n if (lower.includes(\"nofollow\")) {\n results.push({\n ruleId: \"x-robots-tag\",\n ruleName: \"X-Robots-Tag Header\",\n message: 'X-Robots-Tag HTTP header contains \"nofollow\" - links will not be followed by search engines',\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Remove \"nofollow\" from the X-Robots-Tag header if you want search engines to follow your links.',\n data: { value }\n });\n }\n return results;\n }\n};\n\n// src/rules/thin-content.ts\nvar thinContentRule = {\n meta: {\n id: \"thin-content\",\n name: \"Thin Content\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Checks that the page has sufficient text content for search engines\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const bodyText = document.body?.textContent || \"\";\n const wordCount = bodyText.trim().split(/\\s+/).filter(Boolean).length;\n if (wordCount < 300) {\n results.push({\n ruleId: \"thin-content\",\n ruleName: \"Thin Content\",\n message: `Page has thin content (${wordCount} words) - search engines prefer pages with substantial content (300+ words)`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Add more meaningful text content to the page. Search engines rank pages with substantial, relevant content higher.\",\n data: { wordCount }\n });\n }\n return results;\n }\n};\n\n// src/rules/duplicate-meta.ts\nvar duplicateMetaRule = {\n meta: {\n id: \"duplicate-meta\",\n name: \"Duplicate Meta Tags\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Checks for duplicate title, meta description, and canonical tags\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const titleTags = document.querySelectorAll(\"title\");\n if (titleTags.length > 1) {\n results.push({\n ruleId: \"duplicate-meta\",\n ruleName: \"Duplicate Meta Tags\",\n message: `Found ${titleTags.length} <title> tags - should have exactly one`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Remove duplicate <title> tags. Keep only one in your <head> element.\",\n data: { count: titleTags.length, tag: \"title\" }\n });\n }\n const descriptionTags = document.querySelectorAll(\n 'meta[name=\"description\"]'\n );\n if (descriptionTags.length > 1) {\n results.push({\n ruleId: \"duplicate-meta\",\n ruleName: \"Duplicate Meta Tags\",\n message: `Found ${descriptionTags.length} meta description tags - should have exactly one`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Remove duplicate <meta name=\"description\"> tags. Keep only one in your <head> element.',\n data: { count: descriptionTags.length, tag: \"meta-description\" }\n });\n }\n const canonicalTags = document.querySelectorAll('link[rel=\"canonical\"]');\n if (canonicalTags.length > 1) {\n results.push({\n ruleId: \"duplicate-meta\",\n ruleName: \"Duplicate Meta Tags\",\n message: `Found ${canonicalTags.length} canonical link tags - should have exactly one`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Remove duplicate <link rel=\"canonical\"> tags. Keep only one in your <head> element.',\n data: { count: canonicalTags.length, tag: \"canonical\" }\n });\n }\n return results;\n }\n};\n\n// src/rules/structured-data.ts\nvar structuredDataRule = {\n meta: {\n id: \"structured-data\",\n name: \"Structured Data\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Checks for the presence and validity of JSON-LD structured data\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const jsonLdScripts = document.querySelectorAll(\n 'script[type=\"application/ld+json\"]'\n );\n const types = [];\n jsonLdScripts.forEach((script) => {\n try {\n const data = JSON.parse(script.textContent || \"\");\n if (Array.isArray(data[\"@graph\"])) {\n for (const item of data[\"@graph\"]) {\n if (item[\"@type\"]) {\n types.push(item[\"@type\"]);\n }\n }\n } else if (data[\"@type\"]) {\n types.push(data[\"@type\"]);\n }\n } catch {\n results.push({\n ruleId: \"structured-data\",\n ruleName: \"Structured Data\",\n message: \"Invalid JSON-LD structured data found\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Validate your JSON-LD using Google's Rich Results Test tool and fix any JSON syntax errors.\"\n });\n }\n });\n if (types.length === 0) {\n results.push({\n ruleId: \"structured-data\",\n ruleName: \"Structured Data\",\n message: \"No structured data (JSON-LD) found\",\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Add a <script type=\"application/ld+json\"> block with Organization, WebPage, or other relevant schema.org types.',\n data: { types }\n });\n }\n return results;\n }\n};\n\n// src/rules/charset.ts\nvar charsetRule = {\n meta: {\n id: \"charset\",\n name: \"Character Encoding\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Checks for a proper charset/encoding declaration\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const charsetMeta = document.querySelector(\"meta[charset]\");\n const httpEquivMeta = document.querySelector(\n 'meta[http-equiv=\"Content-Type\"]'\n );\n if (!charsetMeta && !httpEquivMeta) {\n results.push({\n ruleId: \"charset\",\n ruleName: \"Character Encoding\",\n message: \"Missing character encoding declaration - may cause rendering issues with special characters\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Add <meta charset=\"utf-8\" /> as the first element in your <head> tag.'\n });\n }\n return results;\n }\n};\n\n// src/rules/image-alt-text.ts\nvar imageAltTextRule = {\n meta: {\n id: \"image-alt-text\",\n name: \"Image Alt Text\",\n category: \"Accessibility\",\n tier: \"pro\",\n description: \"Checks that all images have alt attributes\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const images = document.querySelectorAll(\"img\");\n let missingAlt = 0;\n images.forEach((img) => {\n const alt = img.getAttribute(\"alt\");\n if (alt === null || alt === void 0) {\n missingAlt++;\n }\n });\n if (missingAlt > 0) {\n results.push({\n ruleId: \"image-alt-text\",\n ruleName: \"Image Alt Text\",\n message: `${missingAlt} of ${images.length} images missing alt attributes`,\n severity: \"WARNING\",\n category: \"Accessibility\",\n tier: \"pro\",\n fix: 'Add descriptive alt attributes to all images. Screen readers use alt text to describe images to visually impaired users. Use alt=\"\" for decorative images.',\n data: { total: images.length, missingAlt }\n });\n }\n return results;\n }\n};\n\n// src/rules/accessibility.ts\nvar accessibilityRule = {\n meta: {\n id: \"accessibility\",\n name: \"Accessibility & ARIA\",\n category: \"Accessibility\",\n tier: \"pro\",\n description: \"Checks buttons, links, inputs, and ARIA attributes for accessibility\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const buttons = document.querySelectorAll(\"button\");\n let inaccessibleButtons = 0;\n buttons.forEach((button) => {\n const hasText = button.textContent?.trim();\n const hasAriaLabel = button.getAttribute(\"aria-label\");\n const hasAriaLabelledBy = button.getAttribute(\"aria-labelledby\");\n if (!hasText && !hasAriaLabel && !hasAriaLabelledBy) {\n inaccessibleButtons++;\n }\n });\n if (inaccessibleButtons > 0) {\n results.push({\n ruleId: \"accessibility\",\n ruleName: \"Accessibility & ARIA\",\n message: `${inaccessibleButtons} button(s) missing accessible name (no text, aria-label, or aria-labelledby)`,\n severity: \"WARNING\",\n category: \"Accessibility\",\n tier: \"pro\",\n fix: \"Add visible text content, an aria-label, or aria-labelledby attribute to each button.\",\n data: { inaccessibleButtons }\n });\n }\n const links = document.querySelectorAll(\"a\");\n let inaccessibleLinks = 0;\n links.forEach((link) => {\n const hasText = link.textContent?.trim();\n const hasAriaLabel = link.getAttribute(\"aria-label\");\n const hasAriaLabelledBy = link.getAttribute(\"aria-labelledby\");\n if (!hasText && !hasAriaLabel && !hasAriaLabelledBy) {\n inaccessibleLinks++;\n }\n });\n if (inaccessibleLinks > 0) {\n results.push({\n ruleId: \"accessibility\",\n ruleName: \"Accessibility & ARIA\",\n message: `${inaccessibleLinks} link(s) missing accessible name (no text, aria-label, or aria-labelledby)`,\n severity: \"WARNING\",\n category: \"Accessibility\",\n tier: \"pro\",\n fix: \"Add descriptive text content, an aria-label, or aria-labelledby attribute to each link so screen readers can identify it.\",\n data: { inaccessibleLinks }\n });\n }\n const inputs = document.querySelectorAll(\"input:not([type='hidden'])\");\n let unlabeledInputs = 0;\n inputs.forEach((input) => {\n const id = input.getAttribute(\"id\");\n const ariaLabel = input.getAttribute(\"aria-label\");\n const ariaLabelledBy = input.getAttribute(\"aria-labelledby\");\n const title = input.getAttribute(\"title\");\n const hasExplicitLabel = id && document.querySelector(`label[for=\"${id}\"]`);\n const hasImplicitLabel = input.closest(\"label\") !== null;\n if (!hasExplicitLabel && !hasImplicitLabel && !ariaLabel && !ariaLabelledBy && !title) {\n unlabeledInputs++;\n }\n });\n if (unlabeledInputs > 0) {\n results.push({\n ruleId: \"accessibility\",\n ruleName: \"Accessibility & ARIA\",\n message: `${unlabeledInputs} input(s) missing associated label`,\n severity: \"WARNING\",\n category: \"Accessibility\",\n tier: \"pro\",\n fix: 'Add a <label for=\"inputId\"> element, or add an aria-label attribute to each input.',\n data: { unlabeledInputs }\n });\n }\n const divButtons = document.querySelectorAll(\n \"div[onclick], span[onclick]\"\n );\n let missingRoles = 0;\n divButtons.forEach((el) => {\n if (!el.getAttribute(\"role\")) missingRoles++;\n });\n if (missingRoles > 0) {\n results.push({\n ruleId: \"accessibility\",\n ruleName: \"Accessibility & ARIA\",\n message: `${missingRoles} interactive div/span element(s) missing role attribute`,\n severity: \"WARNING\",\n category: \"Accessibility\",\n tier: \"pro\",\n fix: 'Use a <button> element instead, or add role=\"button\" and an aria-label to interactive elements.',\n data: { missingRoles }\n });\n }\n const navElements = document.querySelectorAll(\n 'nav, [role=\"navigation\"]'\n );\n let unlabeledNav = 0;\n navElements.forEach((nav) => {\n const ariaLabel = nav.getAttribute(\"aria-label\");\n const ariaLabelledBy = nav.getAttribute(\"aria-labelledby\");\n if (!ariaLabel && !ariaLabelledBy) unlabeledNav++;\n });\n if (unlabeledNav > 0) {\n results.push({\n ruleId: \"accessibility\",\n ruleName: \"Accessibility & ARIA\",\n message: `${unlabeledNav} navigation element(s) missing aria-label or aria-labelledby`,\n severity: \"INFO\",\n category: \"Accessibility\",\n tier: \"pro\",\n fix: 'Add aria-label=\"Main navigation\" (or similar descriptive label) to your <nav> elements.',\n data: { unlabeledNav }\n });\n }\n return results;\n }\n};\n\n// src/rules/semantic-structure.ts\nvar semanticStructureRule = {\n meta: {\n id: \"semantic-structure\",\n name: \"Semantic Structure\",\n category: \"Accessibility\",\n tier: \"pro\",\n description: \"Checks for proper semantic HTML: landmarks, lists, tables, articles\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const main = document.querySelector(\"main\");\n if (!main) {\n results.push({\n ruleId: \"semantic-structure\",\n ruleName: \"Semantic Structure\",\n message: \"Missing <main> element - should wrap primary page content for better structure\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Wrap your primary page content in a <main> element. There should be exactly one per page.\"\n });\n }\n const semanticElements = document.querySelectorAll(\n \"main, section, article, aside, nav\"\n );\n if (semanticElements.length === 0) {\n results.push({\n ruleId: \"semantic-structure\",\n ruleName: \"Semantic Structure\",\n message: \"Missing semantic page regions - use <main>, <section>, <article>, <nav>, <aside> instead of generic divs\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Replace generic <div> containers with semantic elements: <main>, <nav>, <section>, <article>, <aside>.\"\n });\n }\n const listItems = document.querySelectorAll(\"li\");\n let orphanedLi = 0;\n listItems.forEach((li) => {\n const parent = li.parentElement;\n if (parent?.tagName !== \"UL\" && parent?.tagName !== \"OL\") {\n orphanedLi++;\n }\n });\n if (orphanedLi > 0) {\n results.push({\n ruleId: \"semantic-structure\",\n ruleName: \"Semantic Structure\",\n message: `${orphanedLi} <li> element(s) found outside of <ul> or <ol> - breaks semantic structure`,\n severity: \"WARNING\",\n category: \"Accessibility\",\n tier: \"pro\",\n fix: \"Wrap <li> elements inside a <ul> (unordered) or <ol> (ordered) list element.\",\n data: { orphanedLi }\n });\n }\n const tables = document.querySelectorAll(\"table\");\n let tablesWithoutHeaders = 0;\n tables.forEach((table) => {\n if (!table.querySelector(\"th\")) tablesWithoutHeaders++;\n });\n if (tablesWithoutHeaders > 0) {\n results.push({\n ruleId: \"semantic-structure\",\n ruleName: \"Semantic Structure\",\n message: `${tablesWithoutHeaders} table(s) missing <th> header cells`,\n severity: \"INFO\",\n category: \"Accessibility\",\n tier: \"pro\",\n fix: \"Add <th> cells to define table column or row headers. Optionally wrap them in a <thead> element for additional structure.\",\n data: { tablesWithoutHeaders }\n });\n }\n const articles = document.querySelectorAll(\"article\");\n let articlesWithoutHeading = 0;\n articles.forEach((article) => {\n if (!article.querySelector(\"h1, h2, h3, h4, h5, h6\")) {\n articlesWithoutHeading++;\n }\n });\n if (articlesWithoutHeading > 0) {\n results.push({\n ruleId: \"semantic-structure\",\n ruleName: \"Semantic Structure\",\n message: `${articlesWithoutHeading} <article> element(s) without a heading`,\n severity: \"INFO\",\n category: \"Accessibility\",\n tier: \"pro\",\n fix: \"Add a heading (h2-h6) inside each <article> element to provide context.\",\n data: { articlesWithoutHeading }\n });\n }\n return results;\n }\n};\n\n// src/rules/performance.ts\nvar performanceRule = {\n meta: {\n id: \"performance\",\n name: \"Performance Hints\",\n category: \"Performance\",\n tier: \"pro\",\n description: \"Checks for inline styles, lazy loading, and script count\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const images = document.querySelectorAll(\"img\");\n const belowFoldImages = Array.from(images).slice(3);\n let noLazyLoad = 0;\n belowFoldImages.forEach((img) => {\n if (!img.getAttribute(\"loading\")) noLazyLoad++;\n });\n if (noLazyLoad > 0) {\n results.push({\n ruleId: \"performance\",\n ruleName: \"Performance Hints\",\n message: `${noLazyLoad} below-the-fold image(s) without loading=\"lazy\" - add lazy loading to defer offscreen images`,\n severity: \"INFO\",\n category: \"Performance\",\n tier: \"pro\",\n fix: 'Add loading=\"lazy\" to images below the fold. Do NOT add loading=\"lazy\" to above-the-fold or LCP images - this hurts performance (per web.dev).',\n data: { noLazyLoad, totalImages: images.length }\n });\n }\n const scripts = document.querySelectorAll(\"script[src]\");\n if (scripts.length > 10) {\n results.push({\n ruleId: \"performance\",\n ruleName: \"Performance Hints\",\n message: `Consider reducing external scripts (${scripts.length} found) for better performance`,\n severity: \"INFO\",\n category: \"Performance\",\n tier: \"pro\",\n fix: \"Audit your scripts and remove unused ones. Consider bundling or deferring non-critical scripts.\",\n data: { scriptCount: scripts.length }\n });\n }\n return results;\n }\n};\n\n// src/rules/image-dimensions.ts\nvar imageDimensionsRule = {\n meta: {\n id: \"image-dimensions\",\n name: \"Image Dimensions\",\n category: \"Performance\",\n tier: \"pro\",\n description: \"Checks that images have explicit width and height to prevent layout shift (CLS)\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const images = document.querySelectorAll(\"img\");\n let missingCount = 0;\n images.forEach((img) => {\n const hasWidth = img.getAttribute(\"width\");\n const hasHeight = img.getAttribute(\"height\");\n if (!hasWidth || !hasHeight) missingCount++;\n });\n if (missingCount > 0) {\n results.push({\n ruleId: \"image-dimensions\",\n ruleName: \"Image Dimensions\",\n message: `${missingCount} image${missingCount !== 1 ? \"s\" : \"\"} missing explicit width/height attributes - causes layout shift (CLS)`,\n severity: \"INFO\",\n category: \"Performance\",\n tier: \"pro\",\n fix: \"Add width and height attributes to <img> tags to reserve space and prevent layout shift.\",\n data: { missingCount, totalImages: images.length }\n });\n }\n return results;\n }\n};\n\n// src/rules/ttfb.ts\nvar ttfbRule = {\n meta: {\n id: \"ttfb-pro\",\n name: \"Time to First Byte (Pro)\",\n category: \"Performance\",\n tier: \"pro\",\n description: \"Measures server response time (TTFB) with detailed thresholds\"\n },\n async run(url) {\n const results = [];\n try {\n const start = Date.now();\n await fetch(url, {\n headers: { \"User-Agent\": \"LintPage-Bot/1.0\" }\n });\n const ttfbMs = Date.now() - start;\n if (ttfbMs > 1800) {\n results.push({\n ruleId: \"ttfb-pro\",\n ruleName: \"Time to First Byte (Pro)\",\n message: `Slow server response time (TTFB: ${ttfbMs}ms) - aim for under 800ms`,\n severity: \"WARNING\",\n category: \"Performance\",\n tier: \"pro\",\n fix: \"Optimize server response time: enable caching, use a CDN, optimize database queries, or upgrade hosting.\",\n data: { ms: ttfbMs }\n });\n } else if (ttfbMs > 800) {\n results.push({\n ruleId: \"ttfb-pro\",\n ruleName: \"Time to First Byte (Pro)\",\n message: `Server response time could be improved (TTFB: ${ttfbMs}ms) - aim for under 800ms`,\n severity: \"INFO\",\n category: \"Performance\",\n tier: \"pro\",\n fix: \"Consider enabling server-side caching or using a CDN to reduce response time.\",\n data: { ms: ttfbMs }\n });\n }\n } catch {\n results.push({\n ruleId: \"ttfb-pro\",\n ruleName: \"Time to First Byte (Pro)\",\n message: \"Could not measure TTFB - server may be unreachable\",\n severity: \"WARNING\",\n category: \"Performance\",\n tier: \"pro\",\n fix: \"Ensure your server is accessible and responding to requests.\"\n });\n }\n return results;\n }\n};\n\n// src/rules/mixed-content.ts\nvar mixedContentRule = {\n meta: {\n id: \"mixed-content\",\n name: \"Mixed Content\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n description: \"Checks for HTTP resources loaded on an HTTPS page (mixed content)\"\n },\n run(context) {\n const { document, isHttps } = context;\n const results = [];\n if (!isHttps) return results;\n const selectors = [\n 'img[src^=\"http:\"]',\n 'script[src^=\"http:\"]',\n 'link[href^=\"http:\"]',\n 'iframe[src^=\"http:\"]',\n 'video[src^=\"http:\"]',\n 'audio[src^=\"http:\"]',\n 'object[data^=\"http:\"]',\n 'source[src^=\"http:\"]'\n ];\n let count = 0;\n selectors.forEach((selector) => {\n count += document.querySelectorAll(selector).length;\n });\n if (count > 0) {\n results.push({\n ruleId: \"mixed-content\",\n ruleName: \"Mixed Content\",\n message: `Found ${count} mixed content resource${count !== 1 ? \"s\" : \"\"} (HTTP on HTTPS page) - browsers may block these`,\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Change all resource URLs from http:// to https:// or use protocol-relative URLs (//).\",\n data: { count }\n });\n }\n return results;\n }\n};\n\n// src/rules/security-headers.ts\nvar securityHeadersRule = {\n meta: {\n id: \"security-headers\",\n name: \"Security Headers\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n description: \"Checks for important security headers (CSP, HSTS, X-Content-Type-Options, Permissions-Policy)\"\n },\n run(context) {\n const { response } = context;\n const results = [];\n const headers = [\n { name: \"content-security-policy\", label: \"Content-Security-Policy\" },\n {\n name: \"strict-transport-security\",\n label: \"Strict-Transport-Security (HSTS)\"\n },\n { name: \"x-content-type-options\", label: \"X-Content-Type-Options\" },\n { name: \"permissions-policy\", label: \"Permissions-Policy\" }\n ];\n const missing = [];\n headers.forEach(({ name, label }) => {\n if (!response.headers.get(name)) missing.push(label);\n });\n if (missing.length > 0) {\n results.push({\n ruleId: \"security-headers\",\n ruleName: \"Security Headers\",\n message: `Missing security headers: ${missing.join(\", \")}`,\n severity: \"INFO\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Configure your server or hosting provider to send these security headers. Most can be set in next.config.js headers() or your CDN settings.\",\n data: { missing }\n });\n }\n return results;\n }\n};\n\n// src/rules/og-image-size.ts\nvar ogImageSizeRule = {\n meta: {\n id: \"og-image-size\",\n name: \"OG Image Size\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Checks that the og:image URL exists and advises on recommended dimensions (1200x630)\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const ogImage = document.querySelector('meta[property=\"og:image\"]');\n const imageUrl = ogImage?.getAttribute(\"content\")?.trim();\n if (!imageUrl) return results;\n const ogWidth = document.querySelector('meta[property=\"og:image:width\"]');\n const ogHeight = document.querySelector(\n 'meta[property=\"og:image:height\"]'\n );\n const width = Number.parseInt(\n ogWidth?.getAttribute(\"content\") || \"\",\n 10\n );\n const height = Number.parseInt(\n ogHeight?.getAttribute(\"content\") || \"\",\n 10\n );\n if (!ogWidth || !ogHeight || Number.isNaN(width) || Number.isNaN(height)) {\n results.push({\n ruleId: \"og-image-size\",\n ruleName: \"OG Image Size\",\n message: \"Missing og:image:width and og:image:height meta tags - social platforms may crop your image incorrectly\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Add <meta property=\"og:image:width\" content=\"1200\" /> and <meta property=\"og:image:height\" content=\"630\" /> to your <head>.'\n });\n return results;\n }\n if (width < 1200 || height < 630) {\n results.push({\n ruleId: \"og-image-size\",\n ruleName: \"OG Image Size\",\n message: `OG image dimensions (${width}x${height}) are below recommended 1200x630 - may appear blurry on social platforms`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Use an image at least 1200x630 pixels for best display on Facebook, LinkedIn, and other social platforms.\",\n data: { width, height }\n });\n }\n return results;\n }\n};\n\n// src/rules/og-image-type.ts\nvar SUPPORTED_TYPES = /* @__PURE__ */ new Set([\n \"image/jpeg\",\n \"image/png\",\n \"image/gif\",\n \"image/webp\"\n]);\nvar SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([\n \".jpg\",\n \".jpeg\",\n \".png\",\n \".gif\",\n \".webp\"\n]);\nvar ogImageTypeRule = {\n meta: {\n id: \"og-image-type\",\n name: \"OG Image Type\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Checks that the og:image type is a widely-supported format (JPEG, PNG, GIF, WebP)\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const ogImage = document.querySelector('meta[property=\"og:image\"]');\n const imageUrl = ogImage?.getAttribute(\"content\")?.trim();\n if (!imageUrl) return results;\n const ogType = document.querySelector('meta[property=\"og:image:type\"]')?.getAttribute(\"content\")?.trim();\n if (ogType && !SUPPORTED_TYPES.has(ogType.toLowerCase())) {\n results.push({\n ruleId: \"og-image-type\",\n ruleName: \"OG Image Type\",\n message: `OG image type \"${ogType}\" may not be supported by all social platforms`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Use JPEG or PNG for og:image. These formats are supported by all social platforms.\",\n data: { type: ogType }\n });\n return results;\n }\n if (!ogType) {\n try {\n const url = new URL(imageUrl, \"https://example.com\");\n const ext = url.pathname.substring(url.pathname.lastIndexOf(\".\")).toLowerCase();\n if (ext && !SUPPORTED_EXTENSIONS.has(ext)) {\n results.push({\n ruleId: \"og-image-type\",\n ruleName: \"OG Image Type\",\n message: `OG image URL has extension \"${ext}\" which may not be supported by all social platforms`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Use JPEG or PNG for og:image, and add <meta property=\"og:image:type\" content=\"image/jpeg\" /> to your <head>.',\n data: { extension: ext }\n });\n }\n } catch {\n }\n }\n return results;\n }\n};\n\n// src/rules/twitter-image.ts\nvar twitterImageRule = {\n meta: {\n id: \"twitter-image\",\n name: \"Twitter/X Image\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Checks for twitter:image meta tag for rich card previews on X/Twitter\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const twitterCard = document.querySelector('meta[name=\"twitter:card\"]');\n if (!twitterCard) return results;\n const twitterImage = document.querySelector(\n 'meta[name=\"twitter:image\"]'\n );\n const ogImage = document.querySelector('meta[property=\"og:image\"]');\n if (!twitterImage && !ogImage) {\n results.push({\n ruleId: \"twitter-image\",\n ruleName: \"Twitter/X Image\",\n message: \"Twitter card present but no twitter:image or og:image found - tweets will have no image preview\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Add <meta name=\"twitter:image\" content=\"https://yoursite.com/image.png\" /> to your <head>.'\n });\n } else if (!twitterImage && ogImage) {\n results.push({\n ruleId: \"twitter-image\",\n ruleName: \"Twitter/X Image\",\n message: \"No explicit twitter:image - falling back to og:image. Consider adding twitter:image for optimal display.\",\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Add <meta name=\"twitter:image\" content=\"...\" /> for more control over how your image appears on X/Twitter.'\n });\n }\n return results;\n }\n};\n\n// src/rules/social-preview-render.ts\nvar socialPreviewRenderRule = {\n meta: {\n id: \"social-preview-render\",\n name: \"Social Preview Completeness\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Checks that all essential meta tags for social sharing previews are present and consistent\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const ogTitle = document.querySelector('meta[property=\"og:title\"]')?.getAttribute(\"content\");\n const ogDesc = document.querySelector('meta[property=\"og:description\"]')?.getAttribute(\"content\");\n const ogImage = document.querySelector('meta[property=\"og:image\"]')?.getAttribute(\"content\");\n const ogUrl = document.querySelector('meta[property=\"og:url\"]')?.getAttribute(\"content\");\n const ogType = document.querySelector('meta[property=\"og:type\"]')?.getAttribute(\"content\");\n const title = document.querySelector(\"title\")?.textContent?.trim();\n const metaDesc = document.querySelector('meta[name=\"description\"]')?.getAttribute(\"content\");\n if (!ogType) {\n results.push({\n ruleId: \"social-preview-render\",\n ruleName: \"Social Preview Completeness\",\n message: \"Missing og:type meta tag - required by the Open Graph protocol and needed for correct social preview rendering\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Add <meta property=\"og:type\" content=\"website\" /> (or \"article\" for blog posts) to your <head>. This is a required property per the Open Graph protocol.'\n });\n }\n if (ogImage && ogImage.trim()) {\n const ogImageAlt = document.querySelector('meta[property=\"og:image:alt\"]')?.getAttribute(\"content\");\n if (!ogImageAlt) {\n results.push({\n ruleId: \"social-preview-render\",\n ruleName: \"Social Preview Completeness\",\n message: \"Missing og:image:alt - the Open Graph protocol recommends providing alt text when og:image is set\",\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Add <meta property=\"og:image:alt\" content=\"Description of the image\" /> to your <head> for accessibility.'\n });\n }\n }\n if (ogTitle && title && ogTitle.length > 0 && title.length > 0) {\n if (ogTitle.length > 60) {\n results.push({\n ruleId: \"social-preview-render\",\n ruleName: \"Social Preview Completeness\",\n message: `og:title is ${ogTitle.length} characters - may be truncated on social platforms (recommended: 50-60)`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Keep og:title under 60 characters for best display on social platforms.\",\n data: { ogTitleLength: ogTitle.length }\n });\n }\n }\n if (ogDesc && ogDesc.length > 200) {\n results.push({\n ruleId: \"social-preview-render\",\n ruleName: \"Social Preview Completeness\",\n message: `og:description is ${ogDesc.length} characters - may be truncated on social platforms (recommended: under 200)`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Keep og:description under 200 characters for best display on social platforms.\",\n data: { ogDescLength: ogDesc.length }\n });\n }\n if (ogUrl && !ogUrl.startsWith(\"http\")) {\n results.push({\n ruleId: \"social-preview-render\",\n ruleName: \"Social Preview Completeness\",\n message: \"og:url should be an absolute URL starting with https://\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Change og:url to an absolute URL (e.g., https://yoursite.com/page).\"\n });\n }\n if (ogImage && !ogImage.startsWith(\"http\")) {\n results.push({\n ruleId: \"social-preview-render\",\n ruleName: \"Social Preview Completeness\",\n message: \"og:image should be an absolute URL starting with https://\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Change og:image to an absolute URL (e.g., https://yoursite.com/image.png).\"\n });\n }\n return results;\n }\n};\n\n// src/rules/title-keyword-stuffing.ts\nvar titleKeywordStuffingRule = {\n meta: {\n id: \"title-keyword-stuffing\",\n name: \"Title Keyword Stuffing\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Detects potential keyword stuffing in the page title\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const title = document.querySelector(\"title\")?.textContent?.trim();\n if (!title) return results;\n const words = title.toLowerCase().split(/[\\s\\-|:,]+/).filter((w) => w.length > 3);\n const wordCounts = /* @__PURE__ */ new Map();\n for (const word of words) {\n wordCounts.set(word, (wordCounts.get(word) || 0) + 1);\n }\n const stuffedWords = [];\n for (const [word, count] of wordCounts) {\n if (count >= 3) stuffedWords.push(`\"${word}\" (${count}x)`);\n }\n if (stuffedWords.length > 0) {\n results.push({\n ruleId: \"title-keyword-stuffing\",\n ruleName: \"Title Keyword Stuffing\",\n message: `Potential keyword stuffing in title: ${stuffedWords.join(\", \")}`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Write a natural, readable title. Avoid repeating the same keyword more than twice. Search engines may penalize keyword stuffing.\",\n data: { title, stuffedWords }\n });\n }\n const separatorCount = (title.match(/[|–—]/g) || []).length;\n if (separatorCount >= 3) {\n results.push({\n ruleId: \"title-keyword-stuffing\",\n ruleName: \"Title Keyword Stuffing\",\n message: `Title has ${separatorCount} separators - may appear spammy to search engines`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Simplify your title. Use at most one separator (|, \\u2013 or \\u2014) to separate the page name from your brand.\",\n data: { separatorCount }\n });\n }\n return results;\n }\n};\n\n// src/rules/content-to-html-ratio.ts\nvar contentToHtmlRatioRule = {\n meta: {\n id: \"content-to-html-ratio\",\n name: \"Content-to-HTML Ratio\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Checks the ratio of visible text to total HTML markup\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const htmlLength = document.documentElement?.outerHTML?.length || 0;\n if (htmlLength === 0) return results;\n const textContent = document.body?.textContent || \"\";\n const textLength = textContent.replace(/\\s+/g, \" \").trim().length;\n const ratio = Math.round(textLength / htmlLength * 100);\n if (ratio < 10) {\n results.push({\n ruleId: \"content-to-html-ratio\",\n ruleName: \"Content-to-HTML Ratio\",\n message: `Low content-to-HTML ratio (${ratio}%) - may indicate excessive markup or thin content`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Increase meaningful text content or reduce unnecessary HTML markup. Note: content-to-HTML ratio is not a direct ranking factor per Google, but correlates with page speed and code quality.\",\n data: { ratio, textLength, htmlLength }\n });\n } else if (ratio < 20) {\n results.push({\n ruleId: \"content-to-html-ratio\",\n ruleName: \"Content-to-HTML Ratio\",\n message: `Content-to-HTML ratio is ${ratio}% - could be improved (aim for 25%+)`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Consider adding more text content or reducing unnecessary HTML markup to improve the ratio.\",\n data: { ratio, textLength, htmlLength }\n });\n }\n return results;\n }\n};\n\n// src/rules/title-uniqueness.ts\nvar titleUniquenessRule = {\n meta: {\n id: \"title-uniqueness\",\n name: \"Title Uniqueness\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Flags titles that appear generic or auto-generated (single-page heuristic)\"\n },\n run(context) {\n const { document, url } = context;\n const results = [];\n const title = document.querySelector(\"title\")?.textContent?.trim();\n if (!title) return results;\n const genericPatterns = [\n /^home$/i,\n /^untitled/i,\n /^page \\d+$/i,\n /^welcome$/i,\n /^index$/i,\n /^document$/i,\n /^my site$/i,\n /^my website$/i,\n /^website$/i,\n /^new page$/i\n ];\n for (const pattern of genericPatterns) {\n if (pattern.test(title)) {\n results.push({\n ruleId: \"title-uniqueness\",\n ruleName: \"Title Uniqueness\",\n message: `Title \"${title}\" appears to be a generic/default title - use a unique, descriptive title`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Write a unique, descriptive title for each page that includes your target keyword.\",\n data: { title }\n });\n break;\n }\n }\n try {\n const hostname = new URL(url).hostname.replace(\"www.\", \"\");\n const domainName = hostname.split(\".\")[0];\n if (domainName && title.toLowerCase() === domainName.toLowerCase()) {\n results.push({\n ruleId: \"title-uniqueness\",\n ruleName: \"Title Uniqueness\",\n message: \"Title is just the domain name - add a descriptive page-specific title\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Include a page-specific description in your title, e.g., \"Product Name \\u2014 Your Brand\".',\n data: { title, hostname }\n });\n }\n } catch {\n }\n return results;\n }\n};\n\n// src/rules/description-uniqueness.ts\nvar descriptionUniquenessRule = {\n meta: {\n id: \"description-uniqueness\",\n name: \"Description Uniqueness\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Flags meta descriptions that appear generic or auto-generated (single-page heuristic)\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const metaDesc = document.querySelector('meta[name=\"description\"]');\n const description = metaDesc?.getAttribute(\"content\")?.trim();\n if (!description) return results;\n const genericPatterns = [\n /^welcome to/i,\n /^this is a website/i,\n /^a website about/i,\n /^home page/i,\n /^we are a company/i,\n /^default description/i\n ];\n for (const pattern of genericPatterns) {\n if (pattern.test(description)) {\n results.push({\n ruleId: \"description-uniqueness\",\n ruleName: \"Description Uniqueness\",\n message: `Meta description appears generic - write a unique, compelling description for this page`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Write a unique meta description for each page that summarizes the specific content and includes a call to action.\",\n data: { description }\n });\n break;\n }\n }\n const title = document.querySelector(\"title\")?.textContent?.trim();\n if (title && description.toLowerCase() === title.toLowerCase()) {\n results.push({\n ruleId: \"description-uniqueness\",\n ruleName: \"Description Uniqueness\",\n message: \"Meta description is identical to the title - they should be different and complementary\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Write a meta description that expands on your title with more detail, a value proposition, or a call to action.\",\n data: { description, title }\n });\n }\n return results;\n }\n};\n\n// src/rules/structured-data-validate.ts\nvar REQUIRED_FIELDS = {\n Organization: [\"name\", \"url\"],\n WebSite: [\"name\", \"url\"],\n WebPage: [\"name\"],\n BreadcrumbList: [\"itemListElement\"],\n LocalBusiness: [\"name\", \"address\"]\n};\nvar RECOMMENDED_FIELDS = {\n Article: [\"headline\", \"author\", \"datePublished\"],\n Product: [\"name\", \"image\", \"offers\"]\n};\nfunction validateJsonLdItem(data, inheritedContext, results) {\n const type = data[\"@type\"];\n if (!type) {\n results.push({\n ruleId: \"structured-data-validate\",\n ruleName: \"Structured Data Validation\",\n message: \"JSON-LD block missing @type property\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Add an @type property (e.g., \"Organization\", \"WebPage\", \"Article\") to your JSON-LD.'\n });\n return;\n }\n const context = data[\"@context\"] || inheritedContext;\n if (!context) {\n results.push({\n ruleId: \"structured-data-validate\",\n ruleName: \"Structured Data Validation\",\n message: `JSON-LD \"${type}\" missing @context - should be \"https://schema.org\"`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Add \"@context\": \"https://schema.org\" to your JSON-LD block.',\n data: { type }\n });\n }\n const required = REQUIRED_FIELDS[type];\n if (required) {\n const missing = required.filter((field) => !data[field]);\n if (missing.length > 0) {\n results.push({\n ruleId: \"structured-data-validate\",\n ruleName: \"Structured Data Validation\",\n message: `JSON-LD \"${type}\" missing required fields: ${missing.join(\", \")}`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: `Add the missing fields to your ${type} schema: ${missing.join(\", \")}.`,\n data: { type, missing }\n });\n }\n }\n const recommended = RECOMMENDED_FIELDS[type];\n if (recommended) {\n const missing = recommended.filter((field) => !data[field]);\n if (missing.length > 0) {\n results.push({\n ruleId: \"structured-data-validate\",\n ruleName: \"Structured Data Validation\",\n message: `JSON-LD \"${type}\" missing recommended fields: ${missing.join(\", \")}`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: `Add the recommended fields to your ${type} schema for richer search results: ${missing.join(\", \")}.`,\n data: { type, missing }\n });\n }\n }\n if (type === \"FAQPage\") {\n results.push({\n ruleId: \"structured-data-validate\",\n ruleName: \"Structured Data Validation\",\n message: \"FAQPage rich results are only shown for well-known, authoritative government and health websites. For all other sites, this rich result will no longer be shown regularly\",\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"You can keep or remove this markup. Unused structured data does not cause problems for Search, but it also has no visible effects in Google Search. Consider using other structured data types that still produce rich results for your site type.\",\n data: { type }\n });\n }\n}\nvar structuredDataValidateRule = {\n meta: {\n id: \"structured-data-validate\",\n name: \"Structured Data Validation\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Validates JSON-LD structured data for required fields based on schema type\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const jsonLdScripts = document.querySelectorAll(\n 'script[type=\"application/ld+json\"]'\n );\n jsonLdScripts.forEach((script) => {\n let data;\n try {\n data = JSON.parse(script.textContent || \"\");\n } catch {\n return;\n }\n if (Array.isArray(data[\"@graph\"])) {\n const rootContext = data[\"@context\"];\n for (const item of data[\"@graph\"]) {\n validateJsonLdItem(item, rootContext, results);\n }\n return;\n }\n validateJsonLdItem(data, void 0, results);\n });\n return results;\n }\n};\n\n// src/rules/hreflang.ts\nvar hreflangRule = {\n meta: {\n id: \"hreflang\",\n name: \"Hreflang Tags\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Validates hreflang tags for multi-language pages\"\n },\n run(context) {\n const { document, url } = context;\n const results = [];\n const hreflangTags = document.querySelectorAll(\n 'link[rel=\"alternate\"][hreflang]'\n );\n if (hreflangTags.length === 0) return results;\n const hasXDefault = Array.from(hreflangTags).some(\n (tag) => tag.getAttribute(\"hreflang\") === \"x-default\"\n );\n if (!hasXDefault) {\n results.push({\n ruleId: \"hreflang\",\n ruleName: \"Hreflang Tags\",\n message: \"Hreflang tags found but missing x-default - add a fallback for unmatched languages\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Add <link rel=\"alternate\" hreflang=\"x-default\" href=\"...\" /> to specify the default/fallback page.'\n });\n }\n const hasSelfRef = Array.from(hreflangTags).some((tag) => {\n const href = tag.getAttribute(\"href\");\n return href === url || href === url.replace(/\\/$/, \"\");\n });\n if (!hasSelfRef) {\n results.push({\n ruleId: \"hreflang\",\n ruleName: \"Hreflang Tags\",\n message: \"Hreflang tags do not include a self-referencing tag for the current page\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Add a hreflang tag that points to the current page URL with the appropriate language code.\"\n });\n }\n const langCodePattern = /^[a-z]{2}(-[A-Z]{2})?$/;\n hreflangTags.forEach((tag) => {\n const lang = tag.getAttribute(\"hreflang\");\n if (lang && lang !== \"x-default\" && !langCodePattern.test(lang)) {\n results.push({\n ruleId: \"hreflang\",\n ruleName: \"Hreflang Tags\",\n message: `Invalid hreflang language code \"${lang}\" - use ISO 639-1 format (e.g., \"en\", \"en-US\")`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: `Change \"${lang}\" to a valid ISO 639-1 language code (e.g., \"en\", \"fr\", \"de-AT\").`,\n data: { invalidLang: lang }\n });\n }\n const href = tag.getAttribute(\"href\");\n if (href && !href.startsWith(\"http\")) {\n results.push({\n ruleId: \"hreflang\",\n ruleName: \"Hreflang Tags\",\n message: `Hreflang href should be an absolute URL (found: \"${href}\")`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Use absolute URLs (starting with https://) for all hreflang href attributes.\"\n });\n }\n });\n return results;\n }\n};\n\n// src/rules/canonical-self-referencing.ts\nvar canonicalSelfReferencingRule = {\n meta: {\n id: \"canonical-self-referencing\",\n name: \"Canonical Self-Referencing\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Checks that the canonical URL points to the current page (self-referencing canonical)\"\n },\n run(context) {\n const { document, url } = context;\n const results = [];\n const canonical = document.querySelector('link[rel=\"canonical\"]');\n if (!canonical) return results;\n const href = canonical.getAttribute(\"href\")?.trim();\n if (!href) return results;\n const normalize = (u) => u.replace(/\\/$/, \"\").toLowerCase();\n try {\n const canonicalUrl = new URL(href, url).href;\n const normalizedCanonical = normalize(canonicalUrl);\n const normalizedUrl = normalize(url);\n if (normalizedCanonical !== normalizedUrl) {\n const sameHost = new URL(canonicalUrl).hostname === new URL(url).hostname;\n if (sameHost) {\n results.push({\n ruleId: \"canonical-self-referencing\",\n ruleName: \"Canonical Self-Referencing\",\n message: `Canonical URL points to a different page on the same site - this tells search engines to index \"${canonicalUrl}\" instead of this page`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"If this page should be indexed, change the canonical to point to itself. If this is intentional (e.g., pagination), you can ignore this.\",\n data: { canonical: canonicalUrl, pageUrl: url }\n });\n } else {\n results.push({\n ruleId: \"canonical-self-referencing\",\n ruleName: \"Canonical Self-Referencing\",\n message: `Canonical URL points to a different domain (\"${new URL(canonicalUrl).hostname}\") - this is unusual and may be a misconfiguration`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Cross-domain canonical tags are rarely correct. Verify this is intentional, otherwise change the canonical to point to this page.\",\n data: { canonical: canonicalUrl, pageUrl: url }\n });\n }\n }\n } catch {\n results.push({\n ruleId: \"canonical-self-referencing\",\n ruleName: \"Canonical Self-Referencing\",\n message: `Cannot parse canonical URL \"${href}\" - ensure it's a valid absolute URL`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Use a valid absolute URL for your canonical tag (e.g., https://yoursite.com/page).\"\n });\n }\n return results;\n }\n};\n\n// src/rules/meta-render-blocking.ts\nvar metaRenderBlockingRule = {\n meta: {\n id: \"meta-render-blocking\",\n name: \"Render-Blocking Resources\",\n category: \"Performance\",\n tier: \"pro\",\n description: \"Checks for render-blocking stylesheets and synchronous scripts in the <head>\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const head = document.querySelector(\"head\");\n if (!head) return results;\n const headScripts = head.querySelectorAll(\"script[src]\");\n let blockingScripts = 0;\n headScripts.forEach((script) => {\n const hasAsync = script.hasAttribute(\"async\");\n const hasDefer = script.hasAttribute(\"defer\");\n const type = script.getAttribute(\"type\");\n if (!hasAsync && !hasDefer && type !== \"module\") {\n blockingScripts++;\n }\n });\n if (blockingScripts > 0) {\n results.push({\n ruleId: \"meta-render-blocking\",\n ruleName: \"Render-Blocking Resources\",\n message: `${blockingScripts} synchronous script(s) in <head> may block page rendering`,\n severity: \"WARNING\",\n category: \"Performance\",\n tier: \"pro\",\n fix: \"Add async or defer attributes to non-critical scripts in the <head>, or move them to the end of <body>.\",\n data: { blockingScripts }\n });\n }\n const stylesheets = head.querySelectorAll(\n 'link[rel=\"stylesheet\"]'\n );\n let blockingStylesheets = 0;\n stylesheets.forEach((link) => {\n const media = link.getAttribute(\"media\");\n if (!media || media === \"all\") blockingStylesheets++;\n });\n if (blockingStylesheets > 3) {\n results.push({\n ruleId: \"meta-render-blocking\",\n ruleName: \"Render-Blocking Resources\",\n message: `${blockingStylesheets} render-blocking stylesheets in <head> - consider inlining critical CSS`,\n severity: \"INFO\",\n category: \"Performance\",\n tier: \"pro\",\n fix: 'Inline critical CSS and load non-critical stylesheets asynchronously using media=\"print\" with an onload handler.',\n data: { blockingStylesheets }\n });\n }\n return results;\n }\n};\n\n// src/rules/lazy-load-lcp.ts\nvar lazyLoadLcpRule = {\n meta: {\n id: \"lazy-load-lcp\",\n name: \"Lazy Load LCP\",\n category: \"Performance\",\n tier: \"pro\",\n description: \"Checks that above-the-fold images (likely LCP candidates) are not lazy-loaded\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const images = document.querySelectorAll(\"img\");\n const firstImages = Array.from(images).slice(0, 3);\n for (const img of firstImages) {\n const loading = img.getAttribute(\"loading\");\n const fetchpriority = img.getAttribute(\"fetchpriority\");\n if (loading === \"lazy\") {\n const src = img.getAttribute(\"src\") || \"\";\n const alt = img.getAttribute(\"alt\") || \"\";\n const identifier = alt ? `\"${alt.substring(0, 40)}\"` : src ? `src=\"${src.substring(0, 50)}\"` : \"first image\";\n results.push({\n ruleId: \"lazy-load-lcp\",\n ruleName: \"Lazy Load LCP\",\n message: `Above-the-fold image (${identifier}) has loading=\"lazy\" - this delays the Largest Contentful Paint`,\n severity: \"WARNING\",\n category: \"Performance\",\n tier: \"pro\",\n fix: 'Remove loading=\"lazy\" from above-the-fold images. Add fetchpriority=\"high\" to the LCP image instead.'\n });\n break;\n }\n if (!fetchpriority && !loading) {\n results.push({\n ruleId: \"lazy-load-lcp\",\n ruleName: \"Lazy Load LCP\",\n message: 'Consider adding fetchpriority=\"high\" to your hero/banner image to improve Largest Contentful Paint',\n severity: \"INFO\",\n category: \"Performance\",\n tier: \"pro\",\n fix: 'Add fetchpriority=\"high\" to the most important above-the-fold image to prioritize its loading.'\n });\n break;\n }\n }\n return results;\n }\n};\n\n// src/rules/https-links.ts\nvar httpsLinksRule = {\n meta: {\n id: \"https-links\",\n name: \"HTTPS Links\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n description: \"Checks that internal links use HTTPS instead of HTTP\"\n },\n run(context) {\n const { document, url } = context;\n const results = [];\n let hostname;\n try {\n hostname = new URL(url).hostname;\n } catch {\n return results;\n }\n const links = document.querySelectorAll('a[href^=\"http:\"]');\n let internalHttpLinks = 0;\n let externalHttpLinks = 0;\n links.forEach((link) => {\n const href = link.getAttribute(\"href\");\n if (!href) return;\n try {\n const linkHostname = new URL(href).hostname;\n if (linkHostname === hostname) {\n internalHttpLinks++;\n } else {\n externalHttpLinks++;\n }\n } catch {\n }\n });\n if (internalHttpLinks > 0) {\n results.push({\n ruleId: \"https-links\",\n ruleName: \"HTTPS Links\",\n message: `${internalHttpLinks} internal link(s) use HTTP instead of HTTPS`,\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Change all internal links from http:// to https:// to avoid redirect chains and mixed content warnings.\",\n data: { internalHttpLinks }\n });\n }\n if (externalHttpLinks > 0) {\n results.push({\n ruleId: \"https-links\",\n ruleName: \"HTTPS Links\",\n message: `${externalHttpLinks} external link(s) use HTTP - consider updating to HTTPS where available`,\n severity: \"INFO\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Update external links to use https:// where the destination supports it.\",\n data: { externalHttpLinks }\n });\n }\n return results;\n }\n};\n\n// src/rules/meta-refresh-redirect.ts\nvar metaRefreshRedirectRule = {\n meta: {\n id: \"meta-refresh-redirect\",\n name: \"Meta Refresh Redirect\",\n category: \"SEO\",\n tier: \"pro\",\n description: 'Checks for <meta http-equiv=\"refresh\"> redirects which are bad for SEO'\n },\n run(context) {\n const { document } = context;\n const results = [];\n const metaRefresh = document.querySelector(\n 'meta[http-equiv=\"refresh\"]'\n );\n if (!metaRefresh) return results;\n const content = metaRefresh.getAttribute(\"content\") || \"\";\n const hasUrl = content.toLowerCase().includes(\"url=\");\n const delay = Number.parseInt(content.split(\";\")[0] || \"\", 10);\n if (hasUrl) {\n results.push({\n ruleId: \"meta-refresh-redirect\",\n ruleName: \"Meta Refresh Redirect\",\n message: `Page uses a meta refresh redirect${!Number.isNaN(delay) ? ` (${delay}s delay)` : \"\"} - use server-side 301 redirects instead`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Replace <meta http-equiv=\"refresh\"> with a server-side 301 redirect. Meta refreshes are bad for SEO and user experience.',\n data: { content, delay: Number.isNaN(delay) ? void 0 : delay }\n });\n } else if (!Number.isNaN(delay) && delay > 0) {\n results.push({\n ruleId: \"meta-refresh-redirect\",\n ruleName: \"Meta Refresh Redirect\",\n message: `Page auto-refreshes every ${delay} seconds - this may cause usability issues`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Consider removing the auto-refresh meta tag unless it serves a clear user need.\",\n data: { content, delay }\n });\n }\n return results;\n }\n};\n\n// src/rules/nofollow-audit.ts\nvar nofollowAuditRule = {\n meta: {\n id: \"nofollow-audit\",\n name: \"Nofollow Audit\",\n category: \"SEO\",\n tier: \"pro\",\n description: 'Audits the use of rel=\"nofollow\" on internal vs. external links'\n },\n run(context) {\n const { document, url } = context;\n const results = [];\n let hostname;\n try {\n hostname = new URL(url).hostname;\n } catch {\n return results;\n }\n const nofollowLinks = document.querySelectorAll('a[rel~=\"nofollow\"]');\n let internalNofollow = 0;\n nofollowLinks.forEach((link) => {\n const href = link.getAttribute(\"href\");\n if (!href) return;\n try {\n const linkHostname = new URL(href, url).hostname;\n if (linkHostname === hostname) internalNofollow++;\n } catch {\n if (href.startsWith(\"/\") || href.startsWith(\".\")) {\n internalNofollow++;\n }\n }\n });\n if (internalNofollow > 0) {\n results.push({\n ruleId: \"nofollow-audit\",\n ruleName: \"Nofollow Audit\",\n message: `${internalNofollow} internal link(s) have rel=\"nofollow\" - this wastes PageRank and hurts internal linking`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Remove rel=\"nofollow\" from internal links. Nofollow should only be used for external links you do not want to endorse (e.g., user-generated content, sponsored links).',\n data: { internalNofollow, totalNofollow: nofollowLinks.length }\n });\n }\n return results;\n }\n};\n\n// src/rules/cors-policy.ts\nvar corsPolicyRule = {\n meta: {\n id: \"cors-policy\",\n name: \"CORS Policy\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n description: \"Checks for overly permissive CORS configuration that could allow unauthorized cross-origin access\"\n },\n async run(url) {\n const results = [];\n const fakeOrigin = \"https://evil.example.com\";\n try {\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n \"User-Agent\": \"LintPage-Bot/1.0\",\n Origin: fakeOrigin\n },\n redirect: \"follow\"\n });\n const acao = response.headers.get(\"access-control-allow-origin\");\n const acac = response.headers.get(\"access-control-allow-credentials\");\n if (!acao) {\n return results;\n }\n if (acao === \"*\") {\n if (acac?.toLowerCase() === \"true\") {\n results.push({\n ruleId: \"cors-policy\",\n ruleName: \"CORS Policy\",\n message: \"CORS allows all origins with credentials enabled - this is a security vulnerability\",\n severity: \"CRITICAL\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: 'Set Access-Control-Allow-Origin to your specific trusted domains instead of \"*\". Wildcard with credentials is blocked by browsers but indicates a dangerous misconfiguration.'\n });\n } else {\n results.push({\n ruleId: \"cors-policy\",\n ruleName: \"CORS Policy\",\n message: \"CORS allows all origins (Access-Control-Allow-Origin: *) - restrict to trusted domains in production. Note: some hosting platforms (e.g. Vercel, Netlify, Cloudflare Pages) add this header by default, even if you haven't configured it.\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: 'If you set this header yourself, configure Access-Control-Allow-Origin to only allow requests from your trusted domains (e.g., \"https://myapp.com\") instead of using the wildcard \"*\". If your hosting platform adds it automatically, check their documentation for how to override or restrict CORS headers.'\n });\n }\n } else if (acao.toLowerCase() === fakeOrigin) {\n if (acac?.toLowerCase() === \"true\") {\n results.push({\n ruleId: \"cors-policy\",\n ruleName: \"CORS Policy\",\n message: \"CORS reflects any origin with credentials enabled - any website can make authenticated cross-origin requests and read responses. This is the most exploitable CORS misconfiguration.\",\n severity: \"CRITICAL\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Configure your server to validate the Origin header against a strict allowlist of trusted domains. Never reflect arbitrary origins when credentials are enabled.\"\n });\n } else {\n results.push({\n ruleId: \"cors-policy\",\n ruleName: \"CORS Policy\",\n message: \"CORS reflects any origin back in Access-Control-Allow-Origin - this is equivalent to a wildcard and allows any site to make cross-origin requests. Note: this may be caused by your hosting platform or a reverse proxy, not your own configuration.\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"If you set this header yourself, configure your server to validate the Origin header against an allowlist of trusted domains instead of reflecting it back. If your hosting platform adds it automatically, check their documentation for how to override or restrict CORS headers.\"\n });\n }\n }\n } catch {\n }\n return results;\n }\n};\n\n// src/rules/broken-internal-links.ts\nvar MAX_LINKS_TO_CHECK = 50;\nvar REQUEST_TIMEOUT_MS = 1e4;\nvar brokenInternalLinksRule = {\n meta: {\n id: \"broken-internal-links\",\n name: \"Broken Internal Links\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Checks that internal links on the page resolve successfully (no 404s or server errors)\"\n },\n async run(context) {\n const { document, url } = context;\n const results = [];\n let baseUrl;\n try {\n baseUrl = new URL(url);\n } catch {\n return results;\n }\n const seen = /* @__PURE__ */ new Set();\n const internalLinks = [];\n const anchors = document.querySelectorAll(\"a[href]\");\n for (const anchor of anchors) {\n const href = anchor.getAttribute(\"href\");\n if (!href) continue;\n if (href.startsWith(\"#\") || href.startsWith(\"mailto:\") || href.startsWith(\"tel:\") || href.startsWith(\"javascript:\") || href.startsWith(\"data:\")) {\n continue;\n }\n let resolved;\n try {\n resolved = new URL(href, url);\n } catch {\n continue;\n }\n if (resolved.hostname !== baseUrl.hostname) continue;\n resolved.hash = \"\";\n const normalized = resolved.toString();\n if (seen.has(normalized)) continue;\n seen.add(normalized);\n const currentNormalized = new URL(url);\n currentNormalized.hash = \"\";\n if (normalized === currentNormalized.toString()) continue;\n internalLinks.push(normalized);\n }\n if (internalLinks.length === 0) return results;\n const linksToCheck = internalLinks.slice(0, MAX_LINKS_TO_CHECK);\n const brokenLinks = [];\n const errorLinks = [];\n const checkLink = async (linkUrl) => {\n try {\n const res = await fetch(linkUrl, {\n method: \"HEAD\",\n headers: { \"User-Agent\": \"LintPage-Bot/1.0\" },\n redirect: \"follow\",\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)\n });\n if (res.status === 405) {\n const getRes = await fetch(linkUrl, {\n method: \"GET\",\n headers: { \"User-Agent\": \"LintPage-Bot/1.0\" },\n redirect: \"follow\",\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)\n });\n if (getRes.status >= 400) {\n brokenLinks.push({ url: linkUrl, status: getRes.status });\n }\n return;\n }\n if (res.status >= 400) {\n brokenLinks.push({ url: linkUrl, status: res.status });\n }\n } catch {\n errorLinks.push(linkUrl);\n }\n };\n const BATCH_SIZE = 10;\n for (let i = 0; i < linksToCheck.length; i += BATCH_SIZE) {\n const batch = linksToCheck.slice(i, i + BATCH_SIZE);\n await Promise.all(batch.map(checkLink));\n }\n if (brokenLinks.length > 0) {\n const notFound = brokenLinks.filter((l) => l.status === 404);\n const serverErrors = brokenLinks.filter((l) => l.status >= 500);\n const other = brokenLinks.filter(\n (l) => l.status !== 404 && l.status < 500\n );\n if (notFound.length > 0) {\n results.push({\n ruleId: \"broken-internal-links\",\n ruleName: \"Broken Internal Links\",\n message: `${notFound.length} internal link(s) return 404 Not Found: ${notFound.map((l) => l.url).join(\", \")}`,\n severity: \"CRITICAL\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Remove or update the broken links to point to valid pages. Broken internal links hurt SEO and user experience.\",\n data: { notFoundLinks: notFound }\n });\n }\n if (serverErrors.length > 0) {\n results.push({\n ruleId: \"broken-internal-links\",\n ruleName: \"Broken Internal Links\",\n message: `${serverErrors.length} internal link(s) return server errors: ${serverErrors.map((l) => `${l.url} (${l.status})`).join(\", \")}`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Investigate server errors on the linked pages. These may indicate temporary issues or misconfigured routes.\",\n data: { serverErrorLinks: serverErrors }\n });\n }\n if (other.length > 0) {\n results.push({\n ruleId: \"broken-internal-links\",\n ruleName: \"Broken Internal Links\",\n message: `${other.length} internal link(s) return client errors: ${other.map((l) => `${l.url} (${l.status})`).join(\", \")}`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Check the linked pages for access issues (e.g., 401/403 may indicate authentication or permission problems).\",\n data: { clientErrorLinks: other }\n });\n }\n }\n if (errorLinks.length > 0) {\n results.push({\n ruleId: \"broken-internal-links\",\n ruleName: \"Broken Internal Links\",\n message: `${errorLinks.length} internal link(s) could not be reached: ${errorLinks.join(\", \")}`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"These links timed out or had network errors during the check. Verify they are accessible.\",\n data: { unreachableLinks: errorLinks }\n });\n }\n if (internalLinks.length > MAX_LINKS_TO_CHECK) {\n results.push({\n ruleId: \"broken-internal-links\",\n ruleName: \"Broken Internal Links\",\n message: `Only checked ${MAX_LINKS_TO_CHECK} of ${internalLinks.length} internal links. Consider reducing the number of links on this page.`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n data: {\n totalLinks: internalLinks.length,\n checkedLinks: MAX_LINKS_TO_CHECK\n }\n });\n }\n return results;\n }\n};\n\n// src/rules/index.ts\nvar proRules = [\n // Ported — Pre-Launch\n sslRule,\n trackingRule,\n xRobotsTagRule,\n // Ported — Content / SEO\n thinContentRule,\n duplicateMetaRule,\n structuredDataRule,\n charsetRule,\n // Ported — Accessibility\n imageAltTextRule,\n accessibilityRule,\n semanticStructureRule,\n // Ported — Performance\n performanceRule,\n imageDimensionsRule,\n // Ported — Security\n mixedContentRule,\n securityHeadersRule,\n // New — Social\n ogImageSizeRule,\n ogImageTypeRule,\n twitterImageRule,\n socialPreviewRenderRule,\n // New — Content\n titleKeywordStuffingRule,\n contentToHtmlRatioRule,\n titleUniquenessRule,\n descriptionUniquenessRule,\n // New — Technical\n structuredDataValidateRule,\n hreflangRule,\n canonicalSelfReferencingRule,\n // New — Performance\n metaRenderBlockingRule,\n lazyLoadLcpRule,\n // New — Security / SEO\n httpsLinksRule,\n metaRefreshRedirectRule,\n nofollowAuditRule\n];\nvar proAsyncRules = [\n brokenInternalLinksRule\n];\nvar proStandaloneRules = [\n robotsTxtCheckRule,\n sitemapPresenceRule,\n ttfbRule,\n corsPolicyRule\n];\n\n// src/license.ts\nimport * as jose from \"jose\";\nvar PUBLIC_KEY_JWK = {\n kty: \"OKP\",\n crv: \"Ed25519\",\n x: \"Q628CrspKqI_ig04oril9DaBhFaCJ2fJtoeFJhzrWek\"\n};\nvar cachedPublicKey = null;\nasync function getPublicKey() {\n if (!cachedPublicKey) {\n cachedPublicKey = await jose.importJWK(PUBLIC_KEY_JWK, \"EdDSA\");\n }\n return cachedPublicKey;\n}\nasync function validateLicense(token) {\n try {\n const publicKey = await getPublicKey();\n const { payload } = await jose.jwtVerify(token, publicKey, {\n algorithms: [\"EdDSA\"],\n issuer: \"lintpage\",\n audience: \"lintpage-pro\"\n });\n const licensePayload = {\n sub: payload.sub,\n plan: payload.plan,\n iat: payload.iat,\n exp: payload.exp\n };\n return { valid: true, payload: licensePayload };\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Invalid license key\";\n return { valid: false, error: message };\n }\n}\nasync function isLicenseValid(token) {\n const result = await validateLicense(token);\n return result.valid;\n}\n\n// src/index.ts\nvar proPlugin = {\n name: \"@lintpage/pro\",\n rules: proRules,\n asyncRules: proAsyncRules,\n standaloneRules: proStandaloneRules\n};\nfunction loadProPlugin() {\n return proPlugin;\n}\nexport {\n accessibilityRule,\n brokenInternalLinksRule,\n canonicalSelfReferencingRule,\n charsetRule,\n contentToHtmlRatioRule,\n corsPolicyRule,\n descriptionUniquenessRule,\n duplicateMetaRule,\n hreflangRule,\n httpsLinksRule,\n imageAltTextRule,\n imageDimensionsRule,\n isLicenseValid,\n lazyLoadLcpRule,\n loadProPlugin,\n metaRefreshRedirectRule,\n metaRenderBlockingRule,\n mixedContentRule,\n nofollowAuditRule,\n ogImageSizeRule,\n ogImageTypeRule,\n performanceRule,\n proAsyncRules,\n proPlugin,\n proRules,\n proStandaloneRules,\n robotsTxtCheckRule,\n securityHeadersRule,\n semanticStructureRule,\n sitemapPresenceRule,\n socialPreviewRenderRule,\n sslRule,\n structuredDataRule,\n structuredDataValidateRule,\n thinContentRule,\n titleKeywordStuffingRule,\n titleUniquenessRule,\n trackingRule,\n ttfbRule,\n twitterImageRule,\n validateLicense,\n xRobotsTagRule\n};\n//# sourceMappingURL=index.mjs.map","import cac from 'cac';\nimport chalk from 'chalk';\nimport {\n auditPage,\n loadConfig,\n createDefaultConfig,\n} from '@lintpage/core';\nimport { loadProPlugin } from '@lintpage/pro';\nimport { format, type Format } from './formatter';\nimport { writeFileSync, readFileSync, existsSync } from 'fs';\nimport { join } from 'path';\n\nconst cli = cac('lintpage');\n\n// Exit codes\nconst EXIT_PASS = 0;\nconst EXIT_FAIL = 1;\nconst EXIT_ERROR = 2;\n\ncli\n .command('<url>', 'Run an audit on a URL')\n .option('--format <format>', 'Output format: text, json, github', {\n default: 'text',\n })\n .option('--config <path>', 'Path to config file')\n .option('--fail-on-warning', 'Exit 1 on warnings (not just criticals)')\n .option('--quiet', 'Minimal output (counts only)')\n .action(async (url: string, options: Record<string, unknown>) => {\n const fmt = (options.format as Format) || 'text';\n const configPath = options.config as string | undefined;\n const failOnWarning = Boolean(options.failOnWarning);\n const quiet = Boolean(options.quiet);\n\n try {\n // Normalize URL\n let targetUrl = url;\n if (!targetUrl.startsWith('http://') && !targetUrl.startsWith('https://')) {\n targetUrl = `https://${targetUrl}`;\n }\n\n // Load config\n const config = loadConfig(configPath) ?? undefined;\n\n // Run audit\n if (!quiet && fmt === 'text') {\n console.log(chalk.dim(`Auditing ${targetUrl}...`));\n }\n\n const result = await auditPage(targetUrl, { plugins: [loadProPlugin()], config });\n\n // Output\n console.log(format(result, fmt, quiet));\n\n // Exit code\n const hasCritical = result.results.some(\n (r) => r.severity === 'CRITICAL'\n );\n const hasWarning = result.results.some(\n (r) => r.severity === 'WARNING'\n );\n\n if (hasCritical) {\n process.exit(EXIT_FAIL);\n }\n if (failOnWarning && hasWarning) {\n process.exit(EXIT_FAIL);\n }\n process.exit(EXIT_PASS);\n } catch (err) {\n if (fmt === 'json') {\n console.error(\n JSON.stringify({\n error: err instanceof Error ? err.message : String(err),\n })\n );\n } else {\n console.error(\n chalk.red(\n `Error: ${err instanceof Error ? err.message : String(err)}`\n )\n );\n }\n process.exit(EXIT_ERROR);\n }\n });\n\ncli\n .command('init', 'Generate a .lintpagerc.json config file')\n .action(() => {\n const configPath = join(process.cwd(), '.lintpagerc.json');\n if (existsSync(configPath)) {\n console.log(chalk.yellow('.lintpagerc.json already exists'));\n process.exit(EXIT_PASS);\n }\n const config = createDefaultConfig();\n writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n');\n console.log(chalk.green('Created .lintpagerc.json'));\n process.exit(EXIT_PASS);\n });\n\ncli.help();\n\n// Read version dynamically from package.json\nconst pkgPath = join(__dirname, '..', 'package.json');\nconst pkgJson = existsSync(pkgPath)\n ? JSON.parse(readFileSync(pkgPath, 'utf-8'))\n : { version: '0.0.0' };\ncli.version(pkgJson.version);\n\ntry {\n cli.parse();\n} catch (err) {\n if (err instanceof Error && err.message) {\n // Extract clean message from CACError (e.g. \"option `--pro <key>` value is missing\")\n console.error(chalk.red(`Error: ${err.message}`));\n console.error(chalk.dim('Run \"lintpage --help\" for usage information.'));\n } else {\n console.error(chalk.red(`Error: ${String(err)}`));\n }\n process.exit(EXIT_ERROR);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.cjs","names":["dns","path","format"],"sources":["../../core/dist/index.mjs","../../pro/dist/index.mjs","../src/cli.ts"],"sourcesContent":["// src/rules/title.ts\nvar titleRule = {\n meta: {\n id: \"title\",\n name: \"Page Title\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Checks for the presence and length of the <title> tag\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const titleElement = document.querySelector(\"title\");\n const value = titleElement?.textContent?.trim() || \"\";\n const length = value.length;\n if (!value) {\n results.push({\n ruleId: \"title\",\n ruleName: \"Page Title\",\n message: \"Missing title tag\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Add a <title>Your Page Title</title> tag inside your <head> element. Aim for 50-60 characters to avoid truncation in search results.\",\n data: { value, length }\n });\n } else if (length < 30) {\n results.push({\n ruleId: \"title\",\n ruleName: \"Page Title\",\n message: \"Title may be too short - under 30 characters may not be descriptive enough\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Expand your title to 50-60 characters to avoid truncation. Google does not enforce a character limit but truncates based on pixel width (~600px on desktop).\",\n data: { value, length }\n });\n } else if (length > 60) {\n results.push({\n ruleId: \"title\",\n ruleName: \"Page Title\",\n message: \"Title is over 60 characters - likely to be truncated in search results\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Shorten your title to under 60 characters to avoid truncation. Google truncates based on pixel width (~600px on desktop), which is roughly 60 characters.\",\n data: { value, length }\n });\n }\n return results;\n }\n};\n\n// src/rules/meta-description.ts\nvar metaDescriptionRule = {\n meta: {\n id: \"meta-description\",\n name: \"Meta Description\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Checks for the presence and length of the meta description tag\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const metaDesc = document.querySelector('meta[name=\"description\"]');\n const value = metaDesc?.getAttribute(\"content\")?.trim() || \"\";\n const length = value.length;\n if (!value) {\n results.push({\n ruleId: \"meta-description\",\n ruleName: \"Meta Description\",\n message: \"Missing meta description\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: 'Add <meta name=\"description\" content=\"Your description here\" /> to your <head> tag. Aim for 150-160 characters to avoid truncation.',\n data: { value, length }\n });\n } else if (length < 120) {\n results.push({\n ruleId: \"meta-description\",\n ruleName: \"Meta Description\",\n message: \"Meta description may be too short - under 120 characters may not fully utilize the available snippet space\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Expand your meta description to 150-160 characters. Google does not enforce a character limit but typically truncates around 160 characters on desktop (~120 on mobile).\",\n data: { value, length }\n });\n } else if (length > 160) {\n results.push({\n ruleId: \"meta-description\",\n ruleName: \"Meta Description\",\n message: \"Meta description is over 160 characters - likely to be truncated in search results\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Shorten your meta description to under 160 characters. Google truncates snippets based on device width, typically around 160 characters on desktop.\",\n data: { value, length }\n });\n }\n return results;\n }\n};\n\n// src/rules/og-title.ts\nvar ogTitleRule = {\n meta: {\n id: \"og-title\",\n name: \"Open Graph Title\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Checks for the og:title meta tag\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const ogTitle = document.querySelector('meta[property=\"og:title\"]');\n const value = ogTitle?.getAttribute(\"content\")?.trim() || \"\";\n if (!value) {\n results.push({\n ruleId: \"og-title\",\n ruleName: \"Open Graph Title\",\n message: \"Missing og:title tag - social media shares will have no title preview\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: 'Add <meta property=\"og:title\" content=\"Your Page Title\" /> to your <head> tag.'\n });\n } else if (value.length > 60) {\n results.push({\n ruleId: \"og-title\",\n ruleName: \"Open Graph Title\",\n message: `og:title is long (${value.length} characters). Optimal: 50-60 characters`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Shorten your og:title to under 60 characters. Longer titles get truncated on most social platforms.\",\n data: { value, length: value.length }\n });\n } else if (value.length < 30) {\n results.push({\n ruleId: \"og-title\",\n ruleName: \"Open Graph Title\",\n message: `og:title is short (${value.length} characters). Optimal: 50-60 characters`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Consider expanding your og:title to 50-60 characters to make social shares more compelling.\",\n data: { value, length: value.length }\n });\n }\n return results;\n }\n};\n\n// src/rules/og-description.ts\nvar ogDescriptionRule = {\n meta: {\n id: \"og-description\",\n name: \"Open Graph Description\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Checks for the og:description meta tag\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const ogDesc = document.querySelector('meta[property=\"og:description\"]');\n const value = ogDesc?.getAttribute(\"content\")?.trim() || \"\";\n if (!value) {\n results.push({\n ruleId: \"og-description\",\n ruleName: \"Open Graph Description\",\n message: \"Missing og:description tag - social media shares will have no description preview\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: 'Add <meta property=\"og:description\" content=\"Your description\" /> to your <head> tag.'\n });\n } else if (value.length > 200) {\n results.push({\n ruleId: \"og-description\",\n ruleName: \"Open Graph Description\",\n message: `og:description is long (${value.length} characters). Optimal: 110-160 characters`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Shorten your og:description to under 200 characters. Most platforms truncate longer descriptions.\",\n data: { value, length: value.length }\n });\n } else if (value.length < 70) {\n results.push({\n ruleId: \"og-description\",\n ruleName: \"Open Graph Description\",\n message: `og:description is short (${value.length} characters). Optimal: 110-160 characters`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Consider expanding your og:description to 110-160 characters to make social shares more engaging.\",\n data: { value, length: value.length }\n });\n }\n return results;\n }\n};\n\n// src/rules/og-image.ts\nvar ogImageRule = {\n meta: {\n id: \"og-image\",\n name: \"Open Graph Image\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Checks for the og:image meta tag\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const ogImage = document.querySelector('meta[property=\"og:image\"]');\n if (!ogImage?.getAttribute(\"content\")) {\n results.push({\n ruleId: \"og-image\",\n ruleName: \"Open Graph Image\",\n message: \"Missing og:image tag - social media shares will have no image preview\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: 'Add <meta property=\"og:image\" content=\"https://yoursite.com/image.jpg\" /> to your <head> tag.'\n });\n }\n return results;\n }\n};\n\n// src/rules/og-url.ts\nvar ogUrlRule = {\n meta: {\n id: \"og-url\",\n name: \"Open Graph URL\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Checks for the og:url meta tag\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const ogUrl = document.querySelector('meta[property=\"og:url\"]');\n if (!ogUrl?.getAttribute(\"content\")) {\n results.push({\n ruleId: \"og-url\",\n ruleName: \"Open Graph URL\",\n message: \"Missing og:url tag - social media may not show the correct URL\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: 'Add <meta property=\"og:url\" content=\"https://yoursite.com/page\" /> to your <head> tag.'\n });\n }\n return results;\n }\n};\n\n// src/rules/twitter-card.ts\nvar twitterCardRule = {\n meta: {\n id: \"twitter-card\",\n name: \"Twitter Card\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Checks for Twitter Card meta tags\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const twitterCard = document.querySelector('meta[name=\"twitter:card\"]');\n if (!twitterCard?.getAttribute(\"content\")) {\n results.push({\n ruleId: \"twitter-card\",\n ruleName: \"Twitter Card\",\n message: \"Missing Twitter Card tags - tweets with your URL will have no preview card\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: 'Add <meta name=\"twitter:card\" content=\"summary_large_image\" />, <meta name=\"twitter:title\" content=\"...\" />, and <meta name=\"twitter:image\" content=\"...\" /> to your <head>.'\n });\n }\n return results;\n }\n};\n\n// src/rules/canonical-url.ts\nvar canonicalUrlRule = {\n meta: {\n id: \"canonical-url\",\n name: \"Canonical URL\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Checks for a canonical link tag and validates the URL\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const canonical = document.querySelector('link[rel=\"canonical\"]');\n const value = canonical?.getAttribute(\"href\") || void 0;\n if (!canonical) {\n results.push({\n ruleId: \"canonical-url\",\n ruleName: \"Canonical URL\",\n message: \"No canonical link found (recommended for SEO)\",\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"free\",\n fix: 'Add <link rel=\"canonical\" href=\"https://yoursite.com/this-page\" /> to your <head> tag to prevent duplicate content issues.',\n data: { present: false }\n });\n } else if (value && !value.startsWith(\"http\")) {\n results.push({\n ruleId: \"canonical-url\",\n ruleName: \"Canonical URL\",\n message: \"Canonical URL should be absolute (include protocol and domain)\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: 'Change your canonical href to an absolute URL starting with https:// (e.g., href=\"https://yoursite.com/page\").',\n data: { present: true, value }\n });\n }\n return results;\n }\n};\n\n// src/rules/robots-noindex.ts\nvar robotsNoindexRule = {\n meta: {\n id: \"robots-noindex\",\n name: \"Robots Noindex\",\n category: \"Pre-Launch\",\n tier: \"free\",\n description: \"Checks for noindex/nofollow in the robots meta tag\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const metaRobots = document.querySelector('meta[name=\"robots\"]');\n const content = metaRobots?.getAttribute(\"content\") || \"\";\n if (content.includes(\"noindex\")) {\n results.push({\n ruleId: \"robots-noindex\",\n ruleName: \"Robots Noindex\",\n message: \"Page has noindex meta tag - WILL NOT BE INDEXED by search engines! Remove this before launch or you'll get ZERO organic traffic.\",\n severity: \"CRITICAL\",\n category: \"Pre-Launch\",\n tier: \"free\",\n fix: 'Remove the <meta name=\"robots\" content=\"noindex\" /> tag from your <head>, or change it to content=\"index, follow\".',\n data: { metaRobots: content }\n });\n }\n if (content.includes(\"nofollow\")) {\n results.push({\n ruleId: \"robots-noindex\",\n ruleName: \"Robots Noindex\",\n message: \"Page has nofollow meta tag - links will not be followed\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: 'Remove \"nofollow\" from your <meta name=\"robots\"> content if you want search engines to follow your links.',\n data: { metaRobots: content }\n });\n }\n return results;\n }\n};\n\n// src/rules/heading-structure.ts\nvar headingStructureRule = {\n meta: {\n id: \"heading-structure\",\n name: \"Heading Structure\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Validates H1 tag presence, count, and heading hierarchy\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const h1Elements = document.querySelectorAll(\"h1\");\n const count = h1Elements.length;\n const values = Array.from(h1Elements).map(\n (h1) => h1.textContent?.trim() || \"\"\n );\n if (count === 0) {\n results.push({\n ruleId: \"heading-structure\",\n ruleName: \"Heading Structure\",\n message: \"No H1 tag found\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Add a single <h1> tag to your page with a clear, descriptive heading that includes your primary keyword.\",\n data: { h1Count: count }\n });\n } else if (count > 1) {\n results.push({\n ruleId: \"heading-structure\",\n ruleName: \"Heading Structure\",\n message: `Multiple H1 tags found (${count}). Best practice is 1 per page`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"While Google does not penalize multiple H1 tags, using a single H1 per page is a widely recommended best practice for clarity and accessibility.\",\n data: { h1Count: count, h1Values: values }\n });\n }\n values.forEach((value, index) => {\n if (!value) {\n results.push({\n ruleId: \"heading-structure\",\n ruleName: \"Heading Structure\",\n message: `H1 #${index + 1} is empty`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Add descriptive text content to your <h1> tag.\"\n });\n } else if (value.length > 70) {\n results.push({\n ruleId: \"heading-structure\",\n ruleName: \"Heading Structure\",\n message: `H1 #${index + 1} is too long (${value.length} characters)`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Shorten your H1 to under 70 characters for better readability and SEO.\"\n });\n }\n });\n const headings = document.querySelectorAll(\"h1, h2, h3, h4, h5, h6\");\n let lastLevel = 0;\n Array.from(headings).forEach((heading) => {\n const level = Number.parseInt(heading.tagName[1] ?? \"1\", 10);\n if (level - lastLevel > 1) {\n const text = heading.textContent?.trim().substring(0, 40) || \"...\";\n results.push({\n ruleId: \"heading-structure\",\n ruleName: \"Heading Structure\",\n message: `${heading.tagName} skips heading level from h${lastLevel} (content: \"${text}\")`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"free\",\n fix: `Don't skip heading levels. Use h${lastLevel + 1} instead of ${heading.tagName} to maintain proper hierarchy.`\n });\n }\n lastLevel = level;\n });\n return results;\n }\n};\n\n// src/rules/html-lang.ts\nvar htmlLangRule = {\n meta: {\n id: \"html-lang\",\n name: \"HTML Lang Attribute\",\n category: \"Accessibility\",\n tier: \"free\",\n description: \"Checks for the lang attribute on the <html> tag\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const html = document.documentElement;\n const lang = html.getAttribute(\"lang\");\n if (!lang) {\n results.push({\n ruleId: \"html-lang\",\n ruleName: \"HTML Lang Attribute\",\n message: \"Missing lang attribute on <html> tag\",\n severity: \"WARNING\",\n category: \"Accessibility\",\n tier: \"free\",\n fix: 'Add lang=\"en\" (or your language code) to your <html> tag: <html lang=\"en\">.',\n data: { present: false }\n });\n }\n return results;\n }\n};\n\n// src/rules/viewport.ts\nvar viewportRule = {\n meta: {\n id: \"viewport\",\n name: \"Viewport Meta Tag\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Checks for the viewport meta tag for mobile responsiveness\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const viewport = document.querySelector('meta[name=\"viewport\"]');\n if (!viewport) {\n results.push({\n ruleId: \"viewport\",\n ruleName: \"Viewport Meta Tag\",\n message: \"Missing viewport meta tag - page will not render properly on mobile devices\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: 'Add <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" /> to your <head> tag.',\n data: { present: false }\n });\n } else {\n const content = viewport.getAttribute(\"content\") || \"\";\n const hasUserScalableNo = /user-scalable\\s*=\\s*no/i.test(content);\n const maxScaleMatch = content.match(/maximum-scale\\s*=\\s*([\\d.]+)/i);\n const hasRestrictiveMaxScale = maxScaleMatch && parseFloat(maxScaleMatch[1]) < 2;\n if (hasUserScalableNo || hasRestrictiveMaxScale) {\n results.push({\n ruleId: \"viewport\",\n ruleName: \"Viewport Meta Tag\",\n message: \"Viewport disables or restricts user zoom - this fails WCAG 1.4.4 (Resize text) which requires at least 200% zoom\",\n severity: \"WARNING\",\n category: \"Accessibility\",\n tier: \"free\",\n fix: \"Remove user-scalable=no and ensure maximum-scale is at least 2.0 (or remove it entirely) to allow users to zoom.\"\n });\n }\n }\n return results;\n }\n};\n\n// src/rules/favicon.ts\nvar faviconRule = {\n meta: {\n id: \"favicon\",\n name: \"Favicon\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Checks for the presence of a favicon link tag\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const favicon = document.querySelector('link[rel*=\"icon\"]');\n if (!favicon) {\n results.push({\n ruleId: \"favicon\",\n ruleName: \"Favicon\",\n message: \"No favicon found - browsers will show a default icon in tabs and bookmarks\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: 'Add <link rel=\"icon\" href=\"/favicon.ico\" /> to your <head> tag. Include multiple sizes for best results.',\n data: { present: false }\n });\n }\n return results;\n }\n};\n\n// src/rules/anchor-missing-href.ts\nvar anchorMissingHrefRule = {\n meta: {\n id: \"anchor-missing-href\",\n name: \"Anchor Missing Href\",\n category: \"SEO\",\n tier: \"free\",\n description: \"Checks that all <a> elements have a valid href attribute\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const anchors = document.querySelectorAll(\"a\");\n const missing = [];\n for (const anchor of anchors) {\n const href = anchor.getAttribute(\"href\");\n if (!href || href.trim() === \"\") {\n const text = anchor.textContent?.trim() || \"\";\n const preview = text.length > 50 ? text.slice(0, 50) + \"\\u2026\" : text;\n missing.push(preview || \"<empty>\");\n }\n }\n if (missing.length > 0) {\n results.push({\n ruleId: \"anchor-missing-href\",\n ruleName: \"Anchor Missing Href\",\n message: `${missing.length} <a> element(s) missing a valid href attribute: ${missing.join(\", \")}`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"free\",\n fix: \"Add a valid href attribute to all <a> elements. Links without href are not crawlable by search engines and inaccessible to keyboard/screen reader users. If the element is not a link, use a <button> or <span> instead.\",\n data: { count: missing.length, anchors: missing }\n });\n }\n return results;\n }\n};\n\n// src/rules/index.ts\nvar coreRules = [\n titleRule,\n metaDescriptionRule,\n ogTitleRule,\n ogDescriptionRule,\n ogImageRule,\n ogUrlRule,\n twitterCardRule,\n canonicalUrlRule,\n robotsNoindexRule,\n headingStructureRule,\n htmlLangRule,\n viewportRule,\n faviconRule,\n anchorMissingHrefRule\n];\nvar ruleRegistry = new Map(\n coreRules.map((rule) => [rule.meta.id, rule])\n);\n\n// src/fetcher.ts\nimport dns from \"dns/promises\";\nfunction isPrivateOrReservedIPv4(ip) {\n const ipv4Match = ip.match(\n /^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/\n );\n if (!ipv4Match) return false;\n const [, a, b] = ipv4Match.map(Number);\n if (a === 10) return true;\n if (a === 172 && b >= 16 && b <= 31) return true;\n if (a === 192 && b === 168) return true;\n if (a === 127) return true;\n if (a === 169 && b === 254) return true;\n if (a === 0) return true;\n if (a === 100 && b >= 64 && b <= 127) return true;\n if (a === 198 && (b === 18 || b === 19)) return true;\n if (a >= 224) return true;\n return false;\n}\nfunction isBlockedHostname(hostname) {\n if (hostname === \"localhost\" || hostname === \"127.0.0.1\" || hostname === \"[::1]\" || hostname === \"0.0.0.0\") {\n return true;\n }\n if (hostname.endsWith(\".internal\") || hostname.endsWith(\".local\") || hostname.endsWith(\".localhost\")) {\n return true;\n }\n if (isPrivateOrReservedIPv4(hostname)) return true;\n if (hostname.startsWith(\"[\") && (hostname === \"[::1]\" || hostname.startsWith(\"[fc\") || hostname.startsWith(\"[fd\") || hostname.startsWith(\"[fe80:\"))) {\n return true;\n }\n return false;\n}\nasync function resolveAndValidateHostname(hostname) {\n const cleanHostname = hostname.replace(/^\\[|\\]$/g, \"\");\n try {\n const { address } = await dns.lookup(cleanHostname);\n if (isPrivateOrReservedIPv4(address)) {\n throw new Error(\"URLs pointing to private or internal addresses are not allowed\");\n }\n } catch (err) {\n if (err instanceof Error && err.message.includes(\"private or internal\")) {\n throw err;\n }\n throw new Error(\"Could not resolve hostname\");\n }\n}\nfunction validateUrl(url) {\n let parsed;\n try {\n parsed = new URL(url);\n } catch {\n throw new Error(\"Invalid URL\");\n }\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n throw new Error(\"Only HTTP and HTTPS URLs are allowed\");\n }\n if (isBlockedHostname(parsed.hostname)) {\n throw new Error(\"URLs pointing to private or internal addresses are not allowed\");\n }\n}\nasync function validateUrlWithDns(url) {\n validateUrl(url);\n const parsed = new URL(url);\n await resolveAndValidateHostname(parsed.hostname);\n}\nasync function fetchPage(url) {\n await validateUrlWithDns(url);\n const fetchStart = Date.now();\n const response = await fetch(url, {\n headers: {\n \"User-Agent\": \"LintPage-Bot/1.0\"\n },\n signal: AbortSignal.timeout(3e4)\n });\n const ttfbMs = Date.now() - fetchStart;\n if (!response.ok) {\n throw new Error(\n `Failed to fetch URL: ${response.status} ${response.statusText}`\n );\n }\n const html = await response.text();\n const { JSDOM } = await import(\"jsdom\");\n const dom = new JSDOM(html);\n return {\n document: dom.window.document,\n response,\n html,\n ttfbMs\n };\n}\n\n// src/runner.ts\nvar CATEGORY_WEIGHTS = {\n \"Pre-Launch\": 30,\n SEO: 35,\n Accessibility: 20,\n Performance: 15\n};\nfunction calculateCategoryScores(results) {\n const categoryIssues = {};\n for (const category of Object.keys(CATEGORY_WEIGHTS)) {\n categoryIssues[category] = { critical: 0, warning: 0, info: 0 };\n }\n for (const result of results) {\n const cat = result.category;\n if (!categoryIssues[cat]) {\n categoryIssues[cat] = { critical: 0, warning: 0, info: 0 };\n }\n if (result.severity === \"CRITICAL\") categoryIssues[cat].critical++;\n else if (result.severity === \"WARNING\") categoryIssues[cat].warning++;\n else categoryIssues[cat].info++;\n }\n const scores = {};\n for (const [category, weight] of Object.entries(CATEGORY_WEIGHTS)) {\n const counts = categoryIssues[category] || {\n critical: 0,\n warning: 0,\n info: 0\n };\n const deductionPercent = Math.min(\n 100,\n counts.critical * 30 + counts.warning * 5 + counts.info * 1\n );\n scores[category] = {\n score: Math.round(weight * (1 - deductionPercent / 100) * 10) / 10,\n max: weight,\n deductionPercent\n };\n }\n return scores;\n}\nfunction calculateScore(results) {\n const categoryScores = calculateCategoryScores(results);\n const total = Object.values(categoryScores).reduce(\n (sum, cat) => sum + cat.score,\n 0\n );\n return Math.round(total);\n}\nfunction runRules(rules, context, config) {\n const results = [];\n for (const rule of rules) {\n if (config?.rules) {\n const ruleConfig = config.rules[rule.meta.id];\n if (ruleConfig === false) continue;\n if (typeof ruleConfig === \"object\" && ruleConfig.enabled === false)\n continue;\n }\n try {\n const ruleResults = rule.run(context);\n results.push(...ruleResults);\n } catch (err) {\n console.warn(\n `[lintpage] Rule \"${rule.meta.id}\" threw an error: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n return results;\n}\nfunction isRuleEnabled(ruleId, config) {\n if (!config?.rules) return true;\n const ruleConfig = config.rules[ruleId];\n if (ruleConfig === false) return false;\n if (typeof ruleConfig === \"object\" && ruleConfig.enabled === false) return false;\n return true;\n}\nasync function runAsyncRules(rules, context, config) {\n const enabledRules = rules.filter((r) => isRuleEnabled(r.meta.id, config));\n const settled = await Promise.allSettled(\n enabledRules.map((rule) => rule.run(context))\n );\n const results = [];\n for (let i = 0; i < settled.length; i++) {\n const outcome = settled[i];\n if (outcome.status === \"fulfilled\") {\n results.push(...outcome.value);\n } else {\n const err = outcome.reason;\n console.warn(\n `[lintpage] Async rule \"${enabledRules[i].meta.id}\" threw an error: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n return results;\n}\nasync function runStandaloneRules(rules, url, config) {\n const enabledRules = rules.filter((r) => isRuleEnabled(r.meta.id, config));\n const settled = await Promise.allSettled(\n enabledRules.map((rule) => rule.run(url))\n );\n const results = [];\n for (let i = 0; i < settled.length; i++) {\n const outcome = settled[i];\n if (outcome.status === \"fulfilled\") {\n results.push(...outcome.value);\n } else {\n const err = outcome.reason;\n console.warn(\n `[lintpage] Standalone rule \"${enabledRules[i].meta.id}\" threw an error: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n return results;\n}\nasync function auditPage(url, options) {\n const { document, response, ttfbMs } = await fetchPage(url);\n const isHttps = url.startsWith(\"https://\");\n const context = {\n document,\n url,\n response,\n isHttps\n };\n const allRules = [...coreRules];\n const allAsyncRules = [];\n const allStandaloneRules = [];\n if (options?.plugins) {\n for (const plugin of options.plugins) {\n allRules.push(...plugin.rules);\n if (plugin.asyncRules) {\n allAsyncRules.push(...plugin.asyncRules);\n }\n if (plugin.standaloneRules) {\n allStandaloneRules.push(...plugin.standaloneRules);\n }\n }\n }\n const results = runRules(allRules, context, options?.config);\n const networkRulePromises = [];\n if (allAsyncRules.length > 0) {\n networkRulePromises.push(runAsyncRules(allAsyncRules, context, options?.config));\n }\n if (allStandaloneRules.length > 0) {\n networkRulePromises.push(runStandaloneRules(allStandaloneRules, url, options?.config));\n }\n if (networkRulePromises.length > 0) {\n const networkResults = await Promise.all(networkRulePromises);\n for (const batch of networkResults) {\n results.push(...batch);\n }\n }\n if (ttfbMs > 1800) {\n results.push({\n ruleId: \"ttfb\",\n ruleName: \"Time to First Byte\",\n message: `Slow server response time (TTFB: ${ttfbMs}ms) - aim for under 800ms`,\n severity: \"WARNING\",\n category: \"Performance\",\n tier: \"free\",\n fix: \"Optimize server response time: enable caching, use a CDN, optimize database queries, or upgrade hosting.\",\n data: { ms: ttfbMs }\n });\n } else if (ttfbMs > 800) {\n results.push({\n ruleId: \"ttfb\",\n ruleName: \"Time to First Byte\",\n message: `Server response time could be improved (TTFB: ${ttfbMs}ms) - aim for under 800ms`,\n severity: \"INFO\",\n category: \"Performance\",\n tier: \"free\",\n fix: \"Consider enabling server-side caching or using a CDN to reduce response time.\",\n data: { ms: ttfbMs }\n });\n }\n const categoryScores = calculateCategoryScores(results);\n const score = Object.values(categoryScores).reduce(\n (sum, cat) => sum + cat.score,\n 0\n );\n const hasCritical = results.some((r) => r.severity === \"CRITICAL\");\n return {\n url,\n timestamp: (/* @__PURE__ */ new Date()).toISOString(),\n results,\n score: Math.round(score),\n overallStatus: hasCritical ? \"FAIL\" : \"PASS\",\n categoryScores\n };\n}\nvar CONCURRENT_AUDITS = 3;\nasync function audit(urls, options) {\n const pages = [];\n for (let i = 0; i < urls.length; i += CONCURRENT_AUDITS) {\n const batch = urls.slice(i, i + CONCURRENT_AUDITS);\n const batchResults = await Promise.all(\n batch.map((url) => auditPage(url, options))\n );\n pages.push(...batchResults);\n }\n return {\n pages,\n timestamp: (/* @__PURE__ */ new Date()).toISOString()\n };\n}\n\n// src/config.ts\nimport { readFileSync, existsSync, statSync } from \"fs\";\nimport { join } from \"path\";\nvar CONFIG_FILES = [\n \".lintpagerc.json\",\n \".lintpagerc\",\n \"lintpage.config.json\"\n];\nfunction loadConfig(pathOrCwd) {\n const resolved = pathOrCwd || process.cwd();\n if (pathOrCwd && existsSync(pathOrCwd) && statSync(pathOrCwd).isFile()) {\n try {\n const content = readFileSync(pathOrCwd, \"utf-8\");\n return JSON.parse(content);\n } catch {\n return null;\n }\n }\n const dir = resolved;\n for (const file of CONFIG_FILES) {\n const path = join(dir, file);\n if (existsSync(path)) {\n try {\n const content = readFileSync(path, \"utf-8\");\n return JSON.parse(content);\n } catch {\n return null;\n }\n }\n }\n return null;\n}\nfunction createDefaultConfig() {\n return {\n rules: {}\n };\n}\n\n// src/utils.ts\nfunction getElementIdentifier(element, index, tagName) {\n const parts = [`${tagName} #${index + 1}`];\n const id = element.getAttribute(\"id\");\n if (id) {\n parts.push(`id=\"${id}\"`);\n }\n const classes = element.getAttribute(\"class\");\n if (classes) {\n const firstClass = classes.trim().split(/\\s+/)[0];\n if (firstClass) {\n parts.push(`class=\"${firstClass}\"`);\n }\n }\n const text = element.textContent?.trim();\n if (text && text.length > 0) {\n const preview = text.length > 40 ? text.substring(0, 40) + \"...\" : text;\n parts.push(`text=\"${preview}\"`);\n }\n return parts.join(\", \");\n}\nexport {\n audit,\n auditPage,\n calculateCategoryScores,\n calculateScore,\n canonicalUrlRule,\n coreRules,\n createDefaultConfig,\n faviconRule,\n fetchPage,\n getElementIdentifier,\n headingStructureRule,\n htmlLangRule,\n loadConfig,\n metaDescriptionRule,\n ogDescriptionRule,\n ogImageRule,\n ogTitleRule,\n ogUrlRule,\n robotsNoindexRule,\n ruleRegistry,\n runAsyncRules,\n runRules,\n runStandaloneRules,\n titleRule,\n twitterCardRule,\n validateUrl,\n viewportRule\n};\n//# sourceMappingURL=index.mjs.map","// src/rules/ssl.ts\nvar sslRule = {\n meta: {\n id: \"ssl\",\n name: \"SSL / HTTPS\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n description: \"Checks that the site is served over HTTPS\"\n },\n run(context) {\n const results = [];\n if (!context.isHttps) {\n results.push({\n ruleId: \"ssl\",\n ruleName: \"SSL / HTTPS\",\n message: \"Site is not using HTTPS - required for SEO and user trust. Search engines penalize HTTP sites.\",\n severity: \"CRITICAL\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Install an SSL certificate and redirect all HTTP traffic to HTTPS. Most hosting providers offer free SSL via Let's Encrypt.\"\n });\n }\n return results;\n }\n};\n\n// src/rules/robots-txt-check.ts\nvar robotsTxtCheckRule = {\n meta: {\n id: \"robots-txt-check\",\n name: \"robots.txt Check\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n description: \"Fetches and validates robots.txt for proper directives\"\n },\n async run(url) {\n const results = [];\n try {\n const robotsUrl = new URL(\"/robots.txt\", url).href;\n const response = await fetch(robotsUrl, {\n headers: { \"User-Agent\": \"LintPage-Bot/1.0\" }\n });\n if (!response.ok) {\n results.push({\n ruleId: \"robots-txt-check\",\n ruleName: \"robots.txt Check\",\n message: \"No robots.txt file found - recommended to have one\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: 'Create a robots.txt file at your site root with at least \"User-Agent: *\" and \"Allow: /\" directives.'\n });\n return results;\n }\n const content = await response.text();\n const lines = content.split(\"\\n\").map((line) => line.trim());\n const rules = /* @__PURE__ */ new Map();\n let currentUserAgent = \"*\";\n for (const line of lines) {\n if (!line || line.startsWith(\"#\")) continue;\n const [directive, ...valueParts] = line.split(\":\").map((part) => part.trim());\n const value = valueParts.join(\":\").trim();\n if (!directive || !value) continue;\n const upper = directive.toUpperCase();\n if (upper === \"USER-AGENT\") {\n currentUserAgent = value;\n if (!rules.has(currentUserAgent)) {\n rules.set(currentUserAgent, { disallow: [], allow: [] });\n }\n } else if (upper === \"DISALLOW\") {\n const r = rules.get(currentUserAgent) || {\n disallow: [],\n allow: []\n };\n r.disallow.push(value);\n rules.set(currentUserAgent, r);\n } else if (upper === \"ALLOW\") {\n const r = rules.get(currentUserAgent) || {\n disallow: [],\n allow: []\n };\n r.allow.push(value);\n rules.set(currentUserAgent, r);\n }\n }\n const wildcard = rules.get(\"*\");\n if (wildcard && wildcard.disallow.includes(\"/\")) {\n results.push({\n ruleId: \"robots-txt-check\",\n ruleName: \"robots.txt Check\",\n message: 'robots.txt contains \"Disallow: /\" for User-Agent: * - this blocks ALL search engines from crawling your entire site!',\n severity: \"CRITICAL\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: 'Change \"Disallow: /\" to \"Allow: /\" in your robots.txt, or remove the Disallow directive entirely.'\n });\n }\n if (!content.toLowerCase().includes(\"sitemap\")) {\n results.push({\n ruleId: \"robots-txt-check\",\n ruleName: \"robots.txt Check\",\n message: \"robots.txt does not reference sitemap.xml - consider adding a Sitemap directive\",\n severity: \"INFO\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: 'Add \"Sitemap: https://yoursite.com/sitemap.xml\" to the end of your robots.txt file.'\n });\n }\n const hasMalformedLines = lines.some((line) => {\n if (!line || line.startsWith(\"#\")) return false;\n return !line.includes(\":\") && line.length > 0;\n });\n if (hasMalformedLines) {\n results.push({\n ruleId: \"robots-txt-check\",\n ruleName: \"robots.txt Check\",\n message: 'robots.txt may have syntax errors - ensure each directive follows \"Directive: value\" format',\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: 'Review each line in robots.txt. Every directive must follow the \"Directive: value\" format (e.g., \"User-Agent: *\").'\n });\n }\n if (rules.size === 0 || rules.size === 1 && !rules.has(\"*\")) {\n results.push({\n ruleId: \"robots-txt-check\",\n ruleName: \"robots.txt Check\",\n message: \"robots.txt exists but has no rules defined - add User-Agent and Disallow/Allow directives\",\n severity: \"INFO\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: 'Add at minimum \"User-Agent: *\" followed by \"Allow: /\" to your robots.txt.'\n });\n }\n } catch {\n results.push({\n ruleId: \"robots-txt-check\",\n ruleName: \"robots.txt Check\",\n message: \"Could not fetch robots.txt - ensure it exists at root domain\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Create a robots.txt file at your domain root (e.g., https://yoursite.com/robots.txt).\"\n });\n }\n return results;\n }\n};\n\n// src/rules/sitemap-presence.ts\nvar sitemapPresenceRule = {\n meta: {\n id: \"sitemap-presence\",\n name: \"Sitemap Presence\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n description: \"Checks for the existence and validity of sitemap.xml\"\n },\n async run(url) {\n const results = [];\n try {\n const sitemapUrl = new URL(\"/sitemap.xml\", url).href;\n const response = await fetch(sitemapUrl, {\n headers: { \"User-Agent\": \"LintPage-Bot/1.0\" }\n });\n if (!response.ok) {\n results.push({\n ruleId: \"sitemap-presence\",\n ruleName: \"Sitemap Presence\",\n message: \"No sitemap.xml found - recommended for search engines to discover your pages\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Generate a sitemap.xml and place it at your domain root. Most frameworks (Next.js, WordPress) have built-in sitemap generation.\"\n });\n return results;\n }\n const content = await response.text();\n const isUrlset = content.includes(\"<urlset\");\n const isSitemapIndex = content.includes(\"<sitemapindex\");\n if (!content.includes(\"<?xml\") || !isUrlset && !isSitemapIndex) {\n results.push({\n ruleId: \"sitemap-presence\",\n ruleName: \"Sitemap Presence\",\n message: \"sitemap.xml exists but may not be valid XML format\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: 'Ensure your sitemap.xml starts with <?xml version=\"1.0\"?> and uses the <urlset> or <sitemapindex> element with proper namespace.'\n });\n }\n if (isSitemapIndex) {\n const sitemapMatches = content.match(/<sitemap>/g);\n if (!sitemapMatches || sitemapMatches.length === 0) {\n results.push({\n ruleId: \"sitemap-presence\",\n ruleName: \"Sitemap Presence\",\n message: \"Sitemap index file is empty - add child sitemap references\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Add <sitemap><loc>https://yoursite.com/sitemap-pages.xml</loc></sitemap> entries to your sitemap index.\"\n });\n }\n return results;\n }\n const urlMatches = content.match(/<loc>/g);\n const urlCount = urlMatches ? urlMatches.length : 0;\n if (urlCount === 0) {\n results.push({\n ruleId: \"sitemap-presence\",\n ruleName: \"Sitemap Presence\",\n message: \"sitemap.xml is empty - add URLs to help search engines discover content\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Add <url><loc>https://yoursite.com/page</loc></url> entries to your sitemap for each page you want indexed.\"\n });\n }\n } catch {\n results.push({\n ruleId: \"sitemap-presence\",\n ruleName: \"Sitemap Presence\",\n message: \"Could not fetch sitemap.xml - create one at /sitemap.xml\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Create a sitemap.xml at your domain root. Use a sitemap generator or your framework's built-in sitemap feature.\"\n });\n }\n return results;\n }\n};\n\n// src/rules/tracking.ts\nvar trackingRule = {\n meta: {\n id: \"tracking\",\n name: \"Analytics Tracking\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n description: \"Checks for Google Analytics, Google Tag Manager, or Facebook Pixel\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n let foundAnalytics = false;\n const scripts = document.querySelectorAll(\"script\");\n const html = document.documentElement?.outerHTML || \"\";\n scripts.forEach((script) => {\n const src = script.getAttribute(\"src\") || \"\";\n const content = script.textContent || \"\";\n if (src.includes(\"googletagmanager.com/gtag/js\") || content.includes(\"gtag(\")) {\n foundAnalytics = true;\n }\n if (src.includes(\"googletagmanager.com/gtm.js\") || content.includes(\"GTM-\")) {\n foundAnalytics = true;\n }\n if (src.includes(\"plausible.io/js/\")) {\n foundAnalytics = true;\n }\n if (src.includes(\"usefathom.com/script.js\") || src.includes(\"cdn.usefathom.com\")) {\n foundAnalytics = true;\n }\n if (src.includes(\"matomo.js\") || src.includes(\"matomo.php\") || src.includes(\"piwik.js\")) {\n foundAnalytics = true;\n }\n if (src.includes(\"posthog-js\") || src.includes(\"i.posthog.com\")) {\n foundAnalytics = true;\n }\n if (src.includes(\"cdn.mxpnl.com\") || src.includes(\"mixpanel.com\")) {\n foundAnalytics = true;\n }\n if (src.includes(\"va.vercel-scripts.com\") || src.includes(\"vitals.vercel-insights.com\")) {\n foundAnalytics = true;\n }\n if (src.includes(\"static.cloudflareinsights.com\")) {\n foundAnalytics = true;\n }\n if (src.includes(\"umami.js\") || src.includes(\"umami.is/script.js\")) {\n foundAnalytics = true;\n }\n if (src.includes(\"clarity.ms/tag\")) {\n foundAnalytics = true;\n }\n });\n if (!foundAnalytics && (html.includes(\"@vercel/analytics\") || html.includes(\"vercel-analytics\"))) {\n foundAnalytics = true;\n }\n if (!foundAnalytics) {\n results.push({\n ruleId: \"tracking\",\n ruleName: \"Analytics Tracking\",\n message: \"No analytics tracking found - you won't be able to measure traffic after launch\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Add an analytics solution to your site. Options include Google Analytics, Plausible, Fathom, Matomo, PostHog, Vercel Analytics, Umami, or Cloudflare Web Analytics.\",\n data: { foundAnalytics }\n });\n }\n return results;\n }\n};\n\n// src/rules/x-robots-tag.ts\nvar xRobotsTagRule = {\n meta: {\n id: \"x-robots-tag\",\n name: \"X-Robots-Tag Header\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n description: \"Checks the X-Robots-Tag HTTP header for noindex/nofollow\"\n },\n run(context) {\n const { response } = context;\n const results = [];\n const value = response.headers.get(\"x-robots-tag\");\n if (!value) return results;\n const lower = value.toLowerCase();\n if (lower.includes(\"noindex\")) {\n results.push({\n ruleId: \"x-robots-tag\",\n ruleName: \"X-Robots-Tag Header\",\n message: 'X-Robots-Tag HTTP header contains \"noindex\" - page will NOT be indexed by search engines!',\n severity: \"CRITICAL\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: 'Remove the X-Robots-Tag header from your server configuration, or change its value to \"index, follow\".',\n data: { value }\n });\n }\n if (lower.includes(\"nofollow\")) {\n results.push({\n ruleId: \"x-robots-tag\",\n ruleName: \"X-Robots-Tag Header\",\n message: 'X-Robots-Tag HTTP header contains \"nofollow\" - links will not be followed by search engines',\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Remove \"nofollow\" from the X-Robots-Tag header if you want search engines to follow your links.',\n data: { value }\n });\n }\n return results;\n }\n};\n\n// src/rules/thin-content.ts\nvar thinContentRule = {\n meta: {\n id: \"thin-content\",\n name: \"Thin Content\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Checks that the page has sufficient text content for search engines\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const bodyText = document.body?.textContent || \"\";\n const wordCount = bodyText.trim().split(/\\s+/).filter(Boolean).length;\n if (wordCount < 300) {\n results.push({\n ruleId: \"thin-content\",\n ruleName: \"Thin Content\",\n message: `Page has thin content (${wordCount} words) - search engines prefer pages with substantial content (300+ words)`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Add more meaningful text content to the page. Search engines rank pages with substantial, relevant content higher.\",\n data: { wordCount }\n });\n }\n return results;\n }\n};\n\n// src/rules/duplicate-meta.ts\nvar duplicateMetaRule = {\n meta: {\n id: \"duplicate-meta\",\n name: \"Duplicate Meta Tags\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Checks for duplicate title, meta description, and canonical tags\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const titleTags = document.querySelectorAll(\"title\");\n if (titleTags.length > 1) {\n results.push({\n ruleId: \"duplicate-meta\",\n ruleName: \"Duplicate Meta Tags\",\n message: `Found ${titleTags.length} <title> tags - should have exactly one`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Remove duplicate <title> tags. Keep only one in your <head> element.\",\n data: { count: titleTags.length, tag: \"title\" }\n });\n }\n const descriptionTags = document.querySelectorAll(\n 'meta[name=\"description\"]'\n );\n if (descriptionTags.length > 1) {\n results.push({\n ruleId: \"duplicate-meta\",\n ruleName: \"Duplicate Meta Tags\",\n message: `Found ${descriptionTags.length} meta description tags - should have exactly one`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Remove duplicate <meta name=\"description\"> tags. Keep only one in your <head> element.',\n data: { count: descriptionTags.length, tag: \"meta-description\" }\n });\n }\n const canonicalTags = document.querySelectorAll('link[rel=\"canonical\"]');\n if (canonicalTags.length > 1) {\n results.push({\n ruleId: \"duplicate-meta\",\n ruleName: \"Duplicate Meta Tags\",\n message: `Found ${canonicalTags.length} canonical link tags - should have exactly one`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Remove duplicate <link rel=\"canonical\"> tags. Keep only one in your <head> element.',\n data: { count: canonicalTags.length, tag: \"canonical\" }\n });\n }\n return results;\n }\n};\n\n// src/rules/structured-data.ts\nvar structuredDataRule = {\n meta: {\n id: \"structured-data\",\n name: \"Structured Data\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Checks for the presence and validity of JSON-LD structured data\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const jsonLdScripts = document.querySelectorAll(\n 'script[type=\"application/ld+json\"]'\n );\n const types = [];\n jsonLdScripts.forEach((script) => {\n try {\n const data = JSON.parse(script.textContent || \"\");\n if (Array.isArray(data[\"@graph\"])) {\n for (const item of data[\"@graph\"]) {\n if (item[\"@type\"]) {\n types.push(item[\"@type\"]);\n }\n }\n } else if (data[\"@type\"]) {\n types.push(data[\"@type\"]);\n }\n } catch {\n results.push({\n ruleId: \"structured-data\",\n ruleName: \"Structured Data\",\n message: \"Invalid JSON-LD structured data found\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Validate your JSON-LD using Google's Rich Results Test tool and fix any JSON syntax errors.\"\n });\n }\n });\n if (types.length === 0) {\n results.push({\n ruleId: \"structured-data\",\n ruleName: \"Structured Data\",\n message: \"No structured data (JSON-LD) found\",\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Add a <script type=\"application/ld+json\"> block with Organization, WebPage, or other relevant schema.org types.',\n data: { types }\n });\n }\n return results;\n }\n};\n\n// src/rules/charset.ts\nvar charsetRule = {\n meta: {\n id: \"charset\",\n name: \"Character Encoding\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Checks for a proper charset/encoding declaration\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const charsetMeta = document.querySelector(\"meta[charset]\");\n const httpEquivMeta = document.querySelector(\n 'meta[http-equiv=\"Content-Type\"]'\n );\n if (!charsetMeta && !httpEquivMeta) {\n results.push({\n ruleId: \"charset\",\n ruleName: \"Character Encoding\",\n message: \"Missing character encoding declaration - may cause rendering issues with special characters\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Add <meta charset=\"utf-8\" /> as the first element in your <head> tag.'\n });\n }\n return results;\n }\n};\n\n// src/rules/image-alt-text.ts\nvar imageAltTextRule = {\n meta: {\n id: \"image-alt-text\",\n name: \"Image Alt Text\",\n category: \"Accessibility\",\n tier: \"pro\",\n description: \"Checks that all images have alt attributes\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const images = document.querySelectorAll(\"img\");\n let missingAlt = 0;\n images.forEach((img) => {\n const alt = img.getAttribute(\"alt\");\n if (alt === null || alt === void 0) {\n missingAlt++;\n }\n });\n if (missingAlt > 0) {\n results.push({\n ruleId: \"image-alt-text\",\n ruleName: \"Image Alt Text\",\n message: `${missingAlt} of ${images.length} images missing alt attributes`,\n severity: \"WARNING\",\n category: \"Accessibility\",\n tier: \"pro\",\n fix: 'Add descriptive alt attributes to all images. Screen readers use alt text to describe images to visually impaired users. Use alt=\"\" for decorative images.',\n data: { total: images.length, missingAlt }\n });\n }\n return results;\n }\n};\n\n// src/rules/accessibility.ts\nvar accessibilityRule = {\n meta: {\n id: \"accessibility\",\n name: \"Accessibility & ARIA\",\n category: \"Accessibility\",\n tier: \"pro\",\n description: \"Checks buttons, links, inputs, and ARIA attributes for accessibility\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const buttons = document.querySelectorAll(\"button\");\n let inaccessibleButtons = 0;\n buttons.forEach((button) => {\n const hasText = button.textContent?.trim();\n const hasAriaLabel = button.getAttribute(\"aria-label\");\n const hasAriaLabelledBy = button.getAttribute(\"aria-labelledby\");\n if (!hasText && !hasAriaLabel && !hasAriaLabelledBy) {\n inaccessibleButtons++;\n }\n });\n if (inaccessibleButtons > 0) {\n results.push({\n ruleId: \"accessibility\",\n ruleName: \"Accessibility & ARIA\",\n message: `${inaccessibleButtons} button(s) missing accessible name (no text, aria-label, or aria-labelledby)`,\n severity: \"WARNING\",\n category: \"Accessibility\",\n tier: \"pro\",\n fix: \"Add visible text content, an aria-label, or aria-labelledby attribute to each button.\",\n data: { inaccessibleButtons }\n });\n }\n const links = document.querySelectorAll(\"a\");\n let inaccessibleLinks = 0;\n links.forEach((link) => {\n const hasText = link.textContent?.trim();\n const hasAriaLabel = link.getAttribute(\"aria-label\");\n const hasAriaLabelledBy = link.getAttribute(\"aria-labelledby\");\n if (!hasText && !hasAriaLabel && !hasAriaLabelledBy) {\n inaccessibleLinks++;\n }\n });\n if (inaccessibleLinks > 0) {\n results.push({\n ruleId: \"accessibility\",\n ruleName: \"Accessibility & ARIA\",\n message: `${inaccessibleLinks} link(s) missing accessible name (no text, aria-label, or aria-labelledby)`,\n severity: \"WARNING\",\n category: \"Accessibility\",\n tier: \"pro\",\n fix: \"Add descriptive text content, an aria-label, or aria-labelledby attribute to each link so screen readers can identify it.\",\n data: { inaccessibleLinks }\n });\n }\n const inputs = document.querySelectorAll(\"input:not([type='hidden'])\");\n let unlabeledInputs = 0;\n inputs.forEach((input) => {\n const id = input.getAttribute(\"id\");\n const ariaLabel = input.getAttribute(\"aria-label\");\n const ariaLabelledBy = input.getAttribute(\"aria-labelledby\");\n const title = input.getAttribute(\"title\");\n const hasExplicitLabel = id && document.querySelector(`label[for=\"${id}\"]`);\n const hasImplicitLabel = input.closest(\"label\") !== null;\n if (!hasExplicitLabel && !hasImplicitLabel && !ariaLabel && !ariaLabelledBy && !title) {\n unlabeledInputs++;\n }\n });\n if (unlabeledInputs > 0) {\n results.push({\n ruleId: \"accessibility\",\n ruleName: \"Accessibility & ARIA\",\n message: `${unlabeledInputs} input(s) missing associated label`,\n severity: \"WARNING\",\n category: \"Accessibility\",\n tier: \"pro\",\n fix: 'Add a <label for=\"inputId\"> element, or add an aria-label attribute to each input.',\n data: { unlabeledInputs }\n });\n }\n const divButtons = document.querySelectorAll(\n \"div[onclick], span[onclick]\"\n );\n let missingRoles = 0;\n divButtons.forEach((el) => {\n if (!el.getAttribute(\"role\")) missingRoles++;\n });\n if (missingRoles > 0) {\n results.push({\n ruleId: \"accessibility\",\n ruleName: \"Accessibility & ARIA\",\n message: `${missingRoles} interactive div/span element(s) missing role attribute`,\n severity: \"WARNING\",\n category: \"Accessibility\",\n tier: \"pro\",\n fix: 'Use a <button> element instead, or add role=\"button\" and an aria-label to interactive elements.',\n data: { missingRoles }\n });\n }\n const navElements = document.querySelectorAll(\n 'nav, [role=\"navigation\"]'\n );\n let unlabeledNav = 0;\n navElements.forEach((nav) => {\n const ariaLabel = nav.getAttribute(\"aria-label\");\n const ariaLabelledBy = nav.getAttribute(\"aria-labelledby\");\n if (!ariaLabel && !ariaLabelledBy) unlabeledNav++;\n });\n if (unlabeledNav > 0) {\n results.push({\n ruleId: \"accessibility\",\n ruleName: \"Accessibility & ARIA\",\n message: `${unlabeledNav} navigation element(s) missing aria-label or aria-labelledby`,\n severity: \"INFO\",\n category: \"Accessibility\",\n tier: \"pro\",\n fix: 'Add aria-label=\"Main navigation\" (or similar descriptive label) to your <nav> elements.',\n data: { unlabeledNav }\n });\n }\n return results;\n }\n};\n\n// src/rules/semantic-structure.ts\nvar semanticStructureRule = {\n meta: {\n id: \"semantic-structure\",\n name: \"Semantic Structure\",\n category: \"Accessibility\",\n tier: \"pro\",\n description: \"Checks for proper semantic HTML: landmarks, lists, tables, articles\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const main = document.querySelector(\"main\");\n if (!main) {\n results.push({\n ruleId: \"semantic-structure\",\n ruleName: \"Semantic Structure\",\n message: \"Missing <main> element - should wrap primary page content for better structure\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Wrap your primary page content in a <main> element. There should be exactly one per page.\"\n });\n }\n const semanticElements = document.querySelectorAll(\n \"main, section, article, aside, nav\"\n );\n if (semanticElements.length === 0) {\n results.push({\n ruleId: \"semantic-structure\",\n ruleName: \"Semantic Structure\",\n message: \"Missing semantic page regions - use <main>, <section>, <article>, <nav>, <aside> instead of generic divs\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Replace generic <div> containers with semantic elements: <main>, <nav>, <section>, <article>, <aside>.\"\n });\n }\n const listItems = document.querySelectorAll(\"li\");\n let orphanedLi = 0;\n listItems.forEach((li) => {\n const parent = li.parentElement;\n if (parent?.tagName !== \"UL\" && parent?.tagName !== \"OL\") {\n orphanedLi++;\n }\n });\n if (orphanedLi > 0) {\n results.push({\n ruleId: \"semantic-structure\",\n ruleName: \"Semantic Structure\",\n message: `${orphanedLi} <li> element(s) found outside of <ul> or <ol> - breaks semantic structure`,\n severity: \"WARNING\",\n category: \"Accessibility\",\n tier: \"pro\",\n fix: \"Wrap <li> elements inside a <ul> (unordered) or <ol> (ordered) list element.\",\n data: { orphanedLi }\n });\n }\n const tables = document.querySelectorAll(\"table\");\n let tablesWithoutHeaders = 0;\n tables.forEach((table) => {\n if (!table.querySelector(\"th\")) tablesWithoutHeaders++;\n });\n if (tablesWithoutHeaders > 0) {\n results.push({\n ruleId: \"semantic-structure\",\n ruleName: \"Semantic Structure\",\n message: `${tablesWithoutHeaders} table(s) missing <th> header cells`,\n severity: \"INFO\",\n category: \"Accessibility\",\n tier: \"pro\",\n fix: \"Add <th> cells to define table column or row headers. Optionally wrap them in a <thead> element for additional structure.\",\n data: { tablesWithoutHeaders }\n });\n }\n const articles = document.querySelectorAll(\"article\");\n let articlesWithoutHeading = 0;\n articles.forEach((article) => {\n if (!article.querySelector(\"h1, h2, h3, h4, h5, h6\")) {\n articlesWithoutHeading++;\n }\n });\n if (articlesWithoutHeading > 0) {\n results.push({\n ruleId: \"semantic-structure\",\n ruleName: \"Semantic Structure\",\n message: `${articlesWithoutHeading} <article> element(s) without a heading`,\n severity: \"INFO\",\n category: \"Accessibility\",\n tier: \"pro\",\n fix: \"Add a heading (h2-h6) inside each <article> element to provide context.\",\n data: { articlesWithoutHeading }\n });\n }\n return results;\n }\n};\n\n// src/rules/performance.ts\nvar performanceRule = {\n meta: {\n id: \"performance\",\n name: \"Performance Hints\",\n category: \"Performance\",\n tier: \"pro\",\n description: \"Checks for inline styles, lazy loading, and script count\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const images = document.querySelectorAll(\"img\");\n const belowFoldImages = Array.from(images).slice(3);\n let noLazyLoad = 0;\n belowFoldImages.forEach((img) => {\n if (!img.getAttribute(\"loading\")) noLazyLoad++;\n });\n if (noLazyLoad > 0) {\n results.push({\n ruleId: \"performance\",\n ruleName: \"Performance Hints\",\n message: `${noLazyLoad} below-the-fold image(s) without loading=\"lazy\" - add lazy loading to defer offscreen images`,\n severity: \"INFO\",\n category: \"Performance\",\n tier: \"pro\",\n fix: 'Add loading=\"lazy\" to images below the fold. Do NOT add loading=\"lazy\" to above-the-fold or LCP images - this hurts performance (per web.dev).',\n data: { noLazyLoad, totalImages: images.length }\n });\n }\n const scripts = document.querySelectorAll(\"script[src]\");\n if (scripts.length > 10) {\n results.push({\n ruleId: \"performance\",\n ruleName: \"Performance Hints\",\n message: `Consider reducing external scripts (${scripts.length} found) for better performance`,\n severity: \"INFO\",\n category: \"Performance\",\n tier: \"pro\",\n fix: \"Audit your scripts and remove unused ones. Consider bundling or deferring non-critical scripts.\",\n data: { scriptCount: scripts.length }\n });\n }\n return results;\n }\n};\n\n// src/rules/image-dimensions.ts\nvar imageDimensionsRule = {\n meta: {\n id: \"image-dimensions\",\n name: \"Image Dimensions\",\n category: \"Performance\",\n tier: \"pro\",\n description: \"Checks that images have explicit width and height to prevent layout shift (CLS)\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const images = document.querySelectorAll(\"img\");\n let missingCount = 0;\n images.forEach((img) => {\n const hasWidth = img.getAttribute(\"width\");\n const hasHeight = img.getAttribute(\"height\");\n if (!hasWidth || !hasHeight) missingCount++;\n });\n if (missingCount > 0) {\n results.push({\n ruleId: \"image-dimensions\",\n ruleName: \"Image Dimensions\",\n message: `${missingCount} image${missingCount !== 1 ? \"s\" : \"\"} missing explicit width/height attributes - causes layout shift (CLS)`,\n severity: \"INFO\",\n category: \"Performance\",\n tier: \"pro\",\n fix: \"Add width and height attributes to <img> tags to reserve space and prevent layout shift.\",\n data: { missingCount, totalImages: images.length }\n });\n }\n return results;\n }\n};\n\n// src/rules/ttfb.ts\nvar ttfbRule = {\n meta: {\n id: \"ttfb-pro\",\n name: \"Time to First Byte (Pro)\",\n category: \"Performance\",\n tier: \"pro\",\n description: \"Measures server response time (TTFB) with detailed thresholds\"\n },\n async run(url) {\n const results = [];\n try {\n const start = Date.now();\n await fetch(url, {\n headers: { \"User-Agent\": \"LintPage-Bot/1.0\" }\n });\n const ttfbMs = Date.now() - start;\n if (ttfbMs > 1800) {\n results.push({\n ruleId: \"ttfb-pro\",\n ruleName: \"Time to First Byte (Pro)\",\n message: `Slow server response time (TTFB: ${ttfbMs}ms) - aim for under 800ms`,\n severity: \"WARNING\",\n category: \"Performance\",\n tier: \"pro\",\n fix: \"Optimize server response time: enable caching, use a CDN, optimize database queries, or upgrade hosting.\",\n data: { ms: ttfbMs }\n });\n } else if (ttfbMs > 800) {\n results.push({\n ruleId: \"ttfb-pro\",\n ruleName: \"Time to First Byte (Pro)\",\n message: `Server response time could be improved (TTFB: ${ttfbMs}ms) - aim for under 800ms`,\n severity: \"INFO\",\n category: \"Performance\",\n tier: \"pro\",\n fix: \"Consider enabling server-side caching or using a CDN to reduce response time.\",\n data: { ms: ttfbMs }\n });\n }\n } catch {\n results.push({\n ruleId: \"ttfb-pro\",\n ruleName: \"Time to First Byte (Pro)\",\n message: \"Could not measure TTFB - server may be unreachable\",\n severity: \"WARNING\",\n category: \"Performance\",\n tier: \"pro\",\n fix: \"Ensure your server is accessible and responding to requests.\"\n });\n }\n return results;\n }\n};\n\n// src/rules/mixed-content.ts\nvar mixedContentRule = {\n meta: {\n id: \"mixed-content\",\n name: \"Mixed Content\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n description: \"Checks for HTTP resources loaded on an HTTPS page (mixed content)\"\n },\n run(context) {\n const { document, isHttps } = context;\n const results = [];\n if (!isHttps) return results;\n const selectors = [\n 'img[src^=\"http:\"]',\n 'script[src^=\"http:\"]',\n 'link[href^=\"http:\"]',\n 'iframe[src^=\"http:\"]',\n 'video[src^=\"http:\"]',\n 'audio[src^=\"http:\"]',\n 'object[data^=\"http:\"]',\n 'source[src^=\"http:\"]'\n ];\n let count = 0;\n selectors.forEach((selector) => {\n count += document.querySelectorAll(selector).length;\n });\n if (count > 0) {\n results.push({\n ruleId: \"mixed-content\",\n ruleName: \"Mixed Content\",\n message: `Found ${count} mixed content resource${count !== 1 ? \"s\" : \"\"} (HTTP on HTTPS page) - browsers may block these`,\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Change all resource URLs from http:// to https:// or use protocol-relative URLs (//).\",\n data: { count }\n });\n }\n return results;\n }\n};\n\n// src/rules/security-headers.ts\nvar securityHeadersRule = {\n meta: {\n id: \"security-headers\",\n name: \"Security Headers\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n description: \"Checks for important security headers (CSP, HSTS, X-Content-Type-Options, Permissions-Policy)\"\n },\n run(context) {\n const { response } = context;\n const results = [];\n const headers = [\n { name: \"content-security-policy\", label: \"Content-Security-Policy\" },\n {\n name: \"strict-transport-security\",\n label: \"Strict-Transport-Security (HSTS)\"\n },\n { name: \"x-content-type-options\", label: \"X-Content-Type-Options\" },\n { name: \"permissions-policy\", label: \"Permissions-Policy\" }\n ];\n const missing = [];\n headers.forEach(({ name, label }) => {\n if (!response.headers.get(name)) missing.push(label);\n });\n if (missing.length > 0) {\n results.push({\n ruleId: \"security-headers\",\n ruleName: \"Security Headers\",\n message: `Missing security headers: ${missing.join(\", \")}`,\n severity: \"INFO\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Configure your server or hosting provider to send these security headers. Most can be set in next.config.js headers() or your CDN settings.\",\n data: { missing }\n });\n }\n return results;\n }\n};\n\n// src/rules/og-image-size.ts\nvar ogImageSizeRule = {\n meta: {\n id: \"og-image-size\",\n name: \"OG Image Size\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Checks that the og:image URL exists and advises on recommended dimensions (1200x630)\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const ogImage = document.querySelector('meta[property=\"og:image\"]');\n const imageUrl = ogImage?.getAttribute(\"content\")?.trim();\n if (!imageUrl) return results;\n const ogWidth = document.querySelector('meta[property=\"og:image:width\"]');\n const ogHeight = document.querySelector(\n 'meta[property=\"og:image:height\"]'\n );\n const width = Number.parseInt(\n ogWidth?.getAttribute(\"content\") || \"\",\n 10\n );\n const height = Number.parseInt(\n ogHeight?.getAttribute(\"content\") || \"\",\n 10\n );\n if (!ogWidth || !ogHeight || Number.isNaN(width) || Number.isNaN(height)) {\n results.push({\n ruleId: \"og-image-size\",\n ruleName: \"OG Image Size\",\n message: \"Missing og:image:width and og:image:height meta tags - social platforms may crop your image incorrectly\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Add <meta property=\"og:image:width\" content=\"1200\" /> and <meta property=\"og:image:height\" content=\"630\" /> to your <head>.'\n });\n return results;\n }\n if (width < 1200 || height < 630) {\n results.push({\n ruleId: \"og-image-size\",\n ruleName: \"OG Image Size\",\n message: `OG image dimensions (${width}x${height}) are below recommended 1200x630 - may appear blurry on social platforms`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Use an image at least 1200x630 pixels for best display on Facebook, LinkedIn, and other social platforms.\",\n data: { width, height }\n });\n }\n return results;\n }\n};\n\n// src/rules/og-image-type.ts\nvar SUPPORTED_TYPES = /* @__PURE__ */ new Set([\n \"image/jpeg\",\n \"image/png\",\n \"image/gif\",\n \"image/webp\"\n]);\nvar SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([\n \".jpg\",\n \".jpeg\",\n \".png\",\n \".gif\",\n \".webp\"\n]);\nvar ogImageTypeRule = {\n meta: {\n id: \"og-image-type\",\n name: \"OG Image Type\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Checks that the og:image type is a widely-supported format (JPEG, PNG, GIF, WebP)\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const ogImage = document.querySelector('meta[property=\"og:image\"]');\n const imageUrl = ogImage?.getAttribute(\"content\")?.trim();\n if (!imageUrl) return results;\n const ogType = document.querySelector('meta[property=\"og:image:type\"]')?.getAttribute(\"content\")?.trim();\n if (ogType && !SUPPORTED_TYPES.has(ogType.toLowerCase())) {\n results.push({\n ruleId: \"og-image-type\",\n ruleName: \"OG Image Type\",\n message: `OG image type \"${ogType}\" may not be supported by all social platforms`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Use JPEG or PNG for og:image. These formats are supported by all social platforms.\",\n data: { type: ogType }\n });\n return results;\n }\n if (!ogType) {\n try {\n const url = new URL(imageUrl, \"https://example.com\");\n const ext = url.pathname.substring(url.pathname.lastIndexOf(\".\")).toLowerCase();\n if (ext && !SUPPORTED_EXTENSIONS.has(ext)) {\n results.push({\n ruleId: \"og-image-type\",\n ruleName: \"OG Image Type\",\n message: `OG image URL has extension \"${ext}\" which may not be supported by all social platforms`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Use JPEG or PNG for og:image, and add <meta property=\"og:image:type\" content=\"image/jpeg\" /> to your <head>.',\n data: { extension: ext }\n });\n }\n } catch {\n }\n }\n return results;\n }\n};\n\n// src/rules/twitter-image.ts\nvar twitterImageRule = {\n meta: {\n id: \"twitter-image\",\n name: \"Twitter/X Image\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Checks for twitter:image meta tag for rich card previews on X/Twitter\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const twitterCard = document.querySelector('meta[name=\"twitter:card\"]');\n if (!twitterCard) return results;\n const twitterImage = document.querySelector(\n 'meta[name=\"twitter:image\"]'\n );\n const ogImage = document.querySelector('meta[property=\"og:image\"]');\n if (!twitterImage && !ogImage) {\n results.push({\n ruleId: \"twitter-image\",\n ruleName: \"Twitter/X Image\",\n message: \"Twitter card present but no twitter:image or og:image found - tweets will have no image preview\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Add <meta name=\"twitter:image\" content=\"https://yoursite.com/image.png\" /> to your <head>.'\n });\n } else if (!twitterImage && ogImage) {\n results.push({\n ruleId: \"twitter-image\",\n ruleName: \"Twitter/X Image\",\n message: \"No explicit twitter:image - falling back to og:image. Consider adding twitter:image for optimal display.\",\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Add <meta name=\"twitter:image\" content=\"...\" /> for more control over how your image appears on X/Twitter.'\n });\n }\n return results;\n }\n};\n\n// src/rules/social-preview-render.ts\nvar socialPreviewRenderRule = {\n meta: {\n id: \"social-preview-render\",\n name: \"Social Preview Completeness\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Checks that all essential meta tags for social sharing previews are present and consistent\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const ogTitle = document.querySelector('meta[property=\"og:title\"]')?.getAttribute(\"content\");\n const ogDesc = document.querySelector('meta[property=\"og:description\"]')?.getAttribute(\"content\");\n const ogImage = document.querySelector('meta[property=\"og:image\"]')?.getAttribute(\"content\");\n const ogUrl = document.querySelector('meta[property=\"og:url\"]')?.getAttribute(\"content\");\n const ogType = document.querySelector('meta[property=\"og:type\"]')?.getAttribute(\"content\");\n const title = document.querySelector(\"title\")?.textContent?.trim();\n const metaDesc = document.querySelector('meta[name=\"description\"]')?.getAttribute(\"content\");\n if (!ogType) {\n results.push({\n ruleId: \"social-preview-render\",\n ruleName: \"Social Preview Completeness\",\n message: \"Missing og:type meta tag - required by the Open Graph protocol and needed for correct social preview rendering\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Add <meta property=\"og:type\" content=\"website\" /> (or \"article\" for blog posts) to your <head>. This is a required property per the Open Graph protocol.'\n });\n }\n if (ogImage && ogImage.trim()) {\n const ogImageAlt = document.querySelector('meta[property=\"og:image:alt\"]')?.getAttribute(\"content\");\n if (!ogImageAlt) {\n results.push({\n ruleId: \"social-preview-render\",\n ruleName: \"Social Preview Completeness\",\n message: \"Missing og:image:alt - the Open Graph protocol recommends providing alt text when og:image is set\",\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Add <meta property=\"og:image:alt\" content=\"Description of the image\" /> to your <head> for accessibility.'\n });\n }\n }\n if (ogTitle && title && ogTitle.length > 0 && title.length > 0) {\n if (ogTitle.length > 60) {\n results.push({\n ruleId: \"social-preview-render\",\n ruleName: \"Social Preview Completeness\",\n message: `og:title is ${ogTitle.length} characters - may be truncated on social platforms (recommended: 50-60)`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Keep og:title under 60 characters for best display on social platforms.\",\n data: { ogTitleLength: ogTitle.length }\n });\n }\n }\n if (ogDesc && ogDesc.length > 200) {\n results.push({\n ruleId: \"social-preview-render\",\n ruleName: \"Social Preview Completeness\",\n message: `og:description is ${ogDesc.length} characters - may be truncated on social platforms (recommended: under 200)`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Keep og:description under 200 characters for best display on social platforms.\",\n data: { ogDescLength: ogDesc.length }\n });\n }\n if (ogUrl && !ogUrl.startsWith(\"http\")) {\n results.push({\n ruleId: \"social-preview-render\",\n ruleName: \"Social Preview Completeness\",\n message: \"og:url should be an absolute URL starting with https://\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Change og:url to an absolute URL (e.g., https://yoursite.com/page).\"\n });\n }\n if (ogImage && !ogImage.startsWith(\"http\")) {\n results.push({\n ruleId: \"social-preview-render\",\n ruleName: \"Social Preview Completeness\",\n message: \"og:image should be an absolute URL starting with https://\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Change og:image to an absolute URL (e.g., https://yoursite.com/image.png).\"\n });\n }\n return results;\n }\n};\n\n// src/rules/title-keyword-stuffing.ts\nvar titleKeywordStuffingRule = {\n meta: {\n id: \"title-keyword-stuffing\",\n name: \"Title Keyword Stuffing\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Detects potential keyword stuffing in the page title\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const title = document.querySelector(\"title\")?.textContent?.trim();\n if (!title) return results;\n const words = title.toLowerCase().split(/[\\s\\-|:,]+/).filter((w) => w.length > 3);\n const wordCounts = /* @__PURE__ */ new Map();\n for (const word of words) {\n wordCounts.set(word, (wordCounts.get(word) || 0) + 1);\n }\n const stuffedWords = [];\n for (const [word, count] of wordCounts) {\n if (count >= 3) stuffedWords.push(`\"${word}\" (${count}x)`);\n }\n if (stuffedWords.length > 0) {\n results.push({\n ruleId: \"title-keyword-stuffing\",\n ruleName: \"Title Keyword Stuffing\",\n message: `Potential keyword stuffing in title: ${stuffedWords.join(\", \")}`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Write a natural, readable title. Avoid repeating the same keyword more than twice. Search engines may penalize keyword stuffing.\",\n data: { title, stuffedWords }\n });\n }\n const separatorCount = (title.match(/[|–—]/g) || []).length;\n if (separatorCount >= 3) {\n results.push({\n ruleId: \"title-keyword-stuffing\",\n ruleName: \"Title Keyword Stuffing\",\n message: `Title has ${separatorCount} separators - may appear spammy to search engines`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Simplify your title. Use at most one separator (|, \\u2013 or \\u2014) to separate the page name from your brand.\",\n data: { separatorCount }\n });\n }\n return results;\n }\n};\n\n// src/rules/content-to-html-ratio.ts\nvar contentToHtmlRatioRule = {\n meta: {\n id: \"content-to-html-ratio\",\n name: \"Content-to-HTML Ratio\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Checks the ratio of visible text to total HTML markup\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const htmlLength = document.documentElement?.outerHTML?.length || 0;\n if (htmlLength === 0) return results;\n const textContent = document.body?.textContent || \"\";\n const textLength = textContent.replace(/\\s+/g, \" \").trim().length;\n const ratio = Math.round(textLength / htmlLength * 100);\n if (ratio < 10) {\n results.push({\n ruleId: \"content-to-html-ratio\",\n ruleName: \"Content-to-HTML Ratio\",\n message: `Low content-to-HTML ratio (${ratio}%) - may indicate excessive markup or thin content`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Increase meaningful text content or reduce unnecessary HTML markup. Note: content-to-HTML ratio is not a direct ranking factor per Google, but correlates with page speed and code quality.\",\n data: { ratio, textLength, htmlLength }\n });\n } else if (ratio < 20) {\n results.push({\n ruleId: \"content-to-html-ratio\",\n ruleName: \"Content-to-HTML Ratio\",\n message: `Content-to-HTML ratio is ${ratio}% - could be improved (aim for 25%+)`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Consider adding more text content or reducing unnecessary HTML markup to improve the ratio.\",\n data: { ratio, textLength, htmlLength }\n });\n }\n return results;\n }\n};\n\n// src/rules/title-uniqueness.ts\nvar titleUniquenessRule = {\n meta: {\n id: \"title-uniqueness\",\n name: \"Title Uniqueness\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Flags titles that appear generic or auto-generated (single-page heuristic)\"\n },\n run(context) {\n const { document, url } = context;\n const results = [];\n const title = document.querySelector(\"title\")?.textContent?.trim();\n if (!title) return results;\n const genericPatterns = [\n /^home$/i,\n /^untitled/i,\n /^page \\d+$/i,\n /^welcome$/i,\n /^index$/i,\n /^document$/i,\n /^my site$/i,\n /^my website$/i,\n /^website$/i,\n /^new page$/i\n ];\n for (const pattern of genericPatterns) {\n if (pattern.test(title)) {\n results.push({\n ruleId: \"title-uniqueness\",\n ruleName: \"Title Uniqueness\",\n message: `Title \"${title}\" appears to be a generic/default title - use a unique, descriptive title`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Write a unique, descriptive title for each page that includes your target keyword.\",\n data: { title }\n });\n break;\n }\n }\n try {\n const hostname = new URL(url).hostname.replace(\"www.\", \"\");\n const domainName = hostname.split(\".\")[0];\n if (domainName && title.toLowerCase() === domainName.toLowerCase()) {\n results.push({\n ruleId: \"title-uniqueness\",\n ruleName: \"Title Uniqueness\",\n message: \"Title is just the domain name - add a descriptive page-specific title\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Include a page-specific description in your title, e.g., \"Product Name \\u2014 Your Brand\".',\n data: { title, hostname }\n });\n }\n } catch {\n }\n return results;\n }\n};\n\n// src/rules/description-uniqueness.ts\nvar descriptionUniquenessRule = {\n meta: {\n id: \"description-uniqueness\",\n name: \"Description Uniqueness\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Flags meta descriptions that appear generic or auto-generated (single-page heuristic)\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const metaDesc = document.querySelector('meta[name=\"description\"]');\n const description = metaDesc?.getAttribute(\"content\")?.trim();\n if (!description) return results;\n const genericPatterns = [\n /^welcome to/i,\n /^this is a website/i,\n /^a website about/i,\n /^home page/i,\n /^we are a company/i,\n /^default description/i\n ];\n for (const pattern of genericPatterns) {\n if (pattern.test(description)) {\n results.push({\n ruleId: \"description-uniqueness\",\n ruleName: \"Description Uniqueness\",\n message: `Meta description appears generic - write a unique, compelling description for this page`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Write a unique meta description for each page that summarizes the specific content and includes a call to action.\",\n data: { description }\n });\n break;\n }\n }\n const title = document.querySelector(\"title\")?.textContent?.trim();\n if (title && description.toLowerCase() === title.toLowerCase()) {\n results.push({\n ruleId: \"description-uniqueness\",\n ruleName: \"Description Uniqueness\",\n message: \"Meta description is identical to the title - they should be different and complementary\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Write a meta description that expands on your title with more detail, a value proposition, or a call to action.\",\n data: { description, title }\n });\n }\n return results;\n }\n};\n\n// src/rules/structured-data-validate.ts\nvar REQUIRED_FIELDS = {\n Organization: [\"name\", \"url\"],\n WebSite: [\"name\", \"url\"],\n WebPage: [\"name\"],\n BreadcrumbList: [\"itemListElement\"],\n LocalBusiness: [\"name\", \"address\"]\n};\nvar RECOMMENDED_FIELDS = {\n Article: [\"headline\", \"author\", \"datePublished\"],\n Product: [\"name\", \"image\", \"offers\"]\n};\nfunction validateJsonLdItem(data, inheritedContext, results) {\n const type = data[\"@type\"];\n if (!type) {\n results.push({\n ruleId: \"structured-data-validate\",\n ruleName: \"Structured Data Validation\",\n message: \"JSON-LD block missing @type property\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Add an @type property (e.g., \"Organization\", \"WebPage\", \"Article\") to your JSON-LD.'\n });\n return;\n }\n const context = data[\"@context\"] || inheritedContext;\n if (!context) {\n results.push({\n ruleId: \"structured-data-validate\",\n ruleName: \"Structured Data Validation\",\n message: `JSON-LD \"${type}\" missing @context - should be \"https://schema.org\"`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Add \"@context\": \"https://schema.org\" to your JSON-LD block.',\n data: { type }\n });\n }\n const required = REQUIRED_FIELDS[type];\n if (required) {\n const missing = required.filter((field) => !data[field]);\n if (missing.length > 0) {\n results.push({\n ruleId: \"structured-data-validate\",\n ruleName: \"Structured Data Validation\",\n message: `JSON-LD \"${type}\" missing required fields: ${missing.join(\", \")}`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: `Add the missing fields to your ${type} schema: ${missing.join(\", \")}.`,\n data: { type, missing }\n });\n }\n }\n const recommended = RECOMMENDED_FIELDS[type];\n if (recommended) {\n const missing = recommended.filter((field) => !data[field]);\n if (missing.length > 0) {\n results.push({\n ruleId: \"structured-data-validate\",\n ruleName: \"Structured Data Validation\",\n message: `JSON-LD \"${type}\" missing recommended fields: ${missing.join(\", \")}`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: `Add the recommended fields to your ${type} schema for richer search results: ${missing.join(\", \")}.`,\n data: { type, missing }\n });\n }\n }\n if (type === \"FAQPage\") {\n results.push({\n ruleId: \"structured-data-validate\",\n ruleName: \"Structured Data Validation\",\n message: \"FAQPage rich results are only shown for well-known, authoritative government and health websites. For all other sites, this rich result will no longer be shown regularly\",\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"You can keep or remove this markup. Unused structured data does not cause problems for Search, but it also has no visible effects in Google Search. Consider using other structured data types that still produce rich results for your site type.\",\n data: { type }\n });\n }\n}\nvar structuredDataValidateRule = {\n meta: {\n id: \"structured-data-validate\",\n name: \"Structured Data Validation\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Validates JSON-LD structured data for required fields based on schema type\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const jsonLdScripts = document.querySelectorAll(\n 'script[type=\"application/ld+json\"]'\n );\n jsonLdScripts.forEach((script) => {\n let data;\n try {\n data = JSON.parse(script.textContent || \"\");\n } catch {\n return;\n }\n if (Array.isArray(data[\"@graph\"])) {\n const rootContext = data[\"@context\"];\n for (const item of data[\"@graph\"]) {\n validateJsonLdItem(item, rootContext, results);\n }\n return;\n }\n validateJsonLdItem(data, void 0, results);\n });\n return results;\n }\n};\n\n// src/rules/hreflang.ts\nvar hreflangRule = {\n meta: {\n id: \"hreflang\",\n name: \"Hreflang Tags\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Validates hreflang tags for multi-language pages\"\n },\n run(context) {\n const { document, url } = context;\n const results = [];\n const hreflangTags = document.querySelectorAll(\n 'link[rel=\"alternate\"][hreflang]'\n );\n if (hreflangTags.length === 0) return results;\n const hasXDefault = Array.from(hreflangTags).some(\n (tag) => tag.getAttribute(\"hreflang\") === \"x-default\"\n );\n if (!hasXDefault) {\n results.push({\n ruleId: \"hreflang\",\n ruleName: \"Hreflang Tags\",\n message: \"Hreflang tags found but missing x-default - add a fallback for unmatched languages\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Add <link rel=\"alternate\" hreflang=\"x-default\" href=\"...\" /> to specify the default/fallback page.'\n });\n }\n const hasSelfRef = Array.from(hreflangTags).some((tag) => {\n const href = tag.getAttribute(\"href\");\n return href === url || href === url.replace(/\\/$/, \"\");\n });\n if (!hasSelfRef) {\n results.push({\n ruleId: \"hreflang\",\n ruleName: \"Hreflang Tags\",\n message: \"Hreflang tags do not include a self-referencing tag for the current page\",\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Add a hreflang tag that points to the current page URL with the appropriate language code.\"\n });\n }\n const langCodePattern = /^[a-z]{2}(-[A-Z]{2})?$/;\n hreflangTags.forEach((tag) => {\n const lang = tag.getAttribute(\"hreflang\");\n if (lang && lang !== \"x-default\" && !langCodePattern.test(lang)) {\n results.push({\n ruleId: \"hreflang\",\n ruleName: \"Hreflang Tags\",\n message: `Invalid hreflang language code \"${lang}\" - use ISO 639-1 format (e.g., \"en\", \"en-US\")`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: `Change \"${lang}\" to a valid ISO 639-1 language code (e.g., \"en\", \"fr\", \"de-AT\").`,\n data: { invalidLang: lang }\n });\n }\n const href = tag.getAttribute(\"href\");\n if (href && !href.startsWith(\"http\")) {\n results.push({\n ruleId: \"hreflang\",\n ruleName: \"Hreflang Tags\",\n message: `Hreflang href should be an absolute URL (found: \"${href}\")`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Use absolute URLs (starting with https://) for all hreflang href attributes.\"\n });\n }\n });\n return results;\n }\n};\n\n// src/rules/canonical-self-referencing.ts\nvar canonicalSelfReferencingRule = {\n meta: {\n id: \"canonical-self-referencing\",\n name: \"Canonical Self-Referencing\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Checks that the canonical URL points to the current page (self-referencing canonical)\"\n },\n run(context) {\n const { document, url } = context;\n const results = [];\n const canonical = document.querySelector('link[rel=\"canonical\"]');\n if (!canonical) return results;\n const href = canonical.getAttribute(\"href\")?.trim();\n if (!href) return results;\n const normalize = (u) => u.replace(/\\/$/, \"\").toLowerCase();\n try {\n const canonicalUrl = new URL(href, url).href;\n const normalizedCanonical = normalize(canonicalUrl);\n const normalizedUrl = normalize(url);\n if (normalizedCanonical !== normalizedUrl) {\n const sameHost = new URL(canonicalUrl).hostname === new URL(url).hostname;\n if (sameHost) {\n results.push({\n ruleId: \"canonical-self-referencing\",\n ruleName: \"Canonical Self-Referencing\",\n message: `Canonical URL points to a different page on the same site - this tells search engines to index \"${canonicalUrl}\" instead of this page`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"If this page should be indexed, change the canonical to point to itself. If this is intentional (e.g., pagination), you can ignore this.\",\n data: { canonical: canonicalUrl, pageUrl: url }\n });\n } else {\n results.push({\n ruleId: \"canonical-self-referencing\",\n ruleName: \"Canonical Self-Referencing\",\n message: `Canonical URL points to a different domain (\"${new URL(canonicalUrl).hostname}\") - this is unusual and may be a misconfiguration`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Cross-domain canonical tags are rarely correct. Verify this is intentional, otherwise change the canonical to point to this page.\",\n data: { canonical: canonicalUrl, pageUrl: url }\n });\n }\n }\n } catch {\n results.push({\n ruleId: \"canonical-self-referencing\",\n ruleName: \"Canonical Self-Referencing\",\n message: `Cannot parse canonical URL \"${href}\" - ensure it's a valid absolute URL`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Use a valid absolute URL for your canonical tag (e.g., https://yoursite.com/page).\"\n });\n }\n return results;\n }\n};\n\n// src/rules/meta-render-blocking.ts\nvar metaRenderBlockingRule = {\n meta: {\n id: \"meta-render-blocking\",\n name: \"Render-Blocking Resources\",\n category: \"Performance\",\n tier: \"pro\",\n description: \"Checks for render-blocking stylesheets and synchronous scripts in the <head>\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const head = document.querySelector(\"head\");\n if (!head) return results;\n const headScripts = head.querySelectorAll(\"script[src]\");\n let blockingScripts = 0;\n headScripts.forEach((script) => {\n const hasAsync = script.hasAttribute(\"async\");\n const hasDefer = script.hasAttribute(\"defer\");\n const type = script.getAttribute(\"type\");\n if (!hasAsync && !hasDefer && type !== \"module\") {\n blockingScripts++;\n }\n });\n if (blockingScripts > 0) {\n results.push({\n ruleId: \"meta-render-blocking\",\n ruleName: \"Render-Blocking Resources\",\n message: `${blockingScripts} synchronous script(s) in <head> may block page rendering`,\n severity: \"WARNING\",\n category: \"Performance\",\n tier: \"pro\",\n fix: \"Add async or defer attributes to non-critical scripts in the <head>, or move them to the end of <body>.\",\n data: { blockingScripts }\n });\n }\n const stylesheets = head.querySelectorAll(\n 'link[rel=\"stylesheet\"]'\n );\n let blockingStylesheets = 0;\n stylesheets.forEach((link) => {\n const media = link.getAttribute(\"media\");\n if (!media || media === \"all\") blockingStylesheets++;\n });\n if (blockingStylesheets > 3) {\n results.push({\n ruleId: \"meta-render-blocking\",\n ruleName: \"Render-Blocking Resources\",\n message: `${blockingStylesheets} render-blocking stylesheets in <head> - consider inlining critical CSS`,\n severity: \"INFO\",\n category: \"Performance\",\n tier: \"pro\",\n fix: 'Inline critical CSS and load non-critical stylesheets asynchronously using media=\"print\" with an onload handler.',\n data: { blockingStylesheets }\n });\n }\n return results;\n }\n};\n\n// src/rules/lazy-load-lcp.ts\nvar lazyLoadLcpRule = {\n meta: {\n id: \"lazy-load-lcp\",\n name: \"Lazy Load LCP\",\n category: \"Performance\",\n tier: \"pro\",\n description: \"Checks that above-the-fold images (likely LCP candidates) are not lazy-loaded\"\n },\n run(context) {\n const { document } = context;\n const results = [];\n const images = document.querySelectorAll(\"img\");\n const firstImages = Array.from(images).slice(0, 3);\n for (const img of firstImages) {\n const loading = img.getAttribute(\"loading\");\n const fetchpriority = img.getAttribute(\"fetchpriority\");\n if (loading === \"lazy\") {\n const src = img.getAttribute(\"src\") || \"\";\n const alt = img.getAttribute(\"alt\") || \"\";\n const identifier = alt ? `\"${alt.substring(0, 40)}\"` : src ? `src=\"${src.substring(0, 50)}\"` : \"first image\";\n results.push({\n ruleId: \"lazy-load-lcp\",\n ruleName: \"Lazy Load LCP\",\n message: `Above-the-fold image (${identifier}) has loading=\"lazy\" - this delays the Largest Contentful Paint`,\n severity: \"WARNING\",\n category: \"Performance\",\n tier: \"pro\",\n fix: 'Remove loading=\"lazy\" from above-the-fold images. Add fetchpriority=\"high\" to the LCP image instead.'\n });\n break;\n }\n if (!fetchpriority && !loading) {\n results.push({\n ruleId: \"lazy-load-lcp\",\n ruleName: \"Lazy Load LCP\",\n message: 'Consider adding fetchpriority=\"high\" to your hero/banner image to improve Largest Contentful Paint',\n severity: \"INFO\",\n category: \"Performance\",\n tier: \"pro\",\n fix: 'Add fetchpriority=\"high\" to the most important above-the-fold image to prioritize its loading.'\n });\n break;\n }\n }\n return results;\n }\n};\n\n// src/rules/https-links.ts\nvar httpsLinksRule = {\n meta: {\n id: \"https-links\",\n name: \"HTTPS Links\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n description: \"Checks that internal links use HTTPS instead of HTTP\"\n },\n run(context) {\n const { document, url } = context;\n const results = [];\n let hostname;\n try {\n hostname = new URL(url).hostname;\n } catch {\n return results;\n }\n const links = document.querySelectorAll('a[href^=\"http:\"]');\n let internalHttpLinks = 0;\n let externalHttpLinks = 0;\n links.forEach((link) => {\n const href = link.getAttribute(\"href\");\n if (!href) return;\n try {\n const linkHostname = new URL(href).hostname;\n if (linkHostname === hostname) {\n internalHttpLinks++;\n } else {\n externalHttpLinks++;\n }\n } catch {\n }\n });\n if (internalHttpLinks > 0) {\n results.push({\n ruleId: \"https-links\",\n ruleName: \"HTTPS Links\",\n message: `${internalHttpLinks} internal link(s) use HTTP instead of HTTPS`,\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Change all internal links from http:// to https:// to avoid redirect chains and mixed content warnings.\",\n data: { internalHttpLinks }\n });\n }\n if (externalHttpLinks > 0) {\n results.push({\n ruleId: \"https-links\",\n ruleName: \"HTTPS Links\",\n message: `${externalHttpLinks} external link(s) use HTTP - consider updating to HTTPS where available`,\n severity: \"INFO\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Update external links to use https:// where the destination supports it.\",\n data: { externalHttpLinks }\n });\n }\n return results;\n }\n};\n\n// src/rules/meta-refresh-redirect.ts\nvar metaRefreshRedirectRule = {\n meta: {\n id: \"meta-refresh-redirect\",\n name: \"Meta Refresh Redirect\",\n category: \"SEO\",\n tier: \"pro\",\n description: 'Checks for <meta http-equiv=\"refresh\"> redirects which are bad for SEO'\n },\n run(context) {\n const { document } = context;\n const results = [];\n const metaRefresh = document.querySelector(\n 'meta[http-equiv=\"refresh\"]'\n );\n if (!metaRefresh) return results;\n const content = metaRefresh.getAttribute(\"content\") || \"\";\n const hasUrl = content.toLowerCase().includes(\"url=\");\n const delay = Number.parseInt(content.split(\";\")[0] || \"\", 10);\n if (hasUrl) {\n results.push({\n ruleId: \"meta-refresh-redirect\",\n ruleName: \"Meta Refresh Redirect\",\n message: `Page uses a meta refresh redirect${!Number.isNaN(delay) ? ` (${delay}s delay)` : \"\"} - use server-side 301 redirects instead`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Replace <meta http-equiv=\"refresh\"> with a server-side 301 redirect. Meta refreshes are bad for SEO and user experience.',\n data: { content, delay: Number.isNaN(delay) ? void 0 : delay }\n });\n } else if (!Number.isNaN(delay) && delay > 0) {\n results.push({\n ruleId: \"meta-refresh-redirect\",\n ruleName: \"Meta Refresh Redirect\",\n message: `Page auto-refreshes every ${delay} seconds - this may cause usability issues`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Consider removing the auto-refresh meta tag unless it serves a clear user need.\",\n data: { content, delay }\n });\n }\n return results;\n }\n};\n\n// src/rules/nofollow-audit.ts\nvar nofollowAuditRule = {\n meta: {\n id: \"nofollow-audit\",\n name: \"Nofollow Audit\",\n category: \"SEO\",\n tier: \"pro\",\n description: 'Audits the use of rel=\"nofollow\" on internal vs. external links'\n },\n run(context) {\n const { document, url } = context;\n const results = [];\n let hostname;\n try {\n hostname = new URL(url).hostname;\n } catch {\n return results;\n }\n const nofollowLinks = document.querySelectorAll('a[rel~=\"nofollow\"]');\n let internalNofollow = 0;\n nofollowLinks.forEach((link) => {\n const href = link.getAttribute(\"href\");\n if (!href) return;\n try {\n const linkHostname = new URL(href, url).hostname;\n if (linkHostname === hostname) internalNofollow++;\n } catch {\n if (href.startsWith(\"/\") || href.startsWith(\".\")) {\n internalNofollow++;\n }\n }\n });\n if (internalNofollow > 0) {\n results.push({\n ruleId: \"nofollow-audit\",\n ruleName: \"Nofollow Audit\",\n message: `${internalNofollow} internal link(s) have rel=\"nofollow\" - this wastes PageRank and hurts internal linking`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: 'Remove rel=\"nofollow\" from internal links. Nofollow should only be used for external links you do not want to endorse (e.g., user-generated content, sponsored links).',\n data: { internalNofollow, totalNofollow: nofollowLinks.length }\n });\n }\n return results;\n }\n};\n\n// src/rules/cors-policy.ts\nvar corsPolicyRule = {\n meta: {\n id: \"cors-policy\",\n name: \"CORS Policy\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n description: \"Checks for overly permissive CORS configuration that could allow unauthorized cross-origin access\"\n },\n async run(url) {\n const results = [];\n const fakeOrigin = \"https://evil.example.com\";\n try {\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n \"User-Agent\": \"LintPage-Bot/1.0\",\n Origin: fakeOrigin\n },\n redirect: \"follow\"\n });\n const acao = response.headers.get(\"access-control-allow-origin\");\n const acac = response.headers.get(\"access-control-allow-credentials\");\n if (!acao) {\n return results;\n }\n if (acao === \"*\") {\n if (acac?.toLowerCase() === \"true\") {\n results.push({\n ruleId: \"cors-policy\",\n ruleName: \"CORS Policy\",\n message: \"CORS allows all origins with credentials enabled - this is a security vulnerability\",\n severity: \"CRITICAL\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: 'Set Access-Control-Allow-Origin to your specific trusted domains instead of \"*\". Wildcard with credentials is blocked by browsers but indicates a dangerous misconfiguration.'\n });\n } else {\n results.push({\n ruleId: \"cors-policy\",\n ruleName: \"CORS Policy\",\n message: \"CORS allows all origins (Access-Control-Allow-Origin: *) - restrict to trusted domains in production. Note: some hosting platforms (e.g. Vercel, Netlify, Cloudflare Pages) add this header by default, even if you haven't configured it.\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: 'If you set this header yourself, configure Access-Control-Allow-Origin to only allow requests from your trusted domains (e.g., \"https://myapp.com\") instead of using the wildcard \"*\". If your hosting platform adds it automatically, check their documentation for how to override or restrict CORS headers.'\n });\n }\n } else if (acao.toLowerCase() === fakeOrigin) {\n if (acac?.toLowerCase() === \"true\") {\n results.push({\n ruleId: \"cors-policy\",\n ruleName: \"CORS Policy\",\n message: \"CORS reflects any origin with credentials enabled - any website can make authenticated cross-origin requests and read responses. This is the most exploitable CORS misconfiguration.\",\n severity: \"CRITICAL\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"Configure your server to validate the Origin header against a strict allowlist of trusted domains. Never reflect arbitrary origins when credentials are enabled.\"\n });\n } else {\n results.push({\n ruleId: \"cors-policy\",\n ruleName: \"CORS Policy\",\n message: \"CORS reflects any origin back in Access-Control-Allow-Origin - this is equivalent to a wildcard and allows any site to make cross-origin requests. Note: this may be caused by your hosting platform or a reverse proxy, not your own configuration.\",\n severity: \"WARNING\",\n category: \"Pre-Launch\",\n tier: \"pro\",\n fix: \"If you set this header yourself, configure your server to validate the Origin header against an allowlist of trusted domains instead of reflecting it back. If your hosting platform adds it automatically, check their documentation for how to override or restrict CORS headers.\"\n });\n }\n }\n } catch {\n }\n return results;\n }\n};\n\n// src/rules/broken-internal-links.ts\nvar MAX_LINKS_TO_CHECK = 50;\nvar REQUEST_TIMEOUT_MS = 1e4;\nvar brokenInternalLinksRule = {\n meta: {\n id: \"broken-internal-links\",\n name: \"Broken Internal Links\",\n category: \"SEO\",\n tier: \"pro\",\n description: \"Checks that internal links on the page resolve successfully (no 404s or server errors)\"\n },\n async run(context) {\n const { document, url } = context;\n const results = [];\n let baseUrl;\n try {\n baseUrl = new URL(url);\n } catch {\n return results;\n }\n const seen = /* @__PURE__ */ new Set();\n const internalLinks = [];\n const anchors = document.querySelectorAll(\"a[href]\");\n for (const anchor of anchors) {\n const href = anchor.getAttribute(\"href\");\n if (!href) continue;\n if (href.startsWith(\"#\") || href.startsWith(\"mailto:\") || href.startsWith(\"tel:\") || href.startsWith(\"javascript:\") || href.startsWith(\"data:\")) {\n continue;\n }\n let resolved;\n try {\n resolved = new URL(href, url);\n } catch {\n continue;\n }\n if (resolved.hostname !== baseUrl.hostname) continue;\n resolved.hash = \"\";\n const normalized = resolved.toString();\n if (seen.has(normalized)) continue;\n seen.add(normalized);\n const currentNormalized = new URL(url);\n currentNormalized.hash = \"\";\n if (normalized === currentNormalized.toString()) continue;\n internalLinks.push(normalized);\n }\n if (internalLinks.length === 0) return results;\n const linksToCheck = internalLinks.slice(0, MAX_LINKS_TO_CHECK);\n const brokenLinks = [];\n const errorLinks = [];\n const checkLink = async (linkUrl) => {\n try {\n const res = await fetch(linkUrl, {\n method: \"HEAD\",\n headers: { \"User-Agent\": \"LintPage-Bot/1.0\" },\n redirect: \"follow\",\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)\n });\n if (res.status === 405) {\n const getRes = await fetch(linkUrl, {\n method: \"GET\",\n headers: { \"User-Agent\": \"LintPage-Bot/1.0\" },\n redirect: \"follow\",\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)\n });\n if (getRes.status >= 400) {\n brokenLinks.push({ url: linkUrl, status: getRes.status });\n }\n return;\n }\n if (res.status >= 400) {\n brokenLinks.push({ url: linkUrl, status: res.status });\n }\n } catch {\n errorLinks.push(linkUrl);\n }\n };\n const BATCH_SIZE = 10;\n for (let i = 0; i < linksToCheck.length; i += BATCH_SIZE) {\n const batch = linksToCheck.slice(i, i + BATCH_SIZE);\n await Promise.all(batch.map(checkLink));\n }\n if (brokenLinks.length > 0) {\n const notFound = brokenLinks.filter((l) => l.status === 404);\n const serverErrors = brokenLinks.filter((l) => l.status >= 500);\n const other = brokenLinks.filter(\n (l) => l.status !== 404 && l.status < 500\n );\n if (notFound.length > 0) {\n results.push({\n ruleId: \"broken-internal-links\",\n ruleName: \"Broken Internal Links\",\n message: `${notFound.length} internal link(s) return 404 Not Found: ${notFound.map((l) => l.url).join(\", \")}`,\n severity: \"CRITICAL\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Remove or update the broken links to point to valid pages. Broken internal links hurt SEO and user experience.\",\n data: { notFoundLinks: notFound }\n });\n }\n if (serverErrors.length > 0) {\n results.push({\n ruleId: \"broken-internal-links\",\n ruleName: \"Broken Internal Links\",\n message: `${serverErrors.length} internal link(s) return server errors: ${serverErrors.map((l) => `${l.url} (${l.status})`).join(\", \")}`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Investigate server errors on the linked pages. These may indicate temporary issues or misconfigured routes.\",\n data: { serverErrorLinks: serverErrors }\n });\n }\n if (other.length > 0) {\n results.push({\n ruleId: \"broken-internal-links\",\n ruleName: \"Broken Internal Links\",\n message: `${other.length} internal link(s) return client errors: ${other.map((l) => `${l.url} (${l.status})`).join(\", \")}`,\n severity: \"WARNING\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"Check the linked pages for access issues (e.g., 401/403 may indicate authentication or permission problems).\",\n data: { clientErrorLinks: other }\n });\n }\n }\n if (errorLinks.length > 0) {\n results.push({\n ruleId: \"broken-internal-links\",\n ruleName: \"Broken Internal Links\",\n message: `${errorLinks.length} internal link(s) could not be reached: ${errorLinks.join(\", \")}`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n fix: \"These links timed out or had network errors during the check. Verify they are accessible.\",\n data: { unreachableLinks: errorLinks }\n });\n }\n if (internalLinks.length > MAX_LINKS_TO_CHECK) {\n results.push({\n ruleId: \"broken-internal-links\",\n ruleName: \"Broken Internal Links\",\n message: `Only checked ${MAX_LINKS_TO_CHECK} of ${internalLinks.length} internal links. Consider reducing the number of links on this page.`,\n severity: \"INFO\",\n category: \"SEO\",\n tier: \"pro\",\n data: {\n totalLinks: internalLinks.length,\n checkedLinks: MAX_LINKS_TO_CHECK\n }\n });\n }\n return results;\n }\n};\n\n// src/rules/index.ts\nvar proRules = [\n // Ported — Pre-Launch\n sslRule,\n trackingRule,\n xRobotsTagRule,\n // Ported — Content / SEO\n thinContentRule,\n duplicateMetaRule,\n structuredDataRule,\n charsetRule,\n // Ported — Accessibility\n imageAltTextRule,\n accessibilityRule,\n semanticStructureRule,\n // Ported — Performance\n performanceRule,\n imageDimensionsRule,\n // Ported — Security\n mixedContentRule,\n securityHeadersRule,\n // New — Social\n ogImageSizeRule,\n ogImageTypeRule,\n twitterImageRule,\n socialPreviewRenderRule,\n // New — Content\n titleKeywordStuffingRule,\n contentToHtmlRatioRule,\n titleUniquenessRule,\n descriptionUniquenessRule,\n // New — Technical\n structuredDataValidateRule,\n hreflangRule,\n canonicalSelfReferencingRule,\n // New — Performance\n metaRenderBlockingRule,\n lazyLoadLcpRule,\n // New — Security / SEO\n httpsLinksRule,\n metaRefreshRedirectRule,\n nofollowAuditRule\n];\nvar proAsyncRules = [\n brokenInternalLinksRule\n];\nvar proStandaloneRules = [\n robotsTxtCheckRule,\n sitemapPresenceRule,\n ttfbRule,\n corsPolicyRule\n];\n\n// src/license.ts\nimport * as jose from \"jose\";\nvar PUBLIC_KEY_JWK = {\n kty: \"OKP\",\n crv: \"Ed25519\",\n x: \"Q628CrspKqI_ig04oril9DaBhFaCJ2fJtoeFJhzrWek\"\n};\nvar cachedPublicKey = null;\nasync function getPublicKey() {\n if (!cachedPublicKey) {\n cachedPublicKey = await jose.importJWK(PUBLIC_KEY_JWK, \"EdDSA\");\n }\n return cachedPublicKey;\n}\nasync function validateLicense(token) {\n try {\n const publicKey = await getPublicKey();\n const { payload } = await jose.jwtVerify(token, publicKey, {\n algorithms: [\"EdDSA\"],\n issuer: \"lintpage\",\n audience: \"lintpage-pro\"\n });\n const licensePayload = {\n sub: payload.sub,\n plan: payload.plan,\n iat: payload.iat,\n exp: payload.exp\n };\n return { valid: true, payload: licensePayload };\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Invalid license key\";\n return { valid: false, error: message };\n }\n}\nasync function isLicenseValid(token) {\n const result = await validateLicense(token);\n return result.valid;\n}\n\n// src/index.ts\nvar proPlugin = {\n name: \"@lintpage/pro\",\n rules: proRules,\n asyncRules: proAsyncRules,\n standaloneRules: proStandaloneRules\n};\nfunction loadProPlugin() {\n return proPlugin;\n}\nexport {\n accessibilityRule,\n brokenInternalLinksRule,\n canonicalSelfReferencingRule,\n charsetRule,\n contentToHtmlRatioRule,\n corsPolicyRule,\n descriptionUniquenessRule,\n duplicateMetaRule,\n hreflangRule,\n httpsLinksRule,\n imageAltTextRule,\n imageDimensionsRule,\n isLicenseValid,\n lazyLoadLcpRule,\n loadProPlugin,\n metaRefreshRedirectRule,\n metaRenderBlockingRule,\n mixedContentRule,\n nofollowAuditRule,\n ogImageSizeRule,\n ogImageTypeRule,\n performanceRule,\n proAsyncRules,\n proPlugin,\n proRules,\n proStandaloneRules,\n robotsTxtCheckRule,\n securityHeadersRule,\n semanticStructureRule,\n sitemapPresenceRule,\n socialPreviewRenderRule,\n sslRule,\n structuredDataRule,\n structuredDataValidateRule,\n thinContentRule,\n titleKeywordStuffingRule,\n titleUniquenessRule,\n trackingRule,\n ttfbRule,\n twitterImageRule,\n validateLicense,\n xRobotsTagRule\n};\n//# sourceMappingURL=index.mjs.map","import cac from 'cac';\nimport chalk from 'chalk';\nimport {\n auditPage,\n loadConfig,\n createDefaultConfig,\n} from '@lintpage/core';\nimport { loadProPlugin } from '@lintpage/pro';\nimport { format, type Format } from './formatter';\nimport { writeFileSync, readFileSync, existsSync } from 'fs';\nimport { join } from 'path';\n\nconst cli = cac('lintpage');\n\n// Exit codes\nconst EXIT_PASS = 0;\nconst EXIT_FAIL = 1;\nconst EXIT_ERROR = 2;\n\ncli\n .command('<url>', 'Run an audit on a URL')\n .option('--format <format>', 'Output format: text, json, github', {\n default: 'text',\n })\n .option('--config <path>', 'Path to config file')\n .option('--fail-on-warning', 'Exit 1 on warnings (not just criticals)')\n .option('--quiet', 'Minimal output (counts only)')\n .action(async (url: string, options: Record<string, unknown>) => {\n const fmt = (options.format as Format) || 'text';\n const configPath = options.config as string | undefined;\n const failOnWarning = Boolean(options.failOnWarning);\n const quiet = Boolean(options.quiet);\n\n try {\n // Normalize URL\n let targetUrl = url;\n if (!targetUrl.startsWith('http://') && !targetUrl.startsWith('https://')) {\n targetUrl = `https://${targetUrl}`;\n }\n\n // Load config\n const config = loadConfig(configPath) ?? undefined;\n\n // Run audit\n if (!quiet && fmt === 'text') {\n console.log(chalk.dim(`Auditing ${targetUrl}...`));\n }\n\n const result = await auditPage(targetUrl, { plugins: [loadProPlugin()], config });\n\n // Output\n console.log(format(result, fmt, quiet));\n\n // Exit code\n const hasCritical = result.results.some(\n (r) => r.severity === 'CRITICAL'\n );\n const hasWarning = result.results.some(\n (r) => r.severity === 'WARNING'\n );\n\n if (hasCritical) {\n process.exit(EXIT_FAIL);\n }\n if (failOnWarning && hasWarning) {\n process.exit(EXIT_FAIL);\n }\n process.exit(EXIT_PASS);\n } catch (err) {\n if (fmt === 'json') {\n console.error(\n JSON.stringify({\n error: err instanceof Error ? err.message : String(err),\n })\n );\n } else {\n console.error(\n chalk.red(\n `Error: ${err instanceof Error ? err.message : String(err)}`\n )\n );\n }\n process.exit(EXIT_ERROR);\n }\n });\n\ncli\n .command('init', 'Generate a .lintpagerc.json config file')\n .action(() => {\n const configPath = join(process.cwd(), '.lintpagerc.json');\n if (existsSync(configPath)) {\n console.log(chalk.yellow('.lintpagerc.json already exists'));\n process.exit(EXIT_PASS);\n }\n const config = createDefaultConfig();\n writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n');\n console.log(chalk.green('Created .lintpagerc.json'));\n process.exit(EXIT_PASS);\n });\n\ncli.help();\n\n// Read version dynamically from package.json\nconst pkgPath = join(__dirname, '..', 'package.json');\nconst pkgJson = existsSync(pkgPath)\n ? JSON.parse(readFileSync(pkgPath, 'utf-8'))\n : { version: '0.0.0' };\ncli.version(pkgJson.version);\n\ntry {\n cli.parse();\n} catch (err) {\n if (err instanceof Error && err.message) {\n // Extract clean message from CACError (e.g. \"option `--pro <key>` value is missing\")\n console.error(chalk.red(`Error: ${err.message}`));\n console.error(chalk.dim('Run \"lintpage --help\" for usage information.'));\n } else {\n console.error(chalk.red(`Error: ${String(err)}`));\n }\n process.exit(EXIT_ERROR);\n}\n"],"mappings":"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"}