@power-seo/content-analysis 1.0.11 → 1.0.15
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/README.md +11 -13
- package/dist/index.cjs +10062 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +267 -3
- package/dist/index.d.ts +267 -3
- package/dist/index.js +9977 -30
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +9892 -29
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +9892 -29
- package/dist/react.js.map +1 -1
- package/dist/types-bMzFlDeW.d.cts +9 -0
- package/dist/types-bMzFlDeW.d.ts +9 -0
- package/package.json +9 -3
- package/dist/types-BGadIBx8.d.cts +0 -9
- package/dist/types-BGadIBx8.d.ts +0 -9
package/dist/react.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react.ts","../src/checks/title.ts","../src/checks/meta-description.ts","../src/checks/keyphrase-usage.ts","../src/checks/headings.ts","../src/checks/word-count.ts","../src/checks/images.ts","../src/checks/links.ts","../src/analyzer.ts"],"sourcesContent":["// @power-seo/content-analysis — React Components\n// ----------------------------------------------------------------------------\n\nimport { createElement, useMemo } from 'react';\nimport type { ReactNode } from 'react';\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport type { AnalysisConfig } from './types.js';\nimport { analyzeContent } from './analyzer.js';\n\n// --- ScorePanel ---\n\nexport interface ScorePanelProps {\n score: number;\n maxScore: number;\n}\n\nfunction getScoreColor(percentage: number): string {\n if (percentage >= 70) return '#1e8e3e';\n if (percentage >= 40) return '#f29900';\n return '#d93025';\n}\n\nfunction getScoreLabel(percentage: number): string {\n if (percentage >= 70) return 'Good';\n if (percentage >= 40) return 'OK';\n return 'Needs improvement';\n}\n\n/**\n * Displays an overall SEO score as a colored bar with label.\n */\nexport function ScorePanel({ score, maxScore }: ScorePanelProps) {\n const percentage = maxScore > 0 ? Math.round((score / maxScore) * 100) : 0;\n const color = getScoreColor(percentage);\n const label = getScoreLabel(percentage);\n\n return createElement(\n 'div',\n {\n style: {\n fontFamily: 'system-ui, -apple-system, sans-serif',\n padding: '16px',\n borderRadius: '8px',\n border: '1px solid #e0e0e0',\n backgroundColor: '#fff',\n },\n },\n createElement(\n 'div',\n {\n style: {\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n marginBottom: '8px',\n },\n },\n createElement(\n 'span',\n { style: { fontWeight: 600, fontSize: '14px', color: '#333' } },\n 'SEO Score',\n ),\n createElement(\n 'span',\n { style: { fontWeight: 700, fontSize: '18px', color } },\n `${percentage}%`,\n ),\n ),\n createElement(\n 'div',\n {\n style: {\n width: '100%',\n height: '8px',\n backgroundColor: '#e8e8e8',\n borderRadius: '4px',\n overflow: 'hidden',\n },\n },\n createElement('div', {\n style: {\n width: `${percentage}%`,\n height: '100%',\n backgroundColor: color,\n borderRadius: '4px',\n transition: 'width 0.3s ease',\n },\n }),\n ),\n createElement(\n 'div',\n { style: { marginTop: '4px', fontSize: '12px', color: '#666' } },\n `${label} — ${score}/${maxScore} points`,\n ),\n );\n}\n\n// --- CheckList ---\n\nexport interface CheckListProps {\n results: AnalysisResult[];\n}\n\nconst STATUS_ICONS: Record<string, string> = {\n good: '\\u2705',\n ok: '\\u26a0\\ufe0f',\n poor: '\\u274c',\n};\n\nconst STATUS_COLORS: Record<string, string> = {\n good: '#1e8e3e',\n ok: '#f29900',\n poor: '#d93025',\n};\n\n/**\n * Renders analysis results as a list with status icons.\n */\nexport function CheckList({ results }: CheckListProps) {\n return createElement(\n 'ul',\n {\n style: {\n listStyle: 'none',\n padding: 0,\n margin: 0,\n fontFamily: 'system-ui, -apple-system, sans-serif',\n },\n },\n ...results.map((result) =>\n createElement(\n 'li',\n {\n key: result.id,\n style: {\n padding: '10px 12px',\n borderBottom: '1px solid #f0f0f0',\n display: 'flex',\n gap: '10px',\n alignItems: 'flex-start',\n },\n },\n createElement(\n 'span',\n { style: { flexShrink: 0, fontSize: '14px' } },\n STATUS_ICONS[result.status] ?? '',\n ),\n createElement(\n 'div',\n { style: { flex: 1 } },\n createElement(\n 'div',\n {\n style: {\n fontWeight: 600,\n fontSize: '13px',\n color: STATUS_COLORS[result.status] ?? '#333',\n },\n },\n result.title,\n ),\n createElement(\n 'div',\n { style: { fontSize: '12px', color: '#555', marginTop: '2px' } },\n result.description,\n ),\n ),\n ),\n ),\n );\n}\n\n// --- ContentAnalyzer ---\n\nexport interface ContentAnalyzerProps {\n input: ContentAnalysisInput;\n config?: AnalysisConfig;\n children?: ReactNode;\n}\n\n/**\n * All-in-one component that runs analysis and renders score + check list.\n */\nexport function ContentAnalyzer({ input, config, children }: ContentAnalyzerProps) {\n const output = useMemo(() => analyzeContent(input, config), [input, config]);\n\n return createElement(\n 'div',\n {\n style: {\n fontFamily: 'system-ui, -apple-system, sans-serif',\n },\n },\n createElement(ScorePanel, { score: output.score, maxScore: output.maxScore }),\n createElement('div', { style: { height: '12px' } }),\n createElement(CheckList, { results: output.results }),\n children ?? null,\n );\n}\n","// @power-seo/content-analysis — Title Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { validateTitle } from '@power-seo/core';\n\nexport function checkTitle(input: ContentAnalysisInput): AnalysisResult[] {\n const results: AnalysisResult[] = [];\n const { title, focusKeyphrase } = input;\n\n // --- Presence & validity check ---\n if (!title || title.trim().length === 0) {\n results.push({\n id: 'title-presence',\n title: 'SEO title',\n description: 'No title has been set. Add a title to improve search visibility.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n });\n return results;\n }\n\n const validation = validateTitle(title);\n\n if (!validation.valid) {\n results.push({\n id: 'title-presence',\n title: 'SEO title',\n description: validation.message,\n status: 'ok',\n score: 3,\n maxScore: 5,\n });\n } else if (validation.severity === 'warning') {\n results.push({\n id: 'title-presence',\n title: 'SEO title',\n description: validation.message,\n status: 'ok',\n score: 3,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'title-presence',\n title: 'SEO title',\n description: validation.message,\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n }\n\n // --- Keyphrase in title check ---\n if (focusKeyphrase && focusKeyphrase.trim().length > 0) {\n const kp = focusKeyphrase.toLowerCase().trim();\n const titleLower = title.toLowerCase();\n\n if (titleLower.includes(kp)) {\n results.push({\n id: 'title-keyphrase',\n title: 'Keyphrase in title',\n description: 'The focus keyphrase appears in the SEO title. Good job!',\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'title-keyphrase',\n title: 'Keyphrase in title',\n description:\n 'The focus keyphrase does not appear in the SEO title. Add it to improve relevance.',\n status: 'ok',\n score: 2,\n maxScore: 5,\n });\n }\n }\n\n return results;\n}\n","// @power-seo/content-analysis — Meta Description Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { validateMetaDescription } from '@power-seo/core';\n\nexport function checkMetaDescription(input: ContentAnalysisInput): AnalysisResult[] {\n const results: AnalysisResult[] = [];\n const { metaDescription, focusKeyphrase } = input;\n\n // --- Presence & validity check ---\n if (!metaDescription || metaDescription.trim().length === 0) {\n results.push({\n id: 'meta-description-presence',\n title: 'Meta description',\n description:\n 'No meta description has been set. Add one to control how your page appears in search results.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n });\n return results;\n }\n\n const validation = validateMetaDescription(metaDescription);\n\n if (!validation.valid) {\n results.push({\n id: 'meta-description-presence',\n title: 'Meta description',\n description: validation.message,\n status: 'ok',\n score: 3,\n maxScore: 5,\n });\n } else if (validation.severity === 'warning') {\n results.push({\n id: 'meta-description-presence',\n title: 'Meta description',\n description: validation.message,\n status: 'ok',\n score: 3,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'meta-description-presence',\n title: 'Meta description',\n description: validation.message,\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n }\n\n // --- Keyphrase in meta description check ---\n if (focusKeyphrase && focusKeyphrase.trim().length > 0) {\n const kp = focusKeyphrase.toLowerCase().trim();\n const descLower = metaDescription.toLowerCase();\n\n if (descLower.includes(kp)) {\n results.push({\n id: 'meta-description-keyphrase',\n title: 'Keyphrase in meta description',\n description: 'The focus keyphrase appears in the meta description. Well done!',\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'meta-description-keyphrase',\n title: 'Keyphrase in meta description',\n description:\n 'The focus keyphrase does not appear in the meta description. Add it to improve click-through rate.',\n status: 'ok',\n score: 2,\n maxScore: 5,\n });\n }\n }\n\n return results;\n}\n","// @power-seo/content-analysis — Keyphrase Usage Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport {\n analyzeKeyphraseOccurrences,\n calculateKeywordDensity,\n KEYWORD_DENSITY,\n} from '@power-seo/core';\n\nexport function checkKeyphraseUsage(input: ContentAnalysisInput): AnalysisResult[] {\n const results: AnalysisResult[] = [];\n const { focusKeyphrase, title, metaDescription, content, slug, images } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n results.push({\n id: 'keyphrase-density',\n title: 'Keyphrase density',\n description: 'No focus keyphrase set. Set one to get keyphrase analysis.',\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n return results;\n }\n\n const occurrences = analyzeKeyphraseOccurrences({\n keyphrase: focusKeyphrase,\n title,\n metaDescription,\n content,\n slug,\n images,\n });\n\n const densityResult = calculateKeywordDensity(focusKeyphrase, content);\n\n // --- Density check ---\n if (densityResult.density < KEYWORD_DENSITY.MIN) {\n results.push({\n id: 'keyphrase-density',\n title: 'Keyphrase density',\n description: `Keyphrase density is ${densityResult.density}%, which is below the recommended minimum of ${KEYWORD_DENSITY.MIN}%. Use the keyphrase more often.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n });\n } else if (densityResult.density > KEYWORD_DENSITY.MAX) {\n results.push({\n id: 'keyphrase-density',\n title: 'Keyphrase density',\n description: `Keyphrase density is ${densityResult.density}%, which exceeds the recommended maximum of ${KEYWORD_DENSITY.MAX}%. Reduce usage to avoid keyword stuffing.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n });\n } else if (\n densityResult.density >= KEYWORD_DENSITY.MIN &&\n densityResult.density <= KEYWORD_DENSITY.MAX\n ) {\n const isOptimal = Math.abs(densityResult.density - KEYWORD_DENSITY.OPTIMAL) < 0.5;\n results.push({\n id: 'keyphrase-density',\n title: 'Keyphrase density',\n description: `Keyphrase density is ${densityResult.density}%.${isOptimal ? ' Great — this is close to the optimal density.' : ' This is within the recommended range.'}`,\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n }\n\n // --- Distribution check ---\n const distributionPoints: string[] = [];\n if (!occurrences.inFirstParagraph) distributionPoints.push('introduction');\n if (!occurrences.inH1 && occurrences.inHeadings === 0) distributionPoints.push('headings');\n if (!occurrences.inSlug) distributionPoints.push('slug');\n if (occurrences.inAltText === 0 && images && images.length > 0)\n distributionPoints.push('image alt text');\n\n if (distributionPoints.length === 0) {\n results.push({\n id: 'keyphrase-distribution',\n title: 'Keyphrase distribution',\n description:\n 'The focus keyphrase is well-distributed across the introduction, headings, slug, and image alt text.',\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n } else if (distributionPoints.length <= 2) {\n results.push({\n id: 'keyphrase-distribution',\n title: 'Keyphrase distribution',\n description: `Consider adding the keyphrase to: ${distributionPoints.join(', ')}.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'keyphrase-distribution',\n title: 'Keyphrase distribution',\n description: `The keyphrase is missing from: ${distributionPoints.join(', ')}. Distribute it more broadly.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n });\n }\n\n return results;\n}\n","// @power-seo/content-analysis — Headings Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml } from '@power-seo/core';\n\ninterface HeadingInfo {\n level: number;\n text: string;\n}\n\n/**\n * Parse all headings (h1-h6) from HTML using plain string search.\n * Avoids regex ReDoS on crafted inputs with many repeated heading-like tags.\n */\nfunction parseHeadings(html: string): HeadingInfo[] {\n const headings: HeadingInfo[] = [];\n const lc = html.toLowerCase();\n let pos = 0;\n\n while (pos < lc.length) {\n // Find the next heading tag of any level\n let earliest = -1;\n let earliestLevel = 0;\n for (let level = 1; level <= 6; level++) {\n const idx = lc.indexOf(`<h${level}`, pos);\n if (idx !== -1 && (earliest === -1 || idx < earliest)) {\n earliest = idx;\n earliestLevel = level;\n }\n }\n if (earliest === -1) break;\n\n const contentStart = lc.indexOf('>', earliest);\n if (contentStart === -1) break;\n\n const closeTag = `</h${earliestLevel}>`;\n const closeIdx = lc.indexOf(closeTag, contentStart + 1);\n if (closeIdx === -1) {\n pos = contentStart + 1;\n continue;\n }\n\n headings.push({\n level: earliestLevel,\n text: stripHtml(html.slice(contentStart + 1, closeIdx)),\n });\n pos = closeIdx + closeTag.length;\n }\n\n return headings;\n}\n\nexport function checkHeadings(input: ContentAnalysisInput): AnalysisResult[] {\n const results: AnalysisResult[] = [];\n const { content, focusKeyphrase } = input;\n const headings = parseHeadings(content);\n\n // --- H1 & structure check ---\n const h1s = headings.filter((h) => h.level === 1);\n\n if (h1s.length === 0) {\n results.push({\n id: 'heading-structure',\n title: 'Heading structure',\n description: 'No H1 heading found. Add exactly one H1 as the main heading of your page.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n });\n } else if (h1s.length > 1) {\n results.push({\n id: 'heading-structure',\n title: 'Heading structure',\n description: `Found ${h1s.length} H1 headings. Use exactly one H1 per page for proper SEO.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n });\n } else {\n // Check heading hierarchy\n let hasSkippedLevel = false;\n for (let i = 1; i < headings.length; i++) {\n const prev = headings[i - 1]!;\n const curr = headings[i]!;\n if (curr.level > prev.level + 1) {\n hasSkippedLevel = true;\n break;\n }\n }\n\n if (hasSkippedLevel) {\n results.push({\n id: 'heading-structure',\n title: 'Heading structure',\n description:\n 'The heading hierarchy skips levels (e.g., H2 to H4). Use sequential heading levels for better accessibility and SEO.',\n status: 'ok',\n score: 3,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'heading-structure',\n title: 'Heading structure',\n description: 'The heading structure looks good with a single H1 and proper hierarchy.',\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n }\n }\n\n // --- Keyphrase in headings check ---\n if (focusKeyphrase && focusKeyphrase.trim().length > 0) {\n const kp = focusKeyphrase.toLowerCase().trim();\n const subheadings = headings.filter((h) => h.level >= 2);\n const hasKeyphraseInSubheading = subheadings.some((h) => h.text.toLowerCase().includes(kp));\n\n if (subheadings.length === 0) {\n results.push({\n id: 'heading-keyphrase',\n title: 'Keyphrase in subheadings',\n description:\n 'No subheadings (H2-H6) found. Add subheadings to structure your content and include the focus keyphrase.',\n status: 'ok',\n score: 2,\n maxScore: 5,\n });\n } else if (hasKeyphraseInSubheading) {\n results.push({\n id: 'heading-keyphrase',\n title: 'Keyphrase in subheadings',\n description: 'The focus keyphrase appears in at least one subheading. Nice!',\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'heading-keyphrase',\n title: 'Keyphrase in subheadings',\n description:\n 'The focus keyphrase does not appear in any subheading. Consider adding it to an H2 or H3.',\n status: 'ok',\n score: 2,\n maxScore: 5,\n });\n }\n }\n\n return results;\n}\n","// @power-seo/content-analysis — Word Count Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { getWords, MIN_WORD_COUNT, RECOMMENDED_WORD_COUNT } from '@power-seo/core';\n\nexport function checkWordCount(input: ContentAnalysisInput): AnalysisResult {\n const words = getWords(input.content);\n const count = words.length;\n\n if (count < MIN_WORD_COUNT) {\n return {\n id: 'word-count',\n title: 'Word count',\n description: `The content is ${count} words, which is below the recommended minimum of ${MIN_WORD_COUNT}. Add more content to improve SEO.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n }\n\n if (count < RECOMMENDED_WORD_COUNT) {\n return {\n id: 'word-count',\n title: 'Word count',\n description: `The content is ${count} words. Consider expanding to at least ${RECOMMENDED_WORD_COUNT} words for more comprehensive coverage.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'word-count',\n title: 'Word count',\n description: `The content is ${count} words. Good — this provides enough depth for search engines.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Images Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\nexport function checkImages(input: ContentAnalysisInput): AnalysisResult[] {\n const results: AnalysisResult[] = [];\n const { images, focusKeyphrase } = input;\n\n if (!images || images.length === 0) {\n results.push({\n id: 'image-alt',\n title: 'Image alt attributes',\n description: 'No images found. Consider adding images to make your content more engaging.',\n status: 'ok',\n score: 3,\n maxScore: 5,\n });\n return results;\n }\n\n // --- Alt text check ---\n const missingAlt = images.filter((img) => !img.alt || img.alt.trim().length === 0);\n\n if (missingAlt.length === 0) {\n results.push({\n id: 'image-alt',\n title: 'Image alt attributes',\n description: 'All images have alt text. Great for accessibility and SEO!',\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n } else if (missingAlt.length === images.length) {\n results.push({\n id: 'image-alt',\n title: 'Image alt attributes',\n description:\n 'None of the images have alt text. Add descriptive alt attributes for accessibility and SEO.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'image-alt',\n title: 'Image alt attributes',\n description: `${missingAlt.length} of ${images.length} images are missing alt text. Add alt attributes to all images.`,\n status: 'ok',\n score: 2,\n maxScore: 5,\n });\n }\n\n // --- Keyphrase in alt text check ---\n if (focusKeyphrase && focusKeyphrase.trim().length > 0) {\n const kp = focusKeyphrase.toLowerCase().trim();\n const hasKeyphraseInAlt = images.some((img) => img.alt && img.alt.toLowerCase().includes(kp));\n\n if (hasKeyphraseInAlt) {\n results.push({\n id: 'image-keyphrase',\n title: 'Keyphrase in image alt',\n description: 'The focus keyphrase appears in at least one image alt attribute.',\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'image-keyphrase',\n title: 'Keyphrase in image alt',\n description:\n 'The focus keyphrase does not appear in any image alt attribute. Add it to at least one image.',\n status: 'ok',\n score: 2,\n maxScore: 5,\n });\n }\n }\n\n return results;\n}\n","// @power-seo/content-analysis — Links Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\nexport function checkLinks(input: ContentAnalysisInput): AnalysisResult[] {\n const results: AnalysisResult[] = [];\n const { internalLinks, externalLinks } = input;\n\n const hasInternal = internalLinks && internalLinks.length > 0;\n const hasExternal = externalLinks && externalLinks.length > 0;\n\n if (!hasInternal) {\n results.push({\n id: 'internal-links',\n title: 'Internal links',\n description:\n 'No internal links found. Add links to other pages on your site to improve crawlability and distribute link equity.',\n status: 'ok',\n score: 2,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'internal-links',\n title: 'Internal links',\n description: `Found ${internalLinks!.length} internal link${internalLinks!.length === 1 ? '' : 's'}. Good for site structure and SEO.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n }\n\n if (!hasExternal) {\n results.push({\n id: 'external-links',\n title: 'External links',\n description:\n 'No external links found. Consider adding outbound links to authoritative sources to strengthen your content.',\n status: 'ok',\n score: 2,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'external-links',\n title: 'External links',\n description: `Found ${externalLinks!.length} external link${externalLinks!.length === 1 ? '' : 's'}. Linking to quality sources adds credibility.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n }\n\n return results;\n}\n","// @power-seo/content-analysis — Content Analyzer Orchestrator\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, ContentAnalysisOutput, AnalysisResult } from '@power-seo/core';\nimport type { AnalysisConfig, CheckId } from './types.js';\nimport { checkTitle } from './checks/title.js';\nimport { checkMetaDescription } from './checks/meta-description.js';\nimport { checkKeyphraseUsage } from './checks/keyphrase-usage.js';\nimport { checkHeadings } from './checks/headings.js';\nimport { checkWordCount } from './checks/word-count.js';\nimport { checkImages } from './checks/images.js';\nimport { checkLinks } from './checks/links.js';\n\n/**\n * Run all SEO content analysis checks and return aggregated results.\n *\n * @example\n * ```ts\n * const output = analyzeContent({\n * title: 'My Blog Post',\n * metaDescription: 'A description of my blog post about SEO.',\n * content: '<h1>My Blog Post</h1><p>Content goes here...</p>',\n * focusKeyphrase: 'blog post',\n * });\n * console.log(output.score, output.maxScore, output.recommendations);\n * ```\n */\nexport function analyzeContent(\n input: ContentAnalysisInput,\n config?: AnalysisConfig,\n): ContentAnalysisOutput {\n const disabled = new Set<CheckId>(config?.disabledChecks ?? []);\n\n const allResults: AnalysisResult[] = [];\n\n // Run each check group and collect results\n const titleResults = checkTitle(input);\n const metaResults = checkMetaDescription(input);\n const keyphraseResults = checkKeyphraseUsage(input);\n const headingResults = checkHeadings(input);\n const wordCountResult = checkWordCount(input);\n const imageResults = checkImages(input);\n const linkResults = checkLinks(input);\n\n // Flatten all results\n const candidateResults = [\n ...titleResults,\n ...metaResults,\n ...keyphraseResults,\n ...headingResults,\n wordCountResult,\n ...imageResults,\n ...linkResults,\n ];\n\n // Filter out disabled checks\n for (const result of candidateResults) {\n if (!disabled.has(result.id as CheckId)) {\n allResults.push(result);\n }\n }\n\n // Sum scores\n const score = allResults.reduce((sum, r) => sum + r.score, 0);\n const maxScore = allResults.reduce((sum, r) => sum + r.maxScore, 0);\n\n // Generate recommendations from poor/ok results\n const recommendations = allResults\n .filter((r) => r.status === 'poor' || r.status === 'ok')\n .map((r) => r.description);\n\n return {\n score,\n maxScore,\n results: allResults,\n recommendations,\n };\n}\n"],"mappings":"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","names":["import_core","import_core","import_core","import_core"]}
|
|
1
|
+
{"version":3,"sources":["../src/react.ts","../src/checks/title.ts","../src/checks/meta-description.ts","../src/checks/keyphrase-usage.ts","../src/checks/headings.ts","../src/checks/word-count.ts","../src/checks/images.ts","../src/checks/links.ts","../src/checks/paragraph-length.ts","../src/checks/sentence-length.ts","../src/checks/subheading-distribution.ts","../src/checks/transition-words.ts","../src/checks/canonical-url.ts","../src/checks/keyphrase-introduction.ts","../src/checks/keyphrase-slug.ts","../src/checks/keyphrase-length.ts","../src/checks/title-readability.ts","../src/checks/keyphrase-title-position.ts","../src/checks/url-length.ts","../src/checks/text-presence.ts","../src/checks/media-count.ts","../src/checks/table-of-contents.ts","../src/checks/nofollow-links.ts","../src/checks/secondary-keyphrases.ts","../src/checks/eeat-experience-depth.ts","../src/checks/eeat-original-research.ts","../src/checks/eeat-specificity-depth.ts","../src/checks/eeat-multimedia-evidence.ts","../src/checks/eeat-case-study-patterns.ts","../src/checks/eeat-author-schema.ts","../src/checks/eeat-topical-authority.ts","../src/checks/eeat-technical-vocabulary.ts","../src/checks/eeat-expert-hedging.ts","../src/checks/eeat-methodology-transparency.ts","../src/checks/eeat-author-social.ts","../src/checks/eeat-organization.ts","../src/checks/eeat-published-works.ts","../src/checks/eeat-expert-sourcing.ts","../src/checks/eeat-editorial-review.ts","../src/checks/eeat-source-quality.ts","../src/checks/eeat-ymyl-compliance.ts","../src/checks/eeat-conflict-disclosure.ts","../src/checks/eeat-content-accuracy.ts","../src/checks/eeat-correction-policy.ts","../src/checks/eeat-privacy-safety.ts","../src/checks/eeat-overall-score.ts","../src/checks/eeat-ymyl-multiplier.ts","../src/checks/previously-used-keyphrase.ts","../src/checks/keyphrase-even-distribution.ts","../src/checks/single-h1.ts","../src/checks/word-complexity.ts","../src/checks/inclusive-language.ts","../src/checks/competing-links.ts","../src/checks/content-freshness.ts","../src/checks/keyphrase-markup.ts","../src/checks/headline-analyzer.ts","../src/checks/inbound-internal-links.ts","../src/checks/intent-utils.ts","../src/checks/intent-keyword-classification.ts","../src/checks/intent-sub-type.ts","../src/checks/intent-modifier-analysis.ts","../src/checks/intent-multi-detection.ts","../src/checks/intent-content-alignment.ts","../src/checks/intent-title-match.ts","../src/checks/intent-meta-match.ts","../src/checks/intent-heading-match.ts","../src/checks/intent-opening-match.ts","../src/checks/intent-conclusion-match.ts","../src/checks/intent-informational-completeness.ts","../src/checks/intent-transactional-elements.ts","../src/checks/intent-commercial-elements.ts","../src/checks/intent-navigational-clarity.ts","../src/checks/intent-format-match.ts","../src/checks/intent-signal-density.ts","../src/checks/intent-signal-distribution.ts","../src/checks/intent-depth-match.ts","../src/checks/intent-mixed-warning.ts","../src/checks/intent-cta-alignment.ts","../src/checks/intent-snippet-readiness.ts","../src/checks/intent-schema-readiness.ts","../src/checks/intent-paa-coverage.ts","../src/checks/intent-satisfaction-score.ts","../src/checks/intent-funnel-position.ts","../src/checks/intent-related-coverage.ts","../src/checks/intent-engagement-signals.ts","../src/checks/aeo-direct-answer.ts","../src/checks/aeo-faq-section.ts","../src/checks/aeo-fact-density.ts","../src/checks/aeo-tldr-summary.ts","../src/checks/aeo-concise-answers.ts","../src/checks/aeo-structured-data-hints.ts","../src/checks/aeo-citation-readiness.ts","../src/checks/aeo-entity-coverage.ts","../src/analyzer.ts"],"sourcesContent":["// @power-seo/content-analysis — React Components\n// ----------------------------------------------------------------------------\n\nimport { createElement, useMemo } from 'react';\nimport type { ReactNode } from 'react';\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport type { AnalysisConfig } from './types.js';\nimport { analyzeContent } from './analyzer.js';\n\n// --- ScorePanel ---\n\nexport interface ScorePanelProps {\n score: number;\n maxScore: number;\n}\n\nfunction getScoreColor(percentage: number): string {\n if (percentage >= 70) return '#1e8e3e';\n if (percentage >= 40) return '#f29900';\n return '#d93025';\n}\n\nfunction getScoreLabel(percentage: number): string {\n if (percentage >= 70) return 'Good';\n if (percentage >= 40) return 'OK';\n return 'Needs improvement';\n}\n\n/**\n * Displays an overall SEO score as a colored bar with label.\n */\nexport function ScorePanel({ score, maxScore }: ScorePanelProps) {\n const percentage = maxScore > 0 ? Math.round((score / maxScore) * 100) : 0;\n const color = getScoreColor(percentage);\n const label = getScoreLabel(percentage);\n\n return createElement(\n 'div',\n {\n style: {\n fontFamily: 'system-ui, -apple-system, sans-serif',\n padding: '16px',\n borderRadius: '8px',\n border: '1px solid #e0e0e0',\n backgroundColor: '#fff',\n },\n },\n createElement(\n 'div',\n {\n style: {\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n marginBottom: '8px',\n },\n },\n createElement(\n 'span',\n { style: { fontWeight: 600, fontSize: '14px', color: '#333' } },\n 'SEO Score',\n ),\n createElement(\n 'span',\n { style: { fontWeight: 700, fontSize: '18px', color } },\n `${percentage}%`,\n ),\n ),\n createElement(\n 'div',\n {\n style: {\n width: '100%',\n height: '8px',\n backgroundColor: '#e8e8e8',\n borderRadius: '4px',\n overflow: 'hidden',\n },\n },\n createElement('div', {\n style: {\n width: `${percentage}%`,\n height: '100%',\n backgroundColor: color,\n borderRadius: '4px',\n transition: 'width 0.3s ease',\n },\n }),\n ),\n createElement(\n 'div',\n { style: { marginTop: '4px', fontSize: '12px', color: '#666' } },\n `${label} — ${score}/${maxScore} points`,\n ),\n );\n}\n\n// --- CheckList ---\n\nexport interface CheckListProps {\n results: AnalysisResult[];\n}\n\nconst STATUS_ICONS: Record<string, string> = {\n good: '\\u2705',\n ok: '\\u26a0\\ufe0f',\n poor: '\\u274c',\n};\n\nconst STATUS_COLORS: Record<string, string> = {\n good: '#1e8e3e',\n ok: '#f29900',\n poor: '#d93025',\n};\n\n/**\n * Renders analysis results as a list with status icons.\n */\nexport function CheckList({ results }: CheckListProps) {\n return createElement(\n 'ul',\n {\n style: {\n listStyle: 'none',\n padding: 0,\n margin: 0,\n fontFamily: 'system-ui, -apple-system, sans-serif',\n },\n },\n ...results.map((result) =>\n createElement(\n 'li',\n {\n key: result.id,\n style: {\n padding: '10px 12px',\n borderBottom: '1px solid #f0f0f0',\n display: 'flex',\n gap: '10px',\n alignItems: 'flex-start',\n },\n },\n createElement(\n 'span',\n { style: { flexShrink: 0, fontSize: '14px' } },\n STATUS_ICONS[result.status] ?? '',\n ),\n createElement(\n 'div',\n { style: { flex: 1 } },\n createElement(\n 'div',\n {\n style: {\n fontWeight: 600,\n fontSize: '13px',\n color: STATUS_COLORS[result.status] ?? '#333',\n },\n },\n result.title,\n ),\n createElement(\n 'div',\n { style: { fontSize: '12px', color: '#555', marginTop: '2px' } },\n result.description,\n ),\n ),\n ),\n ),\n );\n}\n\n// --- ContentAnalyzer ---\n\nexport interface ContentAnalyzerProps {\n input: ContentAnalysisInput;\n config?: AnalysisConfig;\n children?: ReactNode;\n}\n\n/**\n * All-in-one component that runs analysis and renders score + check list.\n */\nexport function ContentAnalyzer({ input, config, children }: ContentAnalyzerProps) {\n const output = useMemo(() => analyzeContent(input, config), [input, config]);\n\n return createElement(\n 'div',\n {\n style: {\n fontFamily: 'system-ui, -apple-system, sans-serif',\n },\n },\n createElement(ScorePanel, { score: output.score, maxScore: output.maxScore }),\n createElement('div', { style: { height: '12px' } }),\n createElement(CheckList, { results: output.results }),\n children ?? null,\n );\n}\n","// @power-seo/content-analysis — Title Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { validateTitle } from '@power-seo/core';\n\nexport function checkTitle(input: ContentAnalysisInput): AnalysisResult[] {\n const results: AnalysisResult[] = [];\n const { title, focusKeyphrase } = input;\n\n // --- Presence & validity check ---\n if (!title || title.trim().length === 0) {\n results.push({\n id: 'title-presence',\n title: 'SEO title',\n description: 'No title has been set. Add a title to improve search visibility.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n });\n return results;\n }\n\n const validation = validateTitle(title);\n\n if (!validation.valid) {\n results.push({\n id: 'title-presence',\n title: 'SEO title',\n description: validation.message,\n status: 'ok',\n score: 3,\n maxScore: 5,\n });\n } else if (validation.severity === 'warning') {\n results.push({\n id: 'title-presence',\n title: 'SEO title',\n description: validation.message,\n status: 'ok',\n score: 3,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'title-presence',\n title: 'SEO title',\n description: validation.message,\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n }\n\n // --- Keyphrase in title check ---\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n results.push({\n id: 'title-keyphrase',\n title: 'Keyphrase in title',\n description: 'No focus keyphrase set. Set one to check keyphrase usage in the title.',\n status: 'na',\n score: 0,\n maxScore: 5,\n });\n } else {\n const kp = focusKeyphrase.toLowerCase().trim();\n const titleLower = title.toLowerCase();\n\n if (titleLower.includes(kp)) {\n results.push({\n id: 'title-keyphrase',\n title: 'Keyphrase in title',\n description: 'The focus keyphrase appears in the SEO title. Good job!',\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'title-keyphrase',\n title: 'Keyphrase in title',\n description:\n 'The focus keyphrase does not appear in the SEO title. Add it to improve relevance.',\n status: 'ok',\n score: 2,\n maxScore: 5,\n });\n }\n }\n\n return results;\n}\n","// @power-seo/content-analysis — Meta Description Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { validateMetaDescription } from '@power-seo/core';\n\nexport function checkMetaDescription(input: ContentAnalysisInput): AnalysisResult[] {\n const results: AnalysisResult[] = [];\n const { metaDescription, focusKeyphrase } = input;\n\n // --- Presence & validity check ---\n if (!metaDescription || metaDescription.trim().length === 0) {\n results.push({\n id: 'meta-description-presence',\n title: 'Meta description',\n description:\n 'No meta description has been set. Add one to control how your page appears in search results.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n });\n return results;\n }\n\n const validation = validateMetaDescription(metaDescription);\n\n if (!validation.valid) {\n results.push({\n id: 'meta-description-presence',\n title: 'Meta description',\n description: validation.message,\n status: 'ok',\n score: 3,\n maxScore: 5,\n });\n } else if (validation.severity === 'warning') {\n results.push({\n id: 'meta-description-presence',\n title: 'Meta description',\n description: validation.message,\n status: 'ok',\n score: 3,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'meta-description-presence',\n title: 'Meta description',\n description: validation.message,\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n }\n\n // --- Keyphrase in meta description check ---\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n results.push({\n id: 'meta-description-keyphrase',\n title: 'Keyphrase in meta description',\n description: 'No focus keyphrase set. Set one to check keyphrase usage in the meta description.',\n status: 'na',\n score: 0,\n maxScore: 5,\n });\n } else {\n const kp = focusKeyphrase.toLowerCase().trim();\n const descLower = metaDescription.toLowerCase();\n\n if (descLower.includes(kp)) {\n results.push({\n id: 'meta-description-keyphrase',\n title: 'Keyphrase in meta description',\n description: 'The focus keyphrase appears in the meta description. Well done!',\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'meta-description-keyphrase',\n title: 'Keyphrase in meta description',\n description:\n 'The focus keyphrase does not appear in the meta description. Add it to improve click-through rate.',\n status: 'ok',\n score: 2,\n maxScore: 5,\n });\n }\n }\n\n return results;\n}\n","// @power-seo/content-analysis — Keyphrase Usage Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport {\n analyzeKeyphraseOccurrences,\n calculateKeywordDensity,\n KEYWORD_DENSITY,\n} from '@power-seo/core';\n\nexport function checkKeyphraseUsage(input: ContentAnalysisInput): AnalysisResult[] {\n const results: AnalysisResult[] = [];\n const { focusKeyphrase, title, metaDescription, content, slug, images } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n results.push({\n id: 'keyphrase-density',\n title: 'Keyphrase density',\n description: 'No focus keyphrase set. Set one to get keyphrase analysis.',\n status: 'na',\n score: 0,\n maxScore: 1,\n });\n results.push({\n id: 'keyphrase-distribution',\n title: 'Keyphrase distribution',\n description: 'No focus keyphrase set. Set one to analyze keyphrase distribution.',\n status: 'na',\n score: 0,\n maxScore: 5,\n });\n return results;\n }\n\n const occurrences = analyzeKeyphraseOccurrences({\n keyphrase: focusKeyphrase,\n title,\n metaDescription,\n content,\n slug,\n images,\n });\n\n const densityResult = calculateKeywordDensity(focusKeyphrase, content);\n\n // --- Density check ---\n if (densityResult.density < KEYWORD_DENSITY.MIN) {\n results.push({\n id: 'keyphrase-density',\n title: 'Keyphrase density',\n description: `Keyphrase density is ${densityResult.density}%, which is below the recommended minimum of ${KEYWORD_DENSITY.MIN}%. Use the keyphrase more often.`,\n status: 'poor',\n score: 0,\n maxScore: 1,\n });\n } else if (densityResult.density > KEYWORD_DENSITY.MAX) {\n results.push({\n id: 'keyphrase-density',\n title: 'Keyphrase density',\n description: `Keyphrase density is ${densityResult.density}%, which exceeds the recommended maximum of ${KEYWORD_DENSITY.MAX}%. Reduce usage to avoid keyword stuffing.`,\n status: 'poor',\n score: 0,\n maxScore: 1,\n });\n } else if (\n densityResult.density >= KEYWORD_DENSITY.MIN &&\n densityResult.density <= KEYWORD_DENSITY.MAX\n ) {\n const isOptimal = Math.abs(densityResult.density - KEYWORD_DENSITY.OPTIMAL) < 0.5;\n results.push({\n id: 'keyphrase-density',\n title: 'Keyphrase density',\n description: `Keyphrase density is ${densityResult.density}%.${isOptimal ? ' Great — this is close to the optimal density.' : ' This is within the recommended range.'}`,\n status: 'good',\n score: 1,\n maxScore: 1,\n });\n }\n\n // --- Distribution check ---\n const distributionPoints: string[] = [];\n if (!occurrences.inFirstParagraph) distributionPoints.push('introduction');\n if (!occurrences.inH1 && occurrences.inHeadings === 0) distributionPoints.push('headings');\n if (!occurrences.inSlug) distributionPoints.push('slug');\n if (occurrences.inAltText === 0 && images && images.length > 0)\n distributionPoints.push('image alt text');\n\n if (distributionPoints.length === 0) {\n results.push({\n id: 'keyphrase-distribution',\n title: 'Keyphrase distribution',\n description:\n 'The focus keyphrase is well-distributed across the introduction, headings, slug, and image alt text.',\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n } else if (distributionPoints.length <= 2) {\n results.push({\n id: 'keyphrase-distribution',\n title: 'Keyphrase distribution',\n description: `Consider adding the keyphrase to: ${distributionPoints.join(', ')}.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'keyphrase-distribution',\n title: 'Keyphrase distribution',\n description: `The keyphrase is missing from: ${distributionPoints.join(', ')}. Distribute it more broadly.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n });\n }\n\n return results;\n}\n","// @power-seo/content-analysis — Headings Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml } from '@power-seo/core';\n\ninterface HeadingInfo {\n level: number;\n text: string;\n}\n\n/**\n * Parse all headings (h1-h6) from HTML using plain string search.\n * Avoids regex ReDoS on crafted inputs with many repeated heading-like tags.\n */\nfunction parseHeadings(html: string): HeadingInfo[] {\n const headings: HeadingInfo[] = [];\n const lc = html.toLowerCase();\n let pos = 0;\n\n while (pos < lc.length) {\n // Find the next heading tag of any level\n let earliest = -1;\n let earliestLevel = 0;\n for (let level = 1; level <= 6; level++) {\n const idx = lc.indexOf(`<h${level}`, pos);\n if (idx !== -1 && (earliest === -1 || idx < earliest)) {\n earliest = idx;\n earliestLevel = level;\n }\n }\n if (earliest === -1) break;\n\n const contentStart = lc.indexOf('>', earliest);\n if (contentStart === -1) break;\n\n const closeTag = `</h${earliestLevel}>`;\n const closeIdx = lc.indexOf(closeTag, contentStart + 1);\n if (closeIdx === -1) {\n pos = contentStart + 1;\n continue;\n }\n\n headings.push({\n level: earliestLevel,\n text: stripHtml(html.slice(contentStart + 1, closeIdx)),\n });\n pos = closeIdx + closeTag.length;\n }\n\n return headings;\n}\n\nexport function checkHeadings(input: ContentAnalysisInput): AnalysisResult[] {\n const results: AnalysisResult[] = [];\n const { content, title, focusKeyphrase } = input;\n const headings = parseHeadings(content);\n\n // Treat the page title as an implicit H1 (most CMS render title as <h1>)\n const hasTitle = title && title.trim().length > 0;\n if (hasTitle) {\n headings.unshift({ level: 1, text: title.trim() });\n }\n\n // --- H1 & structure check ---\n const h1s = headings.filter((h) => h.level === 1);\n\n if (h1s.length === 0) {\n results.push({\n id: 'heading-structure',\n title: 'Heading structure',\n description: 'No H1 heading found. Add exactly one H1 as the main heading of your page.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n });\n } else if (h1s.length > 1) {\n results.push({\n id: 'heading-structure',\n title: 'Heading structure',\n description: `Found ${h1s.length} H1 headings. Use exactly one H1 per page for proper SEO.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n });\n } else {\n // Check heading hierarchy\n let hasSkippedLevel = false;\n for (let i = 1; i < headings.length; i++) {\n const prev = headings[i - 1]!;\n const curr = headings[i]!;\n if (curr.level > prev.level + 1) {\n hasSkippedLevel = true;\n break;\n }\n }\n\n if (hasSkippedLevel) {\n results.push({\n id: 'heading-structure',\n title: 'Heading structure',\n description:\n 'The heading hierarchy skips levels (e.g., H2 to H4). Use sequential heading levels for better accessibility and SEO.',\n status: 'ok',\n score: 3,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'heading-structure',\n title: 'Heading structure',\n description: 'The heading structure looks good with a single H1 and proper hierarchy.',\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n }\n }\n\n // --- Keyphrase in headings check ---\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n results.push({\n id: 'heading-keyphrase',\n title: 'Keyphrase in subheadings',\n description: 'No focus keyphrase set. Set one to check keyphrase usage in subheadings.',\n status: 'na',\n score: 0,\n maxScore: 5,\n });\n } else {\n const kp = focusKeyphrase.toLowerCase().trim();\n const subheadings = headings.filter((h) => h.level >= 2);\n const hasKeyphraseInSubheading = subheadings.some((h) => h.text.toLowerCase().includes(kp));\n\n if (subheadings.length === 0) {\n results.push({\n id: 'heading-keyphrase',\n title: 'Keyphrase in subheadings',\n description:\n 'No subheadings (H2-H6) found. Add subheadings to structure your content and include the focus keyphrase.',\n status: 'ok',\n score: 2,\n maxScore: 5,\n });\n } else if (hasKeyphraseInSubheading) {\n results.push({\n id: 'heading-keyphrase',\n title: 'Keyphrase in subheadings',\n description: 'The focus keyphrase appears in at least one subheading. Nice!',\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'heading-keyphrase',\n title: 'Keyphrase in subheadings',\n description:\n 'The focus keyphrase does not appear in any subheading. Consider adding it to an H2 or H3.',\n status: 'ok',\n score: 2,\n maxScore: 5,\n });\n }\n }\n\n return results;\n}\n","// @power-seo/content-analysis — Word Count Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { getWords, MIN_WORD_COUNT, RECOMMENDED_WORD_COUNT } from '@power-seo/core';\n\nexport function checkWordCount(input: ContentAnalysisInput): AnalysisResult {\n const words = getWords(input.content);\n const count = words.length;\n\n if (count < MIN_WORD_COUNT) {\n return {\n id: 'word-count',\n title: 'Word count',\n description: `The content is ${count} words, which is below the recommended minimum of ${MIN_WORD_COUNT}. Add more content to improve SEO.`,\n status: 'poor',\n score: 1,\n maxScore: 10,\n };\n }\n\n if (count < RECOMMENDED_WORD_COUNT) {\n return {\n id: 'word-count',\n title: 'Word count',\n description: `The content is ${count} words. Consider expanding to at least ${RECOMMENDED_WORD_COUNT} words for more comprehensive coverage.`,\n status: 'ok',\n score: 3,\n maxScore: 10,\n };\n }\n\n return {\n id: 'word-count',\n title: 'Word count',\n description: `The content is ${count} words. Good — this provides enough depth for search engines.`,\n status: 'good',\n score: 10,\n maxScore: 10,\n };\n}\n","// @power-seo/content-analysis — Images Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\nexport function checkImages(input: ContentAnalysisInput): AnalysisResult[] {\n const results: AnalysisResult[] = [];\n const { images, focusKeyphrase } = input;\n\n if (!images || images.length === 0) {\n results.push({\n id: 'image-alt',\n title: 'Image alt attributes',\n description: 'No images found. Add images to make your content more engaging and improve SEO.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n });\n return results;\n }\n\n // --- Alt text check ---\n const missingAlt = images.filter((img) => !img.alt || img.alt.trim().length === 0);\n\n if (missingAlt.length === 0) {\n results.push({\n id: 'image-alt',\n title: 'Image alt attributes',\n description: 'All images have alt text. Great for accessibility and SEO!',\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n } else if (missingAlt.length === images.length) {\n results.push({\n id: 'image-alt',\n title: 'Image alt attributes',\n description:\n 'None of the images have alt text. Add descriptive alt attributes for accessibility and SEO.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'image-alt',\n title: 'Image alt attributes',\n description: `${missingAlt.length} of ${images.length} images are missing alt text. Add alt attributes to all images.`,\n status: 'ok',\n score: 2,\n maxScore: 5,\n });\n }\n\n // --- Keyphrase in alt text check ---\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n results.push({\n id: 'image-keyphrase',\n title: 'Keyphrase in image alt',\n description: 'No focus keyphrase set. Set one to check keyphrase usage in image alt text.',\n status: 'na',\n score: 0,\n maxScore: 5,\n });\n } else {\n const kp = focusKeyphrase.toLowerCase().trim();\n const hasKeyphraseInAlt = images.some((img) => img.alt && img.alt.toLowerCase().includes(kp));\n\n if (hasKeyphraseInAlt) {\n results.push({\n id: 'image-keyphrase',\n title: 'Keyphrase in image alt',\n description: 'The focus keyphrase appears in at least one image alt attribute.',\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'image-keyphrase',\n title: 'Keyphrase in image alt',\n description:\n 'The focus keyphrase does not appear in any image alt attribute. Add it to at least one image.',\n status: 'ok',\n score: 2,\n maxScore: 5,\n });\n }\n }\n\n return results;\n}\n","// @power-seo/content-analysis — Links Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\n/**\n * Parse all <a href=\"...\"> links from HTML content and classify as internal or external.\n */\nfunction parseLinksFromContent(\n html: string,\n siteUrl?: string,\n): { internal: string[]; external: string[] } {\n const internal: string[] = [];\n const external: string[] = [];\n\n const hrefRegex = /<a\\s[^>]*href=[\"']([^\"'#]+)[\"'][^>]*>/gi;\n let match;\n while ((match = hrefRegex.exec(html)) !== null) {\n const url = match[1]!.trim();\n // Skip anchors, mailto, tel, javascript\n if (!url || url.startsWith('mailto:') || url.startsWith('tel:') || url.startsWith('javascript:'))\n continue;\n\n if (url.startsWith('/') || url.startsWith('./') || url.startsWith('../')) {\n // Relative paths are internal\n internal.push(url);\n } else if (siteUrl && url.toLowerCase().startsWith(siteUrl.toLowerCase())) {\n // Same-origin absolute URLs are internal\n internal.push(url);\n } else if (url.startsWith('http://') || url.startsWith('https://')) {\n // Other absolute URLs are external\n external.push(url);\n }\n }\n\n return { internal, external };\n}\n\nexport function checkLinks(input: ContentAnalysisInput): AnalysisResult[] {\n const results: AnalysisResult[] = [];\n\n // Use provided arrays if available, otherwise parse from content HTML\n let internalLinks = input.internalLinks;\n let externalLinks = input.externalLinks;\n\n if (\n (!internalLinks || internalLinks.length === 0) &&\n (!externalLinks || externalLinks.length === 0) &&\n input.content\n ) {\n const parsed = parseLinksFromContent(input.content, input.siteUrl);\n if (parsed.internal.length > 0 || parsed.external.length > 0) {\n internalLinks = parsed.internal.length > 0 ? parsed.internal : undefined;\n externalLinks = parsed.external.length > 0 ? parsed.external : undefined;\n }\n }\n\n const hasInternal = internalLinks && internalLinks.length > 0;\n const hasExternal = externalLinks && externalLinks.length > 0;\n\n if (!hasInternal) {\n results.push({\n id: 'internal-links',\n title: 'Internal links',\n description:\n 'No internal links found. Add links to other pages on your site to improve crawlability and distribute link equity.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'internal-links',\n title: 'Internal links',\n description: `Found ${internalLinks!.length} internal link${internalLinks!.length === 1 ? '' : 's'}. Good for site structure and SEO.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n }\n\n if (!hasExternal) {\n results.push({\n id: 'external-links',\n title: 'External links',\n description:\n 'No external links found. Consider adding outbound links to authoritative sources to strengthen your content.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'external-links',\n title: 'External links',\n description: `Found ${externalLinks!.length} external link${externalLinks!.length === 1 ? '' : 's'}. Linking to quality sources adds credibility.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n }\n\n return results;\n}\n","// @power-seo/content-analysis — Paragraph Length Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml } from '@power-seo/core';\n\nconst MAX_PARAGRAPH_WORDS = 150;\nconst IDEAL_MAX_PARAGRAPH_WORDS = 120;\n\n/**\n * Extract paragraphs from HTML content.\n * Splits on <p>, <br>, or double newlines.\n */\nfunction extractParagraphs(html: string): string[] {\n // Split on closing/opening paragraph tags or double line breaks\n const blocks = html\n .replace(/<\\/p>\\s*<p[^>]*>/gi, '\\n\\n')\n .replace(/<br\\s*\\/?>/gi, '\\n')\n .replace(/<\\/?p[^>]*>/gi, '\\n\\n')\n .split(/\\n{2,}/);\n\n return blocks\n .map((block) => stripHtml(block).trim())\n .filter((text) => text.length > 0);\n}\n\nfunction countWords(text: string): number {\n return text.split(/\\s+/).filter((w) => w.length > 0).length;\n}\n\nexport function checkParagraphLength(input: ContentAnalysisInput): AnalysisResult {\n const paragraphs = extractParagraphs(input.content);\n\n if (paragraphs.length === 0) {\n return {\n id: 'paragraph-length',\n title: 'Paragraph length',\n description: 'No paragraphs found. Structure your content into paragraphs for better readability.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n\n const longParagraphs = paragraphs.filter((p) => countWords(p) > MAX_PARAGRAPH_WORDS);\n const slightlyLong = paragraphs.filter(\n (p) => countWords(p) > IDEAL_MAX_PARAGRAPH_WORDS && countWords(p) <= MAX_PARAGRAPH_WORDS,\n );\n\n if (longParagraphs.length > 0) {\n return {\n id: 'paragraph-length',\n title: 'Paragraph length',\n description: `${longParagraphs.length} paragraph${longParagraphs.length === 1 ? ' is' : 's are'} over ${MAX_PARAGRAPH_WORDS} words. Break long paragraphs into shorter ones for better readability.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n }\n\n if (slightlyLong.length > 0) {\n return {\n id: 'paragraph-length',\n title: 'Paragraph length',\n description: `${slightlyLong.length} paragraph${slightlyLong.length === 1 ? ' is' : 's are'} between ${IDEAL_MAX_PARAGRAPH_WORDS} and ${MAX_PARAGRAPH_WORDS} words. Consider shortening them.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'paragraph-length',\n title: 'Paragraph length',\n description: 'All paragraphs are a good length. Nice work!',\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Sentence Length Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml } from '@power-seo/core';\n\nconst MAX_RECOMMENDED_SENTENCE_LENGTH = 20;\nconst LONG_SENTENCE_THRESHOLD = 0.25; // 25% of sentences being long is problematic\n\n/**\n * Split text into sentences using common sentence-ending punctuation.\n */\nfunction splitSentences(text: string): string[] {\n return text\n .split(/[.!?]+/)\n .map((s) => s.trim())\n .filter((s) => s.length > 0 && s.split(/\\s+/).length >= 3); // At least 3 words to count as a sentence\n}\n\nfunction countWords(text: string): number {\n return text.split(/\\s+/).filter((w) => w.length > 0).length;\n}\n\nexport function checkSentenceLength(input: ContentAnalysisInput): AnalysisResult {\n const plainText = stripHtml(input.content).trim();\n\n if (!plainText || plainText.length === 0) {\n return {\n id: 'sentence-length',\n title: 'Sentence length',\n description: 'No content to analyze. Add content to get sentence length analysis.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const sentences = splitSentences(plainText);\n\n if (sentences.length === 0) {\n return {\n id: 'sentence-length',\n title: 'Sentence length',\n description: 'Not enough sentences to analyze. Add more content.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const longSentences = sentences.filter((s) => countWords(s) > MAX_RECOMMENDED_SENTENCE_LENGTH);\n const longPercentage = longSentences.length / sentences.length;\n\n if (longPercentage > LONG_SENTENCE_THRESHOLD) {\n const pct = Math.round(longPercentage * 100);\n return {\n id: 'sentence-length',\n title: 'Sentence length',\n description: `${pct}% of sentences are over ${MAX_RECOMMENDED_SENTENCE_LENGTH} words. Try to shorten some sentences for easier reading.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n }\n\n if (longSentences.length > 0) {\n return {\n id: 'sentence-length',\n title: 'Sentence length',\n description: `${longSentences.length} sentence${longSentences.length === 1 ? ' is' : 's are'} over ${MAX_RECOMMENDED_SENTENCE_LENGTH} words, but overall sentence length is acceptable.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'sentence-length',\n title: 'Sentence length',\n description: 'Sentence lengths are good. Your content is easy to read.',\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Subheading Distribution Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml } from '@power-seo/core';\n\nconst MAX_WORDS_BETWEEN_SUBHEADINGS = 300;\nconst IDEAL_WORDS_BETWEEN_SUBHEADINGS = 250;\n\n/**\n * Split content into sections based on headings (H2-H6).\n * Returns word counts for text between headings.\n */\nfunction getTextSectionLengths(html: string): number[] {\n // Split on any heading tag (h2-h6)\n const sections = html.split(/<h[2-6][^>]*>/i);\n return sections\n .map((section) => {\n // Remove closing heading tags and other HTML\n const cleaned = section.replace(/<\\/h[2-6]>/gi, '');\n const text = stripHtml(cleaned).trim();\n return text.split(/\\s+/).filter((w) => w.length > 0).length;\n })\n .filter((count) => count > 0);\n}\n\nfunction countWords(text: string): number {\n const plain = stripHtml(text).trim();\n return plain.split(/\\s+/).filter((w) => w.length > 0).length;\n}\n\nexport function checkSubheadingDistribution(input: ContentAnalysisInput): AnalysisResult {\n const totalWords = countWords(input.content);\n\n // Short content doesn't need subheadings\n if (totalWords < 300) {\n return {\n id: 'subheading-distribution',\n title: 'Subheading distribution',\n description: 'Content is short enough that subheading distribution is not a concern.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const sectionLengths = getTextSectionLengths(input.content);\n\n // If there are no subheadings at all in long content\n if (sectionLengths.length <= 1) {\n return {\n id: 'subheading-distribution',\n title: 'Subheading distribution',\n description: `The content is ${totalWords} words long but has no subheadings. Add H2/H3 subheadings to break up the text and improve readability.`,\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n\n const tooLongSections = sectionLengths.filter((len) => len > MAX_WORDS_BETWEEN_SUBHEADINGS);\n const slightlyLongSections = sectionLengths.filter(\n (len) => len > IDEAL_WORDS_BETWEEN_SUBHEADINGS && len <= MAX_WORDS_BETWEEN_SUBHEADINGS,\n );\n\n if (tooLongSections.length > 0) {\n return {\n id: 'subheading-distribution',\n title: 'Subheading distribution',\n description: `${tooLongSections.length} text section${tooLongSections.length === 1 ? '' : 's'} exceed${tooLongSections.length === 1 ? 's' : ''} ${MAX_WORDS_BETWEEN_SUBHEADINGS} words without a subheading. Add more subheadings to break up long sections.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n }\n\n if (slightlyLongSections.length > 0) {\n return {\n id: 'subheading-distribution',\n title: 'Subheading distribution',\n description: `${slightlyLongSections.length} section${slightlyLongSections.length === 1 ? ' is' : 's are'} between ${IDEAL_WORDS_BETWEEN_SUBHEADINGS} and ${MAX_WORDS_BETWEEN_SUBHEADINGS} words. Consider adding subheadings to improve structure.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'subheading-distribution',\n title: 'Subheading distribution',\n description: 'Subheadings are well-distributed throughout the content. Great structure!',\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Transition Words Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml } from '@power-seo/core';\n\nconst TRANSITION_WORDS = [\n // Addition\n 'additionally', 'also', 'besides', 'furthermore', 'in addition', 'moreover', 'likewise',\n // Contrast\n 'although', 'however', 'in contrast', 'nevertheless', 'nonetheless', 'on the other hand',\n 'whereas', 'while', 'yet', 'but', 'despite', 'even though', 'in spite of', 'still',\n // Cause & effect\n 'accordingly', 'as a result', 'because', 'consequently', 'due to', 'for this reason',\n 'hence', 'since', 'so', 'therefore', 'thus',\n // Sequence\n 'finally', 'first', 'firstly', 'in the first place', 'next', 'previously',\n 'second', 'secondly', 'subsequently', 'then', 'third', 'thirdly',\n // Example\n 'for example', 'for instance', 'in other words', 'in particular', 'namely',\n 'specifically', 'such as', 'to illustrate',\n // Conclusion\n 'all in all', 'altogether', 'in conclusion', 'in short', 'in summary',\n 'to conclude', 'to sum up', 'to summarize', 'ultimately', 'overall',\n // Emphasis\n 'above all', 'certainly', 'especially', 'importantly', 'in fact', 'indeed',\n 'most importantly', 'of course', 'particularly', 'undoubtedly',\n // Similarity\n 'equally', 'in the same way', 'similarly',\n];\n\nconst MIN_TRANSITION_PERCENTAGE = 20; // At least 20% of sentences should have transition words\nconst GOOD_TRANSITION_PERCENTAGE = 30;\n\nfunction splitSentences(text: string): string[] {\n return text\n .split(/[.!?]+/)\n .map((s) => s.trim())\n .filter((s) => s.length > 0 && s.split(/\\s+/).length >= 3);\n}\n\nexport function checkTransitionWords(input: ContentAnalysisInput): AnalysisResult {\n const plainText = stripHtml(input.content).trim();\n\n if (!plainText || plainText.length === 0) {\n return {\n id: 'transition-words',\n title: 'Transition words',\n description: 'No content to analyze. Add content to get transition word analysis.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const sentences = splitSentences(plainText);\n\n if (sentences.length < 3) {\n return {\n id: 'transition-words',\n title: 'Transition words',\n description: 'Not enough sentences to analyze transition word usage.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const sentencesWithTransition = sentences.filter((sentence) => {\n const lower = sentence.toLowerCase();\n return TRANSITION_WORDS.some((tw) => {\n // Check if transition word/phrase appears at the start or as a standalone part of the sentence\n const idx = lower.indexOf(tw);\n if (idx === -1) return false;\n // Ensure it's a word boundary\n const before = idx === 0 || /[\\s,;:()]/.test(lower[idx - 1]!);\n const after =\n idx + tw.length >= lower.length || /[\\s,;:()]/.test(lower[idx + tw.length]!);\n return before && after;\n });\n });\n\n const percentage = Math.round((sentencesWithTransition.length / sentences.length) * 100);\n\n if (percentage >= GOOD_TRANSITION_PERCENTAGE) {\n return {\n id: 'transition-words',\n title: 'Transition words',\n description: `${percentage}% of sentences contain transition words. Your text flows well.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (percentage >= MIN_TRANSITION_PERCENTAGE) {\n return {\n id: 'transition-words',\n title: 'Transition words',\n description: `${percentage}% of sentences contain transition words. Consider adding a few more for smoother flow.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'transition-words',\n title: 'Transition words',\n description: `Only ${percentage}% of sentences contain transition words. Use words like \"however\", \"therefore\", \"for example\" to improve text flow.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Canonical URL Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\nexport function checkCanonicalUrl(input: ContentAnalysisInput): AnalysisResult {\n const { canonicalUrl } = input;\n\n if (!canonicalUrl || canonicalUrl.trim().length === 0) {\n return {\n id: 'canonical-url',\n title: 'Canonical URL',\n description:\n 'No canonical URL set. Add a canonical URL to prevent duplicate content issues and consolidate link equity.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n\n const trimmed = canonicalUrl.trim();\n\n // Check for bare slugs (no slashes, no protocol)\n if (!trimmed.includes('/') && !trimmed.startsWith('http')) {\n return {\n id: 'canonical-url',\n title: 'Canonical URL',\n description:\n 'Canonical URL appears to be a slug, not a full URL. Use the complete URL including the domain (e.g., https://example.com/blog/my-post).',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n\n // Check for relative paths\n if (trimmed.startsWith('/')) {\n return {\n id: 'canonical-url',\n title: 'Canonical URL',\n description:\n 'Canonical URL is a relative path. It must be an absolute URL starting with https:// (e.g., https://example.com/blog/my-post).',\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n }\n\n // Check for HTTP instead of HTTPS\n if (trimmed.startsWith('http://')) {\n return {\n id: 'canonical-url',\n title: 'Canonical URL',\n description:\n 'Canonical URL uses HTTP. Consider using HTTPS for better security and SEO.',\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n // Valid HTTPS canonical URL\n if (trimmed.startsWith('https://')) {\n return {\n id: 'canonical-url',\n title: 'Canonical URL',\n description: 'Canonical URL is set and uses HTTPS. Good for SEO and duplicate content prevention.',\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n // Unrecognized format\n return {\n id: 'canonical-url',\n title: 'Canonical URL',\n description:\n 'Canonical URL format is not recognized. Use an absolute URL starting with https:// (e.g., https://example.com/blog/my-post).',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Keyphrase in Introduction Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\nexport function checkKeyphraseIntroduction(input: ContentAnalysisInput): AnalysisResult {\n const { focusKeyphrase, content } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n return {\n id: 'keyphrase-introduction',\n title: 'Keyphrase in introduction',\n description: 'No focus keyphrase set.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n // Parse first <p> tag from HTML content\n const firstParagraphMatch = content.match(/<p[^>]*>([\\s\\S]*?)<\\/p>/i);\n\n if (!firstParagraphMatch) {\n return {\n id: 'keyphrase-introduction',\n title: 'Keyphrase in introduction',\n description:\n 'The focus keyphrase does not appear in the introduction. Add it to the first paragraph for better relevance.',\n status: 'ok',\n score: 2,\n maxScore: 5,\n };\n }\n\n // Strip HTML tags from the first paragraph\n const firstParagraphText = firstParagraphMatch[1]!.replace(/<[^>]*>/g, '');\n const kp = focusKeyphrase.toLowerCase().trim();\n const paragraphLower = firstParagraphText.toLowerCase();\n\n if (paragraphLower.includes(kp)) {\n return {\n id: 'keyphrase-introduction',\n title: 'Keyphrase in introduction',\n description: 'The focus keyphrase appears in the introduction. Good job!',\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n return {\n id: 'keyphrase-introduction',\n title: 'Keyphrase in introduction',\n description:\n 'The focus keyphrase does not appear in the introduction. Add it to the first paragraph for better relevance.',\n status: 'ok',\n score: 2,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Keyphrase in URL/Slug Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\nexport function checkKeyphraseSlug(input: ContentAnalysisInput): AnalysisResult {\n const { focusKeyphrase, slug } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n return {\n id: 'keyphrase-slug',\n title: 'Keyphrase in URL',\n description: 'No focus keyphrase set.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n if (!slug || slug.trim().length === 0) {\n return {\n id: 'keyphrase-slug',\n title: 'Keyphrase in URL',\n description: 'No slug set. Set a URL slug containing your focus keyphrase.',\n status: 'ok',\n score: 2,\n maxScore: 5,\n };\n }\n\n // Convert keyphrase to slug format (lowercase, spaces to hyphens)\n const keyphraseSlug = focusKeyphrase.toLowerCase().trim().replace(/\\s+/g, '-');\n const slugLower = slug.toLowerCase().trim();\n\n if (slugLower.includes(keyphraseSlug)) {\n return {\n id: 'keyphrase-slug',\n title: 'Keyphrase in URL',\n description: 'The focus keyphrase appears in the URL. Great for SEO!',\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n // Also check if keyphrase words appear in slug individually\n const keyphraseWords = focusKeyphrase.toLowerCase().trim().split(/\\s+/);\n const allWordsPresent = keyphraseWords.every((word) => slugLower.includes(word));\n\n if (allWordsPresent) {\n return {\n id: 'keyphrase-slug',\n title: 'Keyphrase in URL',\n description: 'The focus keyphrase appears in the URL. Great for SEO!',\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n return {\n id: 'keyphrase-slug',\n title: 'Keyphrase in URL',\n description:\n 'The focus keyphrase does not appear in the URL. Add it to improve search visibility.',\n status: 'ok',\n score: 2,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Keyphrase Length Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\nexport function checkKeyphraseLength(input: ContentAnalysisInput): AnalysisResult {\n const { focusKeyphrase } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n return {\n id: 'keyphrase-length',\n title: 'Keyphrase length',\n description: 'No focus keyphrase set.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const words = focusKeyphrase.trim().split(/\\s+/);\n const wordCount = words.length;\n\n if (wordCount <= 4) {\n return {\n id: 'keyphrase-length',\n title: 'Keyphrase length',\n description: `Focus keyphrase length is good (${wordCount} word${wordCount === 1 ? '' : 's'}).`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (wordCount <= 6) {\n return {\n id: 'keyphrase-length',\n title: 'Keyphrase length',\n description: `Focus keyphrase is ${wordCount} words long. Consider using a shorter, more focused keyphrase.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'keyphrase-length',\n title: 'Keyphrase length',\n description: `Focus keyphrase is too long (${wordCount} words). Use 1-4 words for better targeting.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Title Readability Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\nconst POSITIVE_WORDS = [\n 'best', 'top', 'great', 'amazing', 'ultimate', 'essential', 'proven',\n 'powerful', 'effective', 'easy', 'simple', 'free', 'new', 'guide',\n 'tips', 'secrets', 'complete', 'perfect', 'incredible',\n];\n\nconst NEGATIVE_WORDS = [\n 'worst', 'avoid', 'never', 'stop', 'mistake', 'wrong', 'bad', 'fail',\n 'warning', 'danger', 'risk', 'problem', 'error', 'crisis', 'scam',\n];\n\nconst POWER_WORDS = [\n 'ultimate', 'essential', 'proven', 'powerful', 'effective', 'incredible',\n 'complete', 'perfect', 'best', 'top', 'amazing', 'great',\n 'unleash', 'exclusive', 'guaranteed', 'instantly', 'revolutionary',\n 'breakthrough', 'limited', 'urgent', 'remarkable', 'extraordinary',\n 'unbelievable', 'insider', 'confidential', 'shocking', 'little-known',\n 'behind-the-scenes', 'bizarre', 'free', 'new', 'guide', 'tips',\n 'secrets', 'simple', 'easy',\n];\n\nexport function checkTitleReadability(input: ContentAnalysisInput): AnalysisResult[] {\n const results: AnalysisResult[] = [];\n const { title } = input;\n\n const titleText = title && title.trim().length > 0 ? title.trim() : '';\n const titleLower = titleText.toLowerCase();\n const titleWords = titleLower.split(/[\\s-]+/);\n\n // --- Check 1: Title contains a number ---\n if (/\\d/.test(titleText)) {\n results.push({\n id: 'title-number',\n title: 'Title number',\n description: 'Title contains a number. Titles with numbers get higher click-through rates.',\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'title-number',\n title: 'Title number',\n description: 'Consider adding a number to your title to increase CTR.',\n status: 'ok',\n score: 3,\n maxScore: 5,\n });\n }\n\n // --- Check 2: Title sentiment ---\n const hasPositive = POSITIVE_WORDS.some((word) => titleWords.includes(word));\n const hasNegative = NEGATIVE_WORDS.some((word) => titleWords.includes(word));\n\n if (hasPositive) {\n results.push({\n id: 'title-sentiment',\n title: 'Title sentiment',\n description: 'Title has positive sentiment. Emotional titles attract more clicks.',\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n } else if (hasNegative) {\n results.push({\n id: 'title-sentiment',\n title: 'Title sentiment',\n description: 'Title has negative sentiment. This can drive curiosity and clicks.',\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'title-sentiment',\n title: 'Title sentiment',\n description:\n 'Title lacks emotional sentiment. Add positive or negative emotion words to improve CTR.',\n status: 'ok',\n score: 3,\n maxScore: 5,\n });\n }\n\n // --- Check 3: Title contains a power word ---\n const foundPowerWord = POWER_WORDS.find((word) => titleWords.includes(word));\n\n if (foundPowerWord) {\n results.push({\n id: 'title-power-word',\n title: 'Title power word',\n description: `Title contains a power word ('${foundPowerWord}'). Power words make titles more compelling.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'title-power-word',\n title: 'Title power word',\n description:\n \"No power words found in your title. Add words like 'ultimate', 'essential', or 'proven' to make it more compelling.\",\n status: 'ok',\n score: 3,\n maxScore: 5,\n });\n }\n\n return results;\n}\n","// @power-seo/content-analysis — Keyphrase Position in Title Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\nexport function checkKeyphraseTitlePosition(input: ContentAnalysisInput): AnalysisResult {\n const { focusKeyphrase, title } = input;\n\n if (\n !focusKeyphrase ||\n focusKeyphrase.trim().length === 0 ||\n !title ||\n title.trim().length === 0\n ) {\n return {\n id: 'keyphrase-title-position',\n title: 'Keyphrase position in title',\n description: 'No focus keyphrase or title set.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const kp = focusKeyphrase.toLowerCase().trim();\n const titleLower = title.toLowerCase();\n const position = titleLower.indexOf(kp);\n\n if (position === -1) {\n return {\n id: 'keyphrase-title-position',\n title: 'Keyphrase position in title',\n description: 'The focus keyphrase does not appear in the title.',\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n }\n\n const halfLength = Math.floor(title.length / 2);\n\n if (position <= halfLength) {\n return {\n id: 'keyphrase-title-position',\n title: 'Keyphrase position in title',\n description:\n 'Focus keyphrase appears near the beginning of the title. Well done!',\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n return {\n id: 'keyphrase-title-position',\n title: 'Keyphrase position in title',\n description:\n 'The focus keyphrase appears in the title but not near the beginning. Move it closer to the start.',\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — URL Length Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\nexport function checkUrlLength(input: ContentAnalysisInput): AnalysisResult {\n const url = input.canonicalUrl || input.slug;\n\n if (!url || url.trim().length === 0) {\n return {\n id: 'url-length',\n title: 'URL length',\n description: 'No URL set.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const length = url.trim().length;\n\n if (length <= 75) {\n return {\n id: 'url-length',\n title: 'URL length',\n description: `URL length is good (${length} characters). Short URLs perform better in search.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (length <= 100) {\n return {\n id: 'url-length',\n title: 'URL length',\n description: `URL is ${length} characters. Consider keeping it under 75 characters.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'url-length',\n title: 'URL length',\n description: `URL is too long (${length} characters). Keep URLs under 75 characters for better SEO.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Text Presence Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\nexport function checkTextPresence(input: ContentAnalysisInput): AnalysisResult {\n const { content } = input;\n\n // Strip HTML tags and count words\n const textOnly = content.replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ').trim();\n const words = textOnly.length > 0 ? textOnly.split(/\\s+/) : [];\n const wordCount = words.length;\n\n if (wordCount === 0) {\n return {\n id: 'text-presence',\n title: 'Text presence',\n description: 'No text content found. Add text content to your page.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n\n if (wordCount < 50) {\n return {\n id: 'text-presence',\n title: 'Text presence',\n description: `Very little text content (${wordCount} words). Search engines need substantial content to understand your page.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n }\n\n return {\n id: 'text-presence',\n title: 'Text presence',\n description: 'Text content is present. Good foundation for SEO.',\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Image/Video Count Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\nexport function checkMediaCount(input: ContentAnalysisInput): AnalysisResult {\n const { content, images } = input;\n\n // Count images from input.images AND <img> tags in content HTML\n const inputImageCount = images ? images.length : 0;\n const contentImgMatches = content.match(/<img\\b/gi);\n const contentImageCount = contentImgMatches ? contentImgMatches.length : 0;\n const imageCount = inputImageCount + contentImageCount;\n\n // Count videos by regex matching\n const videoPatterns = /<video|<iframe|youtube\\.com|vimeo\\.com/gi;\n const videoMatches = content.match(videoPatterns);\n const videoCount = videoMatches ? videoMatches.length : 0;\n\n const totalMedia = imageCount + videoCount;\n\n if (totalMedia === 0) {\n return {\n id: 'media-count',\n title: 'Media count',\n description: 'No images or videos found. Add visual media to improve engagement.',\n status: 'poor',\n score: 0,\n maxScore: 8,\n };\n }\n\n // Strip HTML, count words\n const textOnly = content.replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ').trim();\n const words = textOnly.length > 0 ? textOnly.split(/\\s+/) : [];\n const wordCount = words.length;\n\n // Good ratio: at least 1 media per 200 words\n const requiredMedia = Math.max(1, Math.floor(wordCount / 200));\n\n if (totalMedia >= requiredMedia) {\n return {\n id: 'media-count',\n title: 'Media count',\n description: `Good use of visual media (${imageCount} image${imageCount === 1 ? '' : 's'}, ${videoCount} video${videoCount === 1 ? '' : 's'}). Media improves engagement and time on page.`,\n status: 'good',\n score: 5,\n maxScore: 8,\n };\n }\n\n return {\n id: 'media-count',\n title: 'Media count',\n description: `Found ${imageCount} image${imageCount === 1 ? '' : 's'} and ${videoCount} video${videoCount === 1 ? '' : 's'}. Consider adding more visual media for better engagement.`,\n status: 'ok',\n score: 3,\n maxScore: 8,\n };\n}\n","// @power-seo/content-analysis — Table of Contents Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\nexport function checkTableOfContents(input: ContentAnalysisInput): AnalysisResult {\n const { content } = input;\n\n // Strip HTML, count words\n const textOnly = content.replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ').trim();\n const words = textOnly.length > 0 ? textOnly.split(/\\s+/) : [];\n const wordCount = words.length;\n\n if (wordCount < 1500) {\n return {\n id: 'table-of-contents',\n title: 'Table of contents',\n description: 'Content is short enough that a table of contents is not needed.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n // Check for common table of contents patterns\n const hasToc =\n /id=[\"']table-of-contents[\"']/i.test(content) ||\n /id=[\"']toc[\"']/i.test(content) ||\n /class=[\"'][^\"']*\\btoc\\b[^\"']*[\"']/i.test(content) ||\n /<nav[^>]*>[\\s\\S]*?<a[^>]*href=[\"']#/i.test(content) ||\n /<[ou]l[^>]*>[\\s\\S]*?<a[^>]*href=[\"']#/i.test(content);\n\n if (hasToc) {\n return {\n id: 'table-of-contents',\n title: 'Table of contents',\n description: 'Table of contents detected. This helps readers navigate long content.',\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n return {\n id: 'table-of-contents',\n title: 'Table of contents',\n description: `Content is ${wordCount} words long. Consider adding a table of contents for better navigation and potential SERP feature.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Nofollow Links Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\nexport function checkNofollowLinks(input: ContentAnalysisInput): AnalysisResult {\n const { content, siteUrl } = input;\n\n // Parse all <a> tags from content\n const anchorRegex = /<a\\s([^>]*)>/gi;\n const externalLinks: Array<{ href: string; rel: string }> = [];\n\n let match;\n while ((match = anchorRegex.exec(content)) !== null) {\n const attrs = match[1]!;\n\n // Extract href\n const hrefMatch = attrs.match(/href=[\"']([^\"'#]+)[\"']/i);\n if (!hrefMatch) continue;\n\n const url = hrefMatch[1]!.trim();\n\n // Skip non-http links\n if (\n !url ||\n url.startsWith('mailto:') ||\n url.startsWith('tel:') ||\n url.startsWith('javascript:') ||\n url.startsWith('/') ||\n url.startsWith('./') ||\n url.startsWith('../')\n ) {\n continue;\n }\n\n // Skip same-origin links\n if (siteUrl && url.toLowerCase().startsWith(siteUrl.toLowerCase())) {\n continue;\n }\n\n // Only consider external http(s) links\n if (url.startsWith('http://') || url.startsWith('https://')) {\n const relMatch = attrs.match(/rel=[\"']([^\"']*)[\"']/i);\n const rel = relMatch ? relMatch[1]! : '';\n externalLinks.push({ href: url, rel });\n }\n }\n\n if (externalLinks.length === 0) {\n return {\n id: 'nofollow-links',\n title: 'Nofollow links',\n description: 'No external links found.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const nofollowCount = externalLinks.filter((link) =>\n link.rel.toLowerCase().includes('nofollow'),\n ).length;\n\n if (nofollowCount < externalLinks.length) {\n // Some are dofollow — this is good\n return {\n id: 'nofollow-links',\n title: 'Nofollow links',\n description:\n 'Your external links include dofollow links. This is natural and healthy for SEO.',\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n // All external links are nofollow\n return {\n id: 'nofollow-links',\n title: 'Nofollow links',\n description: `All ${externalLinks.length} external link${externalLinks.length === 1 ? ' is' : 's are'} nofollow. Consider making some dofollow to appear more natural.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Secondary Keyphrases Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\n/**\n * Strip HTML tags from a string.\n */\nfunction stripHtml(html: string): string {\n return html.replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ').trim();\n}\n\n/**\n * Check if secondary keyphrases (seed keywords) appear in the content.\n *\n * Secondary keyphrases are related terms that support the primary focus keyphrase.\n * They help search engines understand the topic depth and relevance of the content.\n */\nexport function checkSecondaryKeyphrases(input: ContentAnalysisInput): AnalysisResult[] {\n const results: AnalysisResult[] = [];\n const { secondaryKeyphrases, content, title, metaDescription } = input;\n\n if (!secondaryKeyphrases || secondaryKeyphrases.length === 0) {\n results.push({\n id: 'secondary-keyphrases',\n title: 'Secondary keyphrases',\n description: 'No secondary keyphrases (seed keywords) set. Add related keywords to broaden your topic coverage.',\n status: 'ok',\n score: 2,\n maxScore: 5,\n });\n return results;\n }\n\n const plainContent = stripHtml(content || '').toLowerCase();\n const titleLower = (title || '').toLowerCase();\n const metaLower = (metaDescription || '').toLowerCase();\n const combinedText = `${titleLower} ${metaLower} ${plainContent}`;\n\n const found: string[] = [];\n const missing: string[] = [];\n\n for (const kp of secondaryKeyphrases) {\n const trimmed = kp.trim();\n if (!trimmed) continue;\n if (combinedText.includes(trimmed.toLowerCase())) {\n found.push(trimmed);\n } else {\n missing.push(trimmed);\n }\n }\n\n const total = found.length + missing.length;\n if (total === 0) {\n results.push({\n id: 'secondary-keyphrases',\n title: 'Secondary keyphrases',\n description: 'No valid secondary keyphrases provided. Add related keywords to broaden your topic coverage.',\n status: 'ok',\n score: 2,\n maxScore: 5,\n });\n return results;\n }\n\n const foundRatio = found.length / total;\n\n if (missing.length === 0) {\n results.push({\n id: 'secondary-keyphrases',\n title: 'Secondary keyphrases',\n description: `All ${found.length} secondary keyphrase${found.length === 1 ? '' : 's'} found in your content. Great topic coverage!`,\n status: 'good',\n score: 5,\n maxScore: 5,\n });\n } else if (foundRatio >= 0.5) {\n results.push({\n id: 'secondary-keyphrases',\n title: 'Secondary keyphrases',\n description: `${found.length} of ${total} secondary keyphrases found. Missing: ${missing.join(', ')}. Try to include them naturally.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n });\n } else {\n results.push({\n id: 'secondary-keyphrases',\n title: 'Secondary keyphrases',\n description: `Only ${found.length} of ${total} secondary keyphrases found. Missing: ${missing.join(', ')}. Add these related terms to improve topic depth.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n });\n }\n\n return results;\n}\n","// @power-seo/content-analysis — E-E-A-T: First-Person Experience Depth\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\n\n// First-person experience phrases (regex patterns)\nconst EXPERIENCE_PATTERNS: RegExp[] = [\n // Direct experience verbs\n /\\bi\\s+tested\\b/gi,\n /\\bi\\s+used\\b/gi,\n /\\bi\\s+tried\\b/gi,\n /\\bi\\s+found\\s+that\\b/gi,\n /\\bi\\s+noticed\\b/gi,\n /\\bi\\s+discovered\\b/gi,\n /\\bi\\s+experienced\\b/gi,\n /\\bi\\s+observed\\b/gi,\n /\\bi\\s+realized\\b/gi,\n /\\bi\\s+learned\\b/gi,\n /\\bi\\s+personally\\b/gi,\n /\\bi\\s+recommend\\b/gi,\n /\\bi\\s+prefer\\b/gi,\n /\\bi\\s+chose\\b/gi,\n /\\bi\\s+built\\b/gi,\n /\\bi\\s+created\\b/gi,\n /\\bi\\s+implemented\\b/gi,\n /\\bi\\s+configured\\b/gi,\n /\\bi\\s+set\\s+up\\b/gi,\n /\\bi\\s+installed\\b/gi,\n /\\bi\\s+measured\\b/gi,\n /\\bi\\s+achieved\\b/gi,\n /\\bi\\s+ran\\b/gi,\n /\\bi\\s+compared\\b/gi,\n\n // Experience phrases\n /\\bin\\s+my\\s+experience\\b/gi,\n /\\bfrom\\s+my\\s+experience\\b/gi,\n /\\bbased\\s+on\\s+my\\s+experience\\b/gi,\n /\\bhaving\\s+used\\b/gi,\n /\\bhaving\\s+tested\\b/gi,\n /\\bhaving\\s+worked\\s+with\\b/gi,\n /\\bfrom\\s+my\\s+testing\\b/gi,\n /\\bwhat\\s+i\\s+found\\b/gi,\n\n // Temporal experience markers\n /\\bafter\\s+\\d+\\s+(months?|years?|weeks?|days?)\\s+of\\s+using\\b/gi,\n /\\bover\\s+the\\s+past\\s+\\d+\\s+(months?|years?|weeks?)\\b/gi,\n /\\bfor\\s+the\\s+last\\s+\\d+\\s+(months?|years?|weeks?)\\b/gi,\n /\\bi['']ve\\s+been\\s+using\\b/gi,\n /\\bi['']ve\\s+spent\\b/gi,\n /\\bi['']ve\\s+worked\\s+with\\b/gi,\n /\\bfor\\s+over\\s+\\d+\\s+years?\\b/gi,\n /\\bsince\\s+\\d{4}\\b/gi,\n\n // Outcome reporting\n /\\bthe\\s+results?\\s+showed\\b/gi,\n /\\bthe\\s+results?\\s+were\\b/gi,\n /\\bi\\s+saw\\s+improvements?\\b/gi,\n /\\bi\\s+saw\\s+a\\s+\\d+%?\\b/gi,\n /\\bthe\\s+outcome\\s+was\\b/gi,\n /\\bthis\\s+resulted\\s+in\\b/gi,\n /\\bperformance\\s+improved\\b/gi,\n /\\bwe\\s+achieved\\b/gi,\n\n // Comparison from use\n /\\bwhen\\s+i\\s+switched\\b/gi,\n /\\bcompared\\s+to\\s+my\\s+previous\\b/gi,\n /\\bi\\s+preferred\\s+.+\\s+over\\b/gi,\n /\\bbefore\\s+and\\s+after\\b/gi,\n /\\bi\\s+migrated\\s+from\\b/gi,\n /\\bside.by.side\\s+comparison\\b/gi,\n\n // Process narration\n /\\bhere['']?s?\\s+what\\s+happened\\b/gi,\n /\\bstep\\s+by\\s+step\\b/gi,\n /\\bthe\\s+process\\s+involved\\b/gi,\n /\\bhere['']?s?\\s+how\\s+i\\b/gi,\n /\\bmy\\s+approach\\s+was\\b/gi,\n /\\bwhat\\s+worked\\s+for\\s+me\\b/gi,\n /\\bi\\s+walked\\s+through\\b/gi,\n /\\bmy\\s+workflow\\b/gi,\n /\\bin\\s+practice\\b/gi,\n /\\bhands.on\\b/gi,\n /\\breal.world\\b/gi,\n];\n\nexport function checkExperienceDepth(input: ContentAnalysisInput): AnalysisResult {\n const plainText = stripHtml(input.content || '');\n const words = getWords(plainText);\n const wordCount = words.length;\n\n if (wordCount < 50) {\n return {\n id: 'eeat-experience-depth',\n title: 'Experience signals',\n description: 'Content is too short to analyze experience depth.',\n status: 'na',\n score: 0,\n maxScore: 9,\n };\n }\n\n let totalMatches = 0;\n const matchedPhrases: string[] = [];\n\n for (const pattern of EXPERIENCE_PATTERNS) {\n const matches = plainText.match(pattern);\n if (matches) {\n totalMatches += matches.length;\n // Collect unique phrase examples (max 3)\n for (const m of matches) {\n const normalized = m.trim().toLowerCase();\n if (!matchedPhrases.includes(normalized) && matchedPhrases.length < 5) {\n matchedPhrases.push(normalized);\n }\n }\n }\n }\n\n // Density: experience markers per 500 words\n const density = (totalMatches / wordCount) * 500;\n\n if (density >= 3) {\n return {\n id: 'eeat-experience-depth',\n title: 'Experience signals',\n description: `Strong first-hand experience signals detected (${totalMatches} markers). Phrases like \"${matchedPhrases.slice(0, 3).join('\", \"')}\" demonstrate real experience.`,\n status: 'good',\n score: 5,\n maxScore: 9,\n };\n }\n\n if (density >= 1) {\n return {\n id: 'eeat-experience-depth',\n title: 'Experience signals',\n description: `Some experience signals found (${totalMatches} markers). Add more first-person experience phrases like \"I tested\", \"in my experience\", or outcome reporting to strengthen E-E-A-T.`,\n status: 'ok',\n score: 3,\n maxScore: 9,\n };\n }\n\n return {\n id: 'eeat-experience-depth',\n title: 'Experience signals',\n description: 'No first-hand experience signals detected. Add personal experience, testing outcomes, temporal markers (\"after 6 months of using...\"), and process narration to demonstrate real experience with the topic.',\n status: 'poor',\n score: 0,\n maxScore: 9,\n };\n}\n","// @power-seo/content-analysis — E-E-A-T: Original Research & Data\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\n\nconst RESEARCH_PATTERNS: RegExp[] = [\n // Original research language\n /\\b(our|my)\\s+study\\b/gi,\n /\\b(our|my)\\s+research\\b/gi,\n /\\b(our|my)\\s+analysis\\b/gi,\n /\\b(our|my)\\s+findings?\\b/gi,\n /\\b(our|my)\\s+data\\b/gi,\n /\\b(our|my)\\s+survey\\b/gi,\n /\\b(our|my)\\s+experiment\\b/gi,\n /\\b(our|my)\\s+investigation\\b/gi,\n /\\b(our|my)\\s+audit\\b/gi,\n /\\b(our|my)\\s+benchmark\\b/gi,\n /\\bwe\\s+(surveyed|analyzed|studied|measured|tested|examined|collected|gathered|interviewed|evaluated)\\b/gi,\n /\\bi\\s+(surveyed|analyzed|studied|measured|examined|collected|gathered|interviewed|evaluated)\\b/gi,\n\n // Methodology descriptions\n /\\b(our|the)\\s+methodology\\b/gi,\n /\\bsample\\s+size\\b/gi,\n /\\bdata\\s+collection\\b/gi,\n /\\bwe\\s+used\\s+a?\\s*(methodology|approach|framework|method)\\b/gi,\n /\\bcontrol\\s+group\\b/gi,\n /\\btest\\s+group\\b/gi,\n /\\bstatistically\\s+significant\\b/gi,\n /\\bconfidence\\s+interval\\b/gi,\n /\\bmargin\\s+of\\s+error\\b/gi,\n /\\bcorrelation\\b/gi,\n\n // Data presentation\n /\\baccording\\s+to\\s+(our|my)\\b/gi,\n /\\b(our|my)\\s+results\\s+(show|indicate|suggest|reveal|demonstrate)\\b/gi,\n /\\bthe\\s+data\\s+(shows?|indicates?|suggests?|reveals?)\\b/gi,\n /\\bas\\s+(our|my)\\s+data\\s+shows\\b/gi,\n /\\bwe\\s+found\\s+that\\b/gi,\n /\\bwe\\s+discovered\\s+that\\b/gi,\n /\\bwe\\s+observed\\s+that\\b/gi,\n\n // Quantitative markers\n /\\b\\d+\\s*%\\s+of\\s+(our|the)\\s+(respondents|participants|users|customers|sample|subjects)\\b/gi,\n /\\b(n\\s*=\\s*\\d+|N\\s*=\\s*\\d+)\\b/g,\n /\\b\\d+\\s+out\\s+of\\s+\\d+\\b/gi,\n /\\b(figure|table|chart|graph)\\s+\\d+\\b/gi,\n];\n\n// Detect data tables in HTML\nconst DATA_TABLE_PATTERN = /<table\\b[^>]*>[\\s\\S]*?<\\/table>/gi;\nconst CHART_PATTERNS = /<(canvas|svg)\\b|chart|graph|data-chart/gi;\n\nexport function checkOriginalResearch(input: ContentAnalysisInput): AnalysisResult {\n const plainText = stripHtml(input.content || '');\n const words = getWords(plainText);\n const wordCount = words.length;\n\n if (wordCount < 50) {\n return {\n id: 'eeat-original-research',\n title: 'Original research',\n description: 'Content is too short to analyze for original research.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n let totalMatches = 0;\n const matchedTypes: Set<string> = new Set();\n\n for (const pattern of RESEARCH_PATTERNS) {\n const matches = plainText.match(pattern);\n if (matches) {\n totalMatches += matches.length;\n if (pattern.source.includes('methodology') || pattern.source.includes('sample')) {\n matchedTypes.add('methodology');\n } else if (pattern.source.includes('survey') || pattern.source.includes('experiment')) {\n matchedTypes.add('primary research');\n } else if (pattern.source.includes('%') || pattern.source.includes('n\\\\s*=')) {\n matchedTypes.add('quantitative data');\n } else {\n matchedTypes.add('research language');\n }\n }\n }\n\n // Check for data tables and charts in HTML\n const tableMatches = (input.content || '').match(DATA_TABLE_PATTERN);\n const chartMatches = (input.content || '').match(CHART_PATTERNS);\n if (tableMatches) {\n totalMatches += tableMatches.length * 2; // Tables are weighted more heavily\n matchedTypes.add('data tables');\n }\n if (chartMatches) {\n totalMatches += chartMatches.length * 2;\n matchedTypes.add('charts/visualizations');\n }\n\n // Check for inline statistics (e.g., \"increased by 47%\", \"3.5x faster\")\n const statsPattern = /\\b\\d+(\\.\\d+)?\\s*(%|x\\s+faster|x\\s+more|x\\s+better|x\\s+higher|x\\s+lower|times\\s+more|percent)\\b/gi;\n const statsMatches = plainText.match(statsPattern);\n if (statsMatches) {\n totalMatches += statsMatches.length;\n matchedTypes.add('statistics');\n }\n\n const density = (totalMatches / wordCount) * 500;\n const typeCount = matchedTypes.size;\n const types = Array.from(matchedTypes).join(', ');\n\n if (density >= 3 && typeCount >= 2) {\n return {\n id: 'eeat-original-research',\n title: 'Original research',\n description: `Strong original research signals detected (${totalMatches} markers across ${types}). Content demonstrates original data collection and analysis.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (density >= 1 || typeCount >= 1) {\n return {\n id: 'eeat-original-research',\n title: 'Original research',\n description: `Some research signals found (${types || 'basic markers'}). Add more original data, methodology descriptions, quantitative results, and data visualizations to strengthen expertise signals.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'eeat-original-research',\n title: 'Original research',\n description: 'No original research signals detected. Add original data, surveys, experiments, methodology descriptions, or data visualizations to demonstrate expertise and first-hand research.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — E-E-A-T: Specificity & Detail Depth\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\n\n// Vague filler phrases that indicate low specificity\nconst VAGUE_PHRASES: RegExp[] = [\n /\\bvery\\s+(good|nice|great|important|useful|helpful|interesting|fast|slow|big|small|easy|hard)\\b/gi,\n /\\breally\\s+(good|nice|great|important|useful|helpful|amazing|fast|awesome)\\b/gi,\n /\\bamazing\\s+(product|tool|service|solution|thing)\\b/gi,\n /\\bincredibly\\s+(useful|helpful|important|powerful)\\b/gi,\n /\\ba\\s+lot\\s+of\\s+(people|users|companies)\\b/gi,\n /\\bmany\\s+(people|users|experts)\\s+(say|think|believe|agree)\\b/gi,\n /\\beveryone\\s+(knows|agrees|says)\\b/gi,\n /\\bit['']?s?\\s+well.known\\s+that\\b/gi,\n /\\bobviously\\b/gi,\n /\\bclearly\\b/gi,\n /\\bbasically\\b/gi,\n /\\bsomehow\\b/gi,\n /\\bsort\\s+of\\b/gi,\n /\\bkind\\s+of\\b/gi,\n /\\bstuff\\s+like\\s+that\\b/gi,\n /\\band\\s+so\\s+on\\b/gi,\n /\\betc\\.?\\s/gi,\n /\\bthings\\s+like\\s+that\\b/gi,\n /\\bmore\\s+or\\s+less\\b/gi,\n];\n\n// Specific detail patterns that indicate high specificity\nconst SPECIFIC_PATTERNS: RegExp[] = [\n // Exact numbers with context\n /\\b\\d+(\\.\\d+)?\\s*(ms|milliseconds?|seconds?|minutes?|hours?|days?|weeks?|months?|years?|GB|MB|KB|TB|px|em|rem|%|mph|km|miles?|kg|lbs?|dollars?|USD|EUR|GBP)\\b/gi,\n // Version numbers\n /\\bv?\\d+\\.\\d+(\\.\\d+)?\\b/g,\n // Dates\n /\\b(January|February|March|April|May|June|July|August|September|October|November|December)\\s+\\d{1,2},?\\s+\\d{4}\\b/gi,\n /\\b\\d{4}-\\d{2}-\\d{2}\\b/g,\n // Proper nouns / product names (capitalized multi-word)\n /\\b[A-Z][a-z]+(?:\\s+[A-Z][a-z]+)+\\b/g,\n // Specific measurements\n /\\b\\d+(\\.\\d+)?\\s*x\\s*\\d+(\\.\\d+)?\\b/gi,\n // Code references\n /`[^`]+`/g,\n // Exact percentages with decimals\n /\\b\\d+\\.\\d+\\s*%/g,\n // Price points\n /\\$\\d+(\\.\\d{2})?/g,\n // URLs/paths mentioned\n /\\bhttps?:\\/\\/[^\\s<>\"]+/gi,\n // Named tools/technologies\n /\\b(using|with|via|through)\\s+[A-Z][a-zA-Z]+(?:\\s+[A-Z][a-zA-Z]+)*\\b/g,\n];\n\nexport function checkSpecificityDepth(input: ContentAnalysisInput): AnalysisResult {\n const plainText = stripHtml(input.content || '');\n const words = getWords(plainText);\n const wordCount = words.length;\n\n if (wordCount < 50) {\n return {\n id: 'eeat-specificity-depth',\n title: 'Content specificity',\n description: 'Content is too short to analyze specificity.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n let vagueCount = 0;\n for (const pattern of VAGUE_PHRASES) {\n const matches = plainText.match(pattern);\n if (matches) vagueCount += matches.length;\n }\n\n let specificCount = 0;\n for (const pattern of SPECIFIC_PATTERNS) {\n const matches = (input.content || '').match(pattern);\n if (matches) specificCount += matches.length;\n }\n\n const specificDensity = (specificCount / wordCount) * 500;\n const specificityRatio = specificCount > 0 && vagueCount > 0\n ? specificCount / (specificCount + vagueCount)\n : specificCount > 0 ? 1 : 0;\n\n if (specificDensity >= 5 && specificityRatio >= 0.7) {\n return {\n id: 'eeat-specificity-depth',\n title: 'Content specificity',\n description: `Excellent detail depth with ${specificCount} specific data points (numbers, dates, versions, measurements). Content demonstrates thorough knowledge.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (specificDensity >= 2 && specificityRatio >= 0.4) {\n const suggestions: string[] = [];\n if (vagueCount > 3) suggestions.push(`replace ${vagueCount} vague phrases with specific data`);\n if (specificDensity < 5) suggestions.push('add more exact numbers, dates, and measurements');\n return {\n id: 'eeat-specificity-depth',\n title: 'Content specificity',\n description: `Moderate specificity (${specificCount} specific details, ${vagueCount} vague phrases). ${suggestions.join('; ')}.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'eeat-specificity-depth',\n title: 'Content specificity',\n description: `Low content specificity (${vagueCount} vague phrases, only ${specificCount} specific details). Replace generic language (\"very good\", \"really helpful\") with exact numbers, dates, version numbers, measurements, and named tools/products.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — E-E-A-T: Multimedia Experience Evidence\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\n\n// Contextual caption patterns (figcaption, alt text with description)\nconst CAPTION_PATTERNS = /<figcaption\\b[^>]*>[^<]+<\\/figcaption>/gi;\nconst FIGURE_PATTERN = /<figure\\b/gi;\n\n// Before/after comparison patterns\nconst BEFORE_AFTER_PATTERNS: RegExp[] = [\n /\\bbefore\\s+and\\s+after\\b/gi,\n /\\bcomparison\\b/gi,\n /\\bside[\\s-]by[\\s-]side\\b/gi,\n /\\bvs\\.?\\b/gi,\n /\\bbefore[\\s:]/gi,\n /\\bafter[\\s:]/gi,\n];\n\n// Screenshot/evidence indicators in alt text or content\nconst EVIDENCE_ALT_PATTERNS: RegExp[] = [\n /screenshot/i,\n /screen\\s*cap/i,\n /dashboard/i,\n /results?\\s+(page|screen|view)/i,\n /settings?\\s+(page|panel|screen)/i,\n /configuration/i,\n /interface/i,\n /output/i,\n /terminal/i,\n /console/i,\n /editor/i,\n /photo\\s+of/i,\n /image\\s+of/i,\n /picture\\s+of/i,\n /showing/i,\n /demonstrat/i,\n];\n\n// Generic/stock alt patterns (low evidence value)\nconst GENERIC_ALT_PATTERNS: RegExp[] = [\n /^image$/i,\n /^photo$/i,\n /^picture$/i,\n /^img$/i,\n /^banner$/i,\n /^header$/i,\n /^stock/i,\n /^shutterstock/i,\n /^getty/i,\n /^unsplash/i,\n /^pexels/i,\n];\n\nexport function checkMultimediaEvidence(input: ContentAnalysisInput): AnalysisResult {\n const content = input.content || '';\n const plainText = stripHtml(content);\n const words = getWords(plainText);\n const wordCount = words.length;\n\n if (wordCount < 50) {\n return {\n id: 'eeat-multimedia-evidence',\n title: 'Multimedia evidence',\n description: 'Content is too short to analyze multimedia evidence.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n // Count images with evidence-quality alt text\n const imgTags = content.match(/<img\\b[^>]*>/gi) || [];\n const inputImages = input.images || [];\n let evidenceImages = 0;\n let genericImages = 0;\n let captionedImages = 0;\n\n // Check img tags in content\n for (const imgTag of imgTags) {\n const altMatch = imgTag.match(/alt\\s*=\\s*[\"']([^\"']+)[\"']/i);\n const alt = (altMatch && altMatch[1]) ? altMatch[1] : '';\n\n if (GENERIC_ALT_PATTERNS.some(p => p.test(alt)) || alt.length < 5) {\n genericImages++;\n } else if (EVIDENCE_ALT_PATTERNS.some(p => p.test(alt))) {\n evidenceImages++;\n }\n }\n\n // Check input.images\n for (const img of inputImages) {\n const alt = img.alt || '';\n if (GENERIC_ALT_PATTERNS.some(p => p.test(alt)) || alt.length < 5) {\n genericImages++;\n } else if (EVIDENCE_ALT_PATTERNS.some(p => p.test(alt))) {\n evidenceImages++;\n }\n }\n\n // Count figures with captions\n const figures = content.match(FIGURE_PATTERN) || [];\n const captions = content.match(CAPTION_PATTERNS) || [];\n captionedImages = Math.min(figures.length, captions.length);\n\n // Count videos\n const videoTags = content.match(/<video\\b/gi) || [];\n const iframeTags = content.match(/<iframe\\b[^>]*(?:youtube|vimeo|loom|screencast)[^>]*>/gi) || [];\n const videoCount = videoTags.length + iframeTags.length;\n\n // Check for before/after patterns\n let beforeAfterCount = 0;\n for (const pattern of BEFORE_AFTER_PATTERNS) {\n const matches = plainText.match(pattern);\n if (matches) beforeAfterCount += matches.length;\n }\n\n // Score calculation\n const totalMedia = imgTags.length + inputImages.length + videoCount;\n const qualityScore =\n (evidenceImages * 3) +\n (captionedImages * 2) +\n (videoCount * 2) +\n (beforeAfterCount > 0 ? 3 : 0) -\n (genericImages * 1);\n\n if (totalMedia === 0) {\n return {\n id: 'eeat-multimedia-evidence',\n title: 'Multimedia evidence',\n description: 'No images or videos found. Add screenshots, original photos, or videos that demonstrate first-hand experience with the topic.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n\n if (qualityScore >= 6 && evidenceImages >= 2) {\n const details: string[] = [];\n if (evidenceImages > 0) details.push(`${evidenceImages} evidence-quality images`);\n if (captionedImages > 0) details.push(`${captionedImages} captioned figures`);\n if (videoCount > 0) details.push(`${videoCount} video${videoCount > 1 ? 's' : ''}`);\n if (beforeAfterCount > 0) details.push('before/after comparisons');\n return {\n id: 'eeat-multimedia-evidence',\n title: 'Multimedia evidence',\n description: `Strong multimedia evidence: ${details.join(', ')}. Media demonstrates real experience with the topic.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (qualityScore >= 2) {\n const suggestions: string[] = [];\n if (genericImages > 0) suggestions.push(`${genericImages} images have generic alt text — add descriptive captions`);\n if (captionedImages === 0) suggestions.push('wrap images in <figure> with <figcaption> for context');\n if (videoCount === 0) suggestions.push('consider adding a video walkthrough');\n if (evidenceImages === 0) suggestions.push('add screenshots or original photos showing your experience');\n return {\n id: 'eeat-multimedia-evidence',\n title: 'Multimedia evidence',\n description: `Some multimedia present but limited evidence value. ${suggestions.slice(0, 2).join('; ')}.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'eeat-multimedia-evidence',\n title: 'Multimedia evidence',\n description: `${totalMedia} media item${totalMedia > 1 ? 's' : ''} found but they lack evidence value. Replace stock/generic images with screenshots, original photos, before/after comparisons, or annotated visuals that prove first-hand experience.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — E-E-A-T: Case Study / Real Example Patterns\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\n\n// Case study structural elements\nconst PROBLEM_PATTERNS: RegExp[] = [\n /\\b(the\\s+)?(problem|challenge|issue|pain\\s+point)\\s+(was|is|we\\s+faced)\\b/gi,\n /\\bwe\\s+(faced|encountered|dealt\\s+with|struggled\\s+with)\\b/gi,\n /\\bthe\\s+client\\s+(needed|wanted|required|asked)\\b/gi,\n /\\b(challenge|problem|issue):\\s/gi,\n /\\bour\\s+(goal|objective|target)\\s+was\\b/gi,\n /\\bthe\\s+situation\\b/gi,\n /\\binitial\\s+(state|condition|setup|assessment)\\b/gi,\n];\n\nconst APPROACH_PATTERNS: RegExp[] = [\n /\\b(our|my|the)\\s+(solution|approach|strategy|method|plan)\\b/gi,\n /\\bwe\\s+(decided\\s+to|chose\\s+to|opted\\s+for|implemented|designed|developed|built|created)\\b/gi,\n /\\bi\\s+(decided\\s+to|chose\\s+to|opted\\s+for|implemented|designed|developed|built|created)\\b/gi,\n /\\bthe\\s+implementation\\s+(involved|included|required)\\b/gi,\n /\\b(step\\s+\\d+|phase\\s+\\d+|stage\\s+\\d+)\\b/gi,\n /\\bhere['']?s?\\s+(how|what)\\s+we\\s+(did|implemented|built|solved)\\b/gi,\n /\\bthe\\s+process\\b/gi,\n /\\bour\\s+workflow\\b/gi,\n /\\btechnical\\s+(approach|solution|implementation)\\b/gi,\n];\n\nconst RESULTS_PATTERNS: RegExp[] = [\n /\\b(the\\s+)?(results?|outcomes?|impact)\\s+(was|were|showed|demonstrated|included)\\b/gi,\n /\\bwe\\s+(achieved|saw|observed|measured|recorded)\\b/gi,\n /\\bi\\s+(achieved|saw|observed|measured|recorded)\\b/gi,\n /\\b(increased|decreased|improved|reduced|grew|boosted)\\s+by\\s+\\d+/gi,\n /\\b\\d+\\s*%\\s+(increase|decrease|improvement|reduction|growth|boost|drop|decline)\\b/gi,\n /\\bROI\\s+(of|was)\\b/gi,\n /\\bkey\\s+(metrics?|results?|findings?|takeaways?)\\b/gi,\n /\\bperformance\\s+(improved|increased|grew)\\b/gi,\n /\\b(before|after)\\s+(the\\s+)?(change|implementation|migration|update|optimization)\\b/gi,\n];\n\nconst LESSONS_PATTERNS: RegExp[] = [\n /\\b(lessons?\\s+learned|key\\s+takeaways?|what\\s+we\\s+learned)\\b/gi,\n /\\bif\\s+I\\s+(had\\s+to|could|were\\s+to)\\s+do\\s+it\\s+again\\b/gi,\n /\\bin\\s+hindsight\\b/gi,\n /\\blooking\\s+back\\b/gi,\n /\\bwhat\\s+(worked|didn['']t\\s+work|surprised\\s+us)\\b/gi,\n /\\bthe\\s+biggest\\s+(lesson|takeaway|surprise|challenge)\\b/gi,\n /\\bnext\\s+time\\b/gi,\n /\\bwould\\s+recommend\\b/gi,\n /\\badvice\\s+(for|to)\\b/gi,\n /\\bpro\\s+tip\\b/gi,\n];\n\nconst REAL_EXAMPLE_PATTERNS: RegExp[] = [\n /\\bfor\\s+example\\b/gi,\n /\\bfor\\s+instance\\b/gi,\n /\\bsuch\\s+as\\b/gi,\n /\\bcase\\s+study\\b/gi,\n /\\breal[\\s-]world\\s+(example|scenario|case|application)\\b/gi,\n /\\bin\\s+one\\s+(case|instance|project|scenario)\\b/gi,\n /\\ba\\s+(client|customer|company|user|team)\\s+(of\\s+ours|we\\s+worked\\s+with)\\b/gi,\n /\\bspecifically\\b/gi,\n /\\bhere['']?s?\\s+a\\s+(concrete|specific|real)\\s+example\\b/gi,\n /\\btake\\s+(the\\s+case|for\\s+example)\\b/gi,\n];\n\ninterface ElementScore {\n name: string;\n count: number;\n found: boolean;\n}\n\nexport function checkCaseStudyPatterns(input: ContentAnalysisInput): AnalysisResult {\n const plainText = stripHtml(input.content || '');\n const words = getWords(plainText);\n const wordCount = words.length;\n\n if (wordCount < 100) {\n return {\n id: 'eeat-case-study-patterns',\n title: 'Case studies & examples',\n description: 'Content is too short to analyze for case study patterns.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const elements: ElementScore[] = [\n { name: 'problem statement', count: 0, found: false },\n { name: 'approach/solution', count: 0, found: false },\n { name: 'results/outcomes', count: 0, found: false },\n { name: 'lessons learned', count: 0, found: false },\n { name: 'real examples', count: 0, found: false },\n ];\n\n const patternGroups = [\n PROBLEM_PATTERNS,\n APPROACH_PATTERNS,\n RESULTS_PATTERNS,\n LESSONS_PATTERNS,\n REAL_EXAMPLE_PATTERNS,\n ];\n\n for (let i = 0; i < patternGroups.length; i++) {\n const group = patternGroups[i]!;\n const element = elements[i]!;\n for (const pattern of group) {\n const matches = plainText.match(pattern);\n if (matches) {\n element.count += matches.length;\n element.found = true;\n }\n }\n }\n\n const foundElements = elements.filter(e => e.found);\n const missingElements = elements.filter(e => !e.found);\n const totalMarkers = elements.reduce((sum, e) => sum + e.count, 0);\n\n if (foundElements.length >= 4 && totalMarkers >= 8) {\n return {\n id: 'eeat-case-study-patterns',\n title: 'Case studies & examples',\n description: `Excellent case study structure with ${foundElements.length}/5 elements: ${foundElements.map(e => e.name).join(', ')}. Content demonstrates real-world application and experience.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (foundElements.length >= 2 && totalMarkers >= 4) {\n return {\n id: 'eeat-case-study-patterns',\n title: 'Case studies & examples',\n description: `Partial case study elements found (${foundElements.map(e => e.name).join(', ')}). Add ${missingElements.slice(0, 2).map(e => e.name).join(' and ')} to complete the narrative.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'eeat-case-study-patterns',\n title: 'Case studies & examples',\n description: 'No case study or real-world example patterns detected. Structure content with: problem statement → approach/solution → measurable results → lessons learned. Use named examples and specific scenarios.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — E-E-A-T: Author Schema Completeness\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\n/**\n * Validates author Person schema completeness.\n * Checks: name, jobTitle, worksFor, education, credentials, knowsAbout,\n * socialProfiles (sameAs), image, bio (description), url.\n */\nexport function checkAuthorSchema(input: ContentAnalysisInput): AnalysisResult {\n const { author } = input;\n\n if (!author) {\n return {\n id: 'eeat-author-schema',\n title: 'Author schema',\n description: 'No author information provided. Add author data (name, bio, credentials, social profiles) to build E-E-A-T trust signals.',\n status: 'poor',\n score: 0,\n maxScore: 10,\n };\n }\n\n interface SchemaField {\n name: string;\n filled: boolean;\n weight: number;\n schemaProperty: string;\n }\n\n const fields: SchemaField[] = [\n { name: 'name', filled: !!(author.name && author.name.trim()), weight: 2, schemaProperty: 'name' },\n { name: 'job title', filled: !!(author.jobTitle && author.jobTitle.trim()), weight: 1.5, schemaProperty: 'jobTitle' },\n { name: 'bio/description', filled: !!(author.bio && author.bio.trim().length >= 20), weight: 1.5, schemaProperty: 'description' },\n { name: 'profile image', filled: !!(author.image && author.image.trim()), weight: 1, schemaProperty: 'image' },\n { name: 'author URL', filled: !!(author.url && author.url.trim()), weight: 1, schemaProperty: 'url' },\n { name: 'organization (worksFor)', filled: !!(author.worksFor && author.worksFor.name), weight: 1.5, schemaProperty: 'worksFor' },\n { name: 'education (alumniOf)', filled: !!(author.education && author.education.length > 0), weight: 1, schemaProperty: 'alumniOf' },\n { name: 'credentials', filled: !!(author.credentials && author.credentials.length > 0), weight: 1.5, schemaProperty: 'hasCredential' },\n { name: 'expertise topics (knowsAbout)', filled: !!(author.knowsAbout && author.knowsAbout.length > 0), weight: 1.5, schemaProperty: 'knowsAbout' },\n { name: 'social profiles (sameAs)', filled: !!(author.socialProfiles && author.socialProfiles.length > 0), weight: 1.5, schemaProperty: 'sameAs' },\n ];\n\n const totalWeight = fields.reduce((sum, f) => sum + f.weight, 0);\n const filledWeight = fields.filter(f => f.filled).reduce((sum, f) => sum + f.weight, 0);\n const completeness = filledWeight / totalWeight;\n\n const filledFields = fields.filter(f => f.filled).map(f => f.name);\n const missingFields = fields.filter(f => !f.filled).map(f => f.name);\n\n // Check bio quality\n let bioQuality = '';\n if (author.bio) {\n const bioWords = author.bio.trim().split(/\\s+/).length;\n if (bioWords < 10) bioQuality = ' (bio is too short — aim for 30+ words)';\n else if (bioWords < 30) bioQuality = ' (consider expanding bio to 50+ words)';\n }\n\n if (completeness >= 0.75) {\n return {\n id: 'eeat-author-schema',\n title: 'Author schema',\n description: `Author schema is ${Math.round(completeness * 100)}% complete (${filledFields.length}/${fields.length} fields). Schema properties: ${filledFields.join(', ')}.${bioQuality}`,\n status: 'good',\n score: 5,\n maxScore: 10,\n };\n }\n\n if (completeness >= 0.4) {\n return {\n id: 'eeat-author-schema',\n title: 'Author schema',\n description: `Author schema is ${Math.round(completeness * 100)}% complete. Missing: ${missingFields.join(', ')}. Add these Person schema properties to strengthen expertise signals.${bioQuality}`,\n status: 'ok',\n score: 3,\n maxScore: 10,\n };\n }\n\n return {\n id: 'eeat-author-schema',\n title: 'Author schema',\n description: `Author schema is only ${Math.round(completeness * 100)}% complete. Missing: ${missingFields.join(', ')}. A complete author schema (name, jobTitle, worksFor, credentials, knowsAbout, sameAs) is critical for E-E-A-T.`,\n status: 'poor',\n score: 1,\n maxScore: 10,\n };\n}\n","// @power-seo/content-analysis — E-E-A-T: Topical Authority Signals\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\n// YMYL categories that require strong topical authority\nconst YMYL_CATEGORIES = [\n 'health', 'medical', 'medicine', 'healthcare',\n 'finance', 'financial', 'investing', 'banking', 'insurance', 'tax',\n 'legal', 'law',\n 'safety', 'emergency',\n 'news', 'politics', 'government',\n];\n\n// Map credential keywords to relevant categories\nconst CREDENTIAL_RELEVANCE: Record<string, string[]> = {\n 'md': ['health', 'medical', 'medicine', 'healthcare'],\n 'doctor': ['health', 'medical', 'medicine', 'healthcare'],\n 'physician': ['health', 'medical', 'medicine', 'healthcare'],\n 'nurse': ['health', 'medical', 'medicine', 'healthcare'],\n 'pharmacist': ['health', 'medical', 'medicine', 'healthcare'],\n 'rn': ['health', 'medical', 'medicine', 'healthcare'],\n 'dentist': ['health', 'medical', 'medicine', 'healthcare'],\n 'therapist': ['health', 'medical', 'medicine', 'healthcare'],\n 'psychologist': ['health', 'medical', 'medicine', 'healthcare'],\n 'nutritionist': ['health', 'medical', 'medicine', 'healthcare'],\n 'dietitian': ['health', 'medical', 'medicine', 'healthcare'],\n 'cpa': ['finance', 'financial', 'tax', 'accounting'],\n 'cfp': ['finance', 'financial', 'investing'],\n 'cfa': ['finance', 'financial', 'investing'],\n 'accountant': ['finance', 'financial', 'tax', 'accounting'],\n 'financial advisor': ['finance', 'financial', 'investing'],\n 'attorney': ['legal', 'law'],\n 'lawyer': ['legal', 'law'],\n 'jd': ['legal', 'law'],\n 'paralegal': ['legal', 'law'],\n 'engineer': ['technology', 'engineering', 'construction'],\n 'developer': ['technology', 'software', 'programming'],\n 'architect': ['technology', 'construction', 'design'],\n 'professor': ['education', 'academic', 'research'],\n 'phd': ['academic', 'research'],\n 'researcher': ['academic', 'research', 'science'],\n 'scientist': ['science', 'research'],\n 'certified': ['professional'],\n};\n\nexport function checkTopicalAuthority(input: ContentAnalysisInput): AnalysisResult {\n const { author, contentCategory } = input;\n\n if (!author || !contentCategory) {\n return {\n id: 'eeat-topical-authority',\n title: 'Topical authority',\n description: 'Set both author information and content category to assess topical authority alignment. This check verifies the author has relevant expertise for the content topic.',\n status: 'na',\n score: 0,\n maxScore: 8,\n };\n }\n\n const category = contentCategory.toLowerCase();\n const isYMYL = YMYL_CATEGORIES.some(c => category.includes(c));\n\n let authorityScore = 0;\n const authoritySignals: string[] = [];\n const gaps: string[] = [];\n\n // Check if knowsAbout includes the content category\n if (author.knowsAbout && author.knowsAbout.length > 0) {\n const topicMatch = author.knowsAbout.some(topic =>\n topic.toLowerCase().includes(category) || category.includes(topic.toLowerCase())\n );\n if (topicMatch) {\n authorityScore += 3;\n authoritySignals.push('author knowsAbout aligns with content topic');\n } else {\n authorityScore += 1;\n gaps.push(`author knowsAbout (${author.knowsAbout.join(', ')}) doesn't match content category \"${contentCategory}\"`);\n }\n } else {\n gaps.push('no knowsAbout topics defined');\n }\n\n // Check if credentials are relevant to the content category\n if (author.credentials && author.credentials.length > 0) {\n const relevantCreds = author.credentials.filter(cred => {\n const credLower = cred.name.toLowerCase();\n for (const [keyword, categories] of Object.entries(CREDENTIAL_RELEVANCE)) {\n if (credLower.includes(keyword) && categories.some(c => category.includes(c))) {\n return true;\n }\n }\n return false;\n });\n\n if (relevantCreds.length > 0) {\n authorityScore += 3;\n authoritySignals.push(`relevant credentials: ${relevantCreds.map(c => c.name).join(', ')}`);\n } else {\n authorityScore += 1;\n gaps.push('credentials not directly related to content topic');\n }\n } else {\n if (isYMYL) {\n gaps.push('YMYL content requires verifiable credentials');\n } else {\n gaps.push('no credentials provided');\n }\n }\n\n // Check job title relevance\n if (author.jobTitle) {\n const titleLower = author.jobTitle.toLowerCase();\n const titleRelevant = Object.entries(CREDENTIAL_RELEVANCE).some(([keyword, categories]) =>\n titleLower.includes(keyword) && categories.some(c => category.includes(c))\n );\n if (titleRelevant) {\n authorityScore += 2;\n authoritySignals.push(`job title \"${author.jobTitle}\" is relevant`);\n }\n }\n\n // Check years of experience\n if (author.yearsOfExperience && author.yearsOfExperience >= 5) {\n authorityScore += 1;\n authoritySignals.push(`${author.yearsOfExperience}+ years of experience`);\n }\n\n // YMYL amplifier — stricter scoring for YMYL content\n const ymylNote = isYMYL\n ? ' This is YMYL content — Google applies stricter E-E-A-T evaluation.'\n : '';\n\n if (authorityScore >= 6) {\n return {\n id: 'eeat-topical-authority',\n title: 'Topical authority',\n description: `Strong topical authority: ${authoritySignals.join('; ')}.${ymylNote}`,\n status: 'good',\n score: 5,\n maxScore: 8,\n };\n }\n\n if (authorityScore >= 3) {\n return {\n id: 'eeat-topical-authority',\n title: 'Topical authority',\n description: `Moderate topical authority (${authoritySignals.join('; ')}). Gaps: ${gaps.join('; ')}.${ymylNote}`,\n status: 'ok',\n score: 3,\n maxScore: 8,\n };\n }\n\n return {\n id: 'eeat-topical-authority',\n title: 'Topical authority',\n description: `Weak topical authority for \"${contentCategory}\" content. ${gaps.join('; ')}. Ensure the author has demonstrable expertise in this topic area.${ymylNote}`,\n status: 'poor',\n score: 1,\n maxScore: 8,\n };\n}\n","// @power-seo/content-analysis — E-E-A-T: Technical Vocabulary Depth\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords, countSyllables } from '@power-seo/core';\n\n// Patterns that indicate technical terms are being explained (good for expertise)\nconst EXPLANATION_PATTERNS: RegExp[] = [\n /\\bwhich\\s+means\\b/gi,\n /\\bin\\s+other\\s+words\\b/gi,\n /\\balso\\s+known\\s+as\\b/gi,\n /\\breferred\\s+to\\s+as\\b/gi,\n /\\bdefined\\s+as\\b/gi,\n /\\bi\\.e\\.\\b/gi,\n /\\be\\.g\\.\\b/gi,\n /\\bfor\\s+example\\b/gi,\n /\\bsimply\\s+put\\b/gi,\n /\\bin\\s+simple\\s+terms\\b/gi,\n /\\bthis\\s+means\\b/gi,\n /\\bthat\\s+is\\b/gi,\n /\\b\\(\\s*[A-Z][a-z]+/g, // Parenthetical definitions like \"(Hypertext Transfer Protocol)\"\n];\n\n// Unnecessarily complex words with simpler alternatives\nconst COMPLEX_SYNONYMS: Array<{ complex: RegExp; simple: string }> = [\n { complex: /\\butilize\\b/gi, simple: 'use' },\n { complex: /\\bapproximately\\b/gi, simple: 'about' },\n { complex: /\\bsubsequently\\b/gi, simple: 'then/later' },\n { complex: /\\bcommence\\b/gi, simple: 'start/begin' },\n { complex: /\\bterminate\\b/gi, simple: 'end/stop' },\n { complex: /\\bfacilitate\\b/gi, simple: 'help/enable' },\n { complex: /\\bdemonstrate\\b/gi, simple: 'show' },\n { complex: /\\bleverage\\b/gi, simple: 'use' },\n { complex: /\\boptimize\\b/gi, simple: 'improve' },\n { complex: /\\bimplementation\\b/gi, simple: 'setup' },\n { complex: /\\bfunctionality\\b/gi, simple: 'feature' },\n { complex: /\\bmodification\\b/gi, simple: 'change' },\n { complex: /\\bconfiguration\\b/gi, simple: 'setup/settings' },\n { complex: /\\bascertain\\b/gi, simple: 'find out' },\n { complex: /\\bnumerous\\b/gi, simple: 'many' },\n { complex: /\\bsufficient\\b/gi, simple: 'enough' },\n { complex: /\\bnecessitate\\b/gi, simple: 'need/require' },\n { complex: /\\bprocure\\b/gi, simple: 'get/obtain' },\n { complex: /\\bdiminish\\b/gi, simple: 'reduce' },\n { complex: /\\bameliorat\\w+\\b/gi, simple: 'improve' },\n { complex: /\\bexpedit\\w+\\b/gi, simple: 'speed up' },\n { complex: /\\belucidat\\w+\\b/gi, simple: 'explain/clarify' },\n { complex: /\\bperpetuat\\w+\\b/gi, simple: 'continue' },\n { complex: /\\bexacerbat\\w+\\b/gi, simple: 'worsen' },\n { complex: /\\bamalgamat\\w+\\b/gi, simple: 'combine/merge' },\n];\n\n// Common technical/domain words (3+ syllables that are NOT unnecessarily complex)\nconst VALID_TECHNICAL_WORDS: RegExp[] = [\n /\\b(algorithm|database|framework|component|interface|architecture|infrastructure|deployment|repository|middleware|authentication|authorization|encryption|protocol|bandwidth|latency|throughput|scalability|microservic\\w+|containeriz\\w+|orchestrat\\w+|kubernetes|javascript|typescript|python|machine\\s+learning|artificial\\s+intelligence|neural\\s+network|blockchain|cryptocurrency|responsive|analytics|automation|integration|documentation|performance|accessibility|optimization|specification)\\b/gi,\n];\n\nexport function checkTechnicalVocabulary(input: ContentAnalysisInput): AnalysisResult {\n const plainText = stripHtml(input.content || '');\n const words = getWords(plainText);\n const wordCount = words.length;\n\n if (wordCount < 50) {\n return {\n id: 'eeat-technical-vocabulary',\n title: 'Technical vocabulary',\n description: 'Content is too short to analyze technical vocabulary.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n // Count complex words (3+ syllables)\n let complexWordCount = 0;\n const complexWords: string[] = [];\n for (const word of words) {\n if (countSyllables(word) >= 3 && word.length >= 6) {\n complexWordCount++;\n const lower = word.toLowerCase();\n if (!complexWords.includes(lower) && complexWords.length < 15) {\n complexWords.push(lower);\n }\n }\n }\n const complexRatio = complexWordCount / wordCount;\n\n // Count explanation patterns\n let explanationCount = 0;\n for (const pattern of EXPLANATION_PATTERNS) {\n const matches = plainText.match(pattern);\n if (matches) explanationCount += matches.length;\n }\n\n // Count unnecessarily complex synonyms\n let unnecessaryComplexCount = 0;\n const unnecessaryExamples: string[] = [];\n for (const { complex, simple } of COMPLEX_SYNONYMS) {\n const matches = plainText.match(complex);\n if (matches) {\n unnecessaryComplexCount += matches.length;\n if (unnecessaryExamples.length < 3) {\n unnecessaryExamples.push(`\"${matches[0]}\" → \"${simple}\"`);\n }\n }\n }\n\n // Count valid technical terms\n let technicalTermCount = 0;\n for (const pattern of VALID_TECHNICAL_WORDS) {\n const matches = plainText.match(pattern);\n if (matches) technicalTermCount += matches.length;\n }\n\n // Evaluate: Good = uses technical terms AND explains them, AND avoids unnecessary complexity\n const hasGoodTechnicalDepth = technicalTermCount >= 3 || complexRatio >= 0.08;\n const explainsTerms = explanationCount >= 2;\n const lowUnnecessary = unnecessaryComplexCount <= 2;\n\n if (hasGoodTechnicalDepth && explainsTerms && lowUnnecessary) {\n return {\n id: 'eeat-technical-vocabulary',\n title: 'Technical vocabulary',\n description: `Good technical depth with ${technicalTermCount} domain-specific terms and ${explanationCount} explanatory phrases. Complex concepts are properly explained for the reader.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (hasGoodTechnicalDepth && (explainsTerms || lowUnnecessary)) {\n const suggestions: string[] = [];\n if (!explainsTerms) suggestions.push('explain technical terms for wider audience');\n if (!lowUnnecessary) suggestions.push(`simplify: ${unnecessaryExamples.join(', ')}`);\n return {\n id: 'eeat-technical-vocabulary',\n title: 'Technical vocabulary',\n description: `Moderate technical vocabulary. ${suggestions.join('; ')}. Good expertise signals come from using domain terms AND explaining them clearly.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n const suggestions: string[] = [];\n if (technicalTermCount < 3) suggestions.push('add more domain-specific terminology');\n if (explanationCount < 2) suggestions.push('explain technical concepts with \"which means\", \"in other words\"');\n if (unnecessaryComplexCount > 2) suggestions.push(`simplify: ${unnecessaryExamples.join(', ')}`);\n\n return {\n id: 'eeat-technical-vocabulary',\n title: 'Technical vocabulary',\n description: `Weak technical vocabulary depth. ${suggestions.join('; ')}. Expert content uses precise domain language while remaining accessible.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — E-E-A-T: Expert Hedging & Precision\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\n\n// Good epistemic language — calibrated confidence (experts use these)\nconst HEDGING_PATTERNS: RegExp[] = [\n /\\bresearch\\s+(suggests?|indicates?|shows?)\\b/gi,\n /\\bevidence\\s+(suggests?|indicates?|shows?|supports?)\\b/gi,\n /\\bstudies\\s+(suggest|indicate|show|have\\s+found)\\b/gi,\n /\\baccording\\s+to\\s+(research|studies|data|experts?)\\b/gi,\n /\\b(may|might|could)\\s+(help|improve|reduce|increase|affect|cause|lead\\s+to)\\b/gi,\n /\\btends?\\s+to\\b/gi,\n /\\bgenerally\\s+(speaking|considered)\\b/gi,\n /\\bin\\s+(most|many|some)\\s+cases\\b/gi,\n /\\btypically\\b/gi,\n /\\bit\\s+appears?\\s+that\\b/gi,\n /\\bit\\s+seems?\\s+(that|like)\\b/gi,\n /\\bcurrent\\s+(evidence|research|data)\\b/gi,\n /\\bas\\s+of\\s+(this\\s+writing|\\d{4})\\b/gi,\n /\\bbased\\s+on\\s+(available|current|existing)\\s+(data|evidence|research)\\b/gi,\n /\\bto\\s+the\\s+best\\s+of\\s+(our|my)\\s+knowledge\\b/gi,\n /\\bwhile\\s+more\\s+research\\s+is\\s+needed\\b/gi,\n /\\bfurther\\s+(research|study|investigation)\\s+is\\s+needed\\b/gi,\n /\\blimitations?\\s+(include|of\\s+this|to\\s+consider)\\b/gi,\n /\\bit['']?s?\\s+worth\\s+noting\\s+that\\b/gi,\n /\\bhowever,?\\s+it['']?s?\\s+important\\s+to\\b/gi,\n /\\bthat\\s+said\\b/gi,\n /\\bon\\s+the\\s+other\\s+hand\\b/gi,\n /\\bwith\\s+the\\s+caveat\\s+that\\b/gi,\n];\n\n// Bad absolute claims — unsubstantiated certainty (non-experts overuse these)\nconst ABSOLUTE_PATTERNS: RegExp[] = [\n /\\bguaranteed\\s+(to|results?|success)\\b/gi,\n /\\b100\\s*%\\s+(proven|guaranteed|effective|safe|sure|certain)\\b/gi,\n /\\bdefinitely\\s+(works?|will|the\\s+best)\\b/gi,\n /\\balways\\s+(works?|will|leads?\\s+to|results?\\s+in)\\b/gi,\n /\\bnever\\s+(fails?|wrong|a\\s+bad)\\b/gi,\n /\\bthe\\s+only\\s+(way|method|solution|answer)\\b/gi,\n /\\babsolutely\\s+(the\\s+best|essential|necessary|certain)\\b/gi,\n /\\bwithout\\s+a\\s+doubt\\b/gi,\n /\\bundeniably\\b/gi,\n /\\bunquestionably\\b/gi,\n /\\birrefutably\\b/gi,\n /\\bscientifically\\s+proven\\b/gi,\n /\\bproven\\s+to\\s+(work|cure|fix|solve)\\b/gi,\n /\\bcure[\\s-]all\\b/gi,\n /\\bmiracle\\s+(cure|solution|product)\\b/gi,\n /\\binstant\\s+(results?|cure|fix|solution)\\b/gi,\n /\\bno\\s+risk\\b/gi,\n /\\brisk[\\s-]free\\b/gi,\n /\\bfoolproof\\b/gi,\n /\\bsecret\\s+(formula|method|trick|hack)\\s+that\\b/gi,\n /\\beveryone\\s+(should|must|needs?\\s+to)\\b/gi,\n /\\byou\\s+must\\s+(buy|try|use|get)\\b/gi,\n /\\bact\\s+now\\b/gi,\n /\\blimited\\s+time\\s+only\\b/gi,\n /\\bbefore\\s+it['']?s?\\s+too\\s+late\\b/gi,\n];\n\nexport function checkExpertHedging(input: ContentAnalysisInput): AnalysisResult {\n const plainText = stripHtml(input.content || '');\n const words = getWords(plainText);\n const wordCount = words.length;\n\n if (wordCount < 50) {\n return {\n id: 'eeat-expert-hedging',\n title: 'Expert precision',\n description: 'Content is too short to analyze claim precision.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n let hedgingCount = 0;\n for (const pattern of HEDGING_PATTERNS) {\n const matches = plainText.match(pattern);\n if (matches) hedgingCount += matches.length;\n }\n\n let absoluteCount = 0;\n const absoluteExamples: string[] = [];\n for (const pattern of ABSOLUTE_PATTERNS) {\n const matches = plainText.match(pattern);\n if (matches) {\n absoluteCount += matches.length;\n for (const m of matches) {\n if (absoluteExamples.length < 3) {\n absoluteExamples.push(`\"${m.trim()}\"`);\n }\n }\n }\n }\n\n // Good: has hedging language AND few/no absolute claims\n if (hedgingCount >= 3 && absoluteCount === 0) {\n return {\n id: 'eeat-expert-hedging',\n title: 'Expert precision',\n description: `Excellent claim precision with ${hedgingCount} calibrated statements (\"research suggests\", \"evidence indicates\"). No unsubstantiated absolute claims detected. This signals expert-level communication.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (hedgingCount >= 2 && absoluteCount <= 1) {\n return {\n id: 'eeat-expert-hedging',\n title: 'Expert precision',\n description: `Good claim precision with ${hedgingCount} hedged statements.${absoluteCount > 0 ? ` Found ${absoluteCount} absolute claim: ${absoluteExamples.join(', ')} — consider softening.` : ''} Experts use calibrated confidence rather than absolute certainty.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (hedgingCount >= 1 && absoluteCount <= 3) {\n const suggestions: string[] = [];\n if (absoluteCount > 0) suggestions.push(`soften ${absoluteCount} absolute claims: ${absoluteExamples.join(', ')}`);\n suggestions.push('add hedging phrases: \"research suggests\", \"in most cases\", \"evidence indicates\"');\n return {\n id: 'eeat-expert-hedging',\n title: 'Expert precision',\n description: `Moderate claim precision. ${suggestions.join('; ')}. Calibrated language builds credibility.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n if (absoluteCount > 3) {\n return {\n id: 'eeat-expert-hedging',\n title: 'Expert precision',\n description: `${absoluteCount} unsubstantiated absolute claims detected (${absoluteExamples.join(', ')}). This undermines credibility. Replace with evidence-backed, calibrated language: \"research suggests\", \"studies indicate\", \"in most cases\".`,\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n\n return {\n id: 'eeat-expert-hedging',\n title: 'Expert precision',\n description: 'No hedging or precision language detected. Experts qualify claims with \"research suggests\", \"evidence indicates\", \"in most cases\". Add calibrated confidence language to demonstrate expertise.',\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — E-E-A-T: Methodology & Process Transparency\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\n\nconst METHODOLOGY_PATTERNS: RegExp[] = [\n // Testing methodology\n /\\bhow\\s+we\\s+tested\\b/gi,\n /\\bhow\\s+i\\s+tested\\b/gi,\n /\\b(our|my)\\s+testing\\s+(process|methodology|approach|criteria)\\b/gi,\n /\\btest(ing)?\\s+methodology\\b/gi,\n /\\btest(ing)?\\s+environment\\b/gi,\n /\\btest(ing)?\\s+conditions?\\b/gi,\n /\\btest(ing)?\\s+setup\\b/gi,\n /\\bwe\\s+tested\\s+(by|using|with|on|across)\\b/gi,\n\n // Evaluation criteria\n /\\b(our|my|the)\\s+evaluation\\s+criteria\\b/gi,\n /\\b(our|my|the)\\s+selection\\s+(criteria|process)\\b/gi,\n /\\b(our|my|the)\\s+review\\s+(process|criteria|methodology)\\b/gi,\n /\\b(our|my|the)\\s+assessment\\s+(criteria|framework|process)\\b/gi,\n /\\bscoring\\s+(system|methodology|criteria|rubric)\\b/gi,\n /\\bgrading\\s+(system|criteria|scale)\\b/gi,\n /\\brated\\s+(on|based\\s+on|according\\s+to)\\b/gi,\n /\\bwe\\s+(evaluated|assessed|rated|scored|ranked|compared)\\b/gi,\n\n // Research process\n /\\b(our|my|the)\\s+(research\\s+)?(process|approach|framework|method)\\s+(involved|included|consisted|was)\\b/gi,\n /\\bdata\\s+(collection|gathering|analysis)\\s+(method|process|approach)\\b/gi,\n /\\bsample\\s+(size|group|population)\\b/gi,\n /\\bcontrol\\s+(group|variable|condition)\\b/gi,\n /\\bvariable\\w*\\s+(controlled|measured|tested)\\b/gi,\n\n // Scope and limitations\n /\\bscope\\s+of\\s+(this|our|the)\\b/gi,\n /\\blimitations?\\s+(of\\s+this|include|to\\s+note|to\\s+consider)\\b/gi,\n /\\bdisclaimer\\b/gi,\n /\\bit['']?s?\\s+(important|worth)\\s+(to\\s+)?not(e|ing)\\s+that\\b/gi,\n /\\bwe\\s+did\\s+not\\s+(test|evaluate|include|consider)\\b/gi,\n /\\bthis\\s+(review|analysis|study)\\s+(does\\s+not|doesn['']t)\\s+(cover|include)\\b/gi,\n /\\bout\\s+of\\s+scope\\b/gi,\n\n // Assumptions\n /\\b(our|the)\\s+assumption\\w*\\b/gi,\n /\\bwe\\s+assum(e|ed|ing)\\b/gi,\n /\\bfor\\s+the\\s+purposes?\\s+of\\s+this\\b/gi,\n\n // Reproducibility\n /\\byou\\s+can\\s+replicate\\b/gi,\n /\\breproducib\\w+\\b/gi,\n /\\bfollow\\s+(these|the\\s+same)\\s+steps\\b/gi,\n /\\brepeat\\s+(this|the)\\s+(experiment|test|process)\\b/gi,\n\n // Tools and environment\n /\\btools?\\s+(used|we\\s+used|i\\s+used)\\b/gi,\n /\\b(software|hardware|equipment)\\s+used\\b/gi,\n /\\b(tested|measured|analyzed)\\s+(using|with|on)\\b/gi,\n /\\benvironment\\s+(details|specs|specifications)\\b/gi,\n];\n\nexport function checkMethodologyTransparency(input: ContentAnalysisInput): AnalysisResult {\n const plainText = stripHtml(input.content || '');\n const words = getWords(plainText);\n const wordCount = words.length;\n\n if (wordCount < 100) {\n return {\n id: 'eeat-methodology-transparency',\n title: 'Methodology transparency',\n description: 'Content is too short to assess methodology transparency.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n let totalMatches = 0;\n const categories: Set<string> = new Set();\n\n for (const pattern of METHODOLOGY_PATTERNS) {\n const matches = plainText.match(pattern);\n if (matches) {\n totalMatches += matches.length;\n const src = pattern.source.toLowerCase();\n if (src.includes('test')) categories.add('testing process');\n else if (src.includes('evaluat') || src.includes('criteria') || src.includes('scor')) categories.add('evaluation criteria');\n else if (src.includes('sample') || src.includes('data') || src.includes('control')) categories.add('research process');\n else if (src.includes('scope') || src.includes('limitation') || src.includes('disclaimer')) categories.add('scope & limitations');\n else if (src.includes('assum')) categories.add('assumptions');\n else if (src.includes('replic') || src.includes('reproduc') || src.includes('repeat')) categories.add('reproducibility');\n else if (src.includes('tool') || src.includes('software') || src.includes('environment')) categories.add('tools & environment');\n }\n }\n\n const categoryList = Array.from(categories);\n\n if (totalMatches >= 5 && categoryList.length >= 3) {\n return {\n id: 'eeat-methodology-transparency',\n title: 'Methodology transparency',\n description: `Excellent methodology transparency across ${categoryList.length} areas: ${categoryList.join(', ')}. Transparent processes build reader trust and demonstrate expertise.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (totalMatches >= 2 && categoryList.length >= 1) {\n const missing: string[] = [];\n if (!categories.has('testing process') && !categories.has('evaluation criteria')) missing.push('evaluation criteria');\n if (!categories.has('scope & limitations')) missing.push('scope & limitations');\n if (!categories.has('tools & environment')) missing.push('tools used');\n return {\n id: 'eeat-methodology-transparency',\n title: 'Methodology transparency',\n description: `Partial methodology transparency (${categoryList.join(', ')}). Consider adding: ${missing.slice(0, 2).join(', ')}. Transparent methodology strengthens credibility.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'eeat-methodology-transparency',\n title: 'Methodology transparency',\n description: 'No methodology transparency detected. Add: how you tested/evaluated, tools used, evaluation criteria, scope & limitations, and assumptions. Transparent processes are a strong expertise signal.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — E-E-A-T: Author Cross-Platform Presence\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\n// Platform categories for diversity scoring\nconst PLATFORM_CATEGORIES: Record<string, string> = {\n linkedin: 'professional',\n twitter: 'social',\n 'x.com': 'social',\n github: 'technical',\n gitlab: 'technical',\n bitbucket: 'technical',\n stackoverflow: 'technical',\n medium: 'publishing',\n substack: 'publishing',\n 'dev.to': 'publishing',\n hashnode: 'publishing',\n wordpress: 'publishing',\n youtube: 'video',\n vimeo: 'video',\n twitch: 'video',\n facebook: 'social',\n instagram: 'social',\n mastodon: 'social',\n threads: 'social',\n bluesky: 'social',\n researchgate: 'academic',\n 'scholar.google': 'academic',\n orcid: 'academic',\n academia: 'academic',\n dribbble: 'portfolio',\n behance: 'portfolio',\n kaggle: 'technical',\n 'huggingface.co': 'technical',\n};\n\nfunction detectPlatform(url: string): { platform: string; category: string } | null {\n const urlLower = url.toLowerCase();\n for (const [platform, category] of Object.entries(PLATFORM_CATEGORIES)) {\n if (urlLower.includes(platform)) {\n return { platform, category };\n }\n }\n return null;\n}\n\nexport function checkAuthorSocial(input: ContentAnalysisInput): AnalysisResult {\n const { author } = input;\n\n if (!author) {\n return {\n id: 'eeat-author-social',\n title: 'Author social presence',\n description: 'No author information provided. Add author social profiles to demonstrate real identity and cross-platform authority.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n\n const profiles = author.socialProfiles || [];\n\n if (profiles.length === 0) {\n return {\n id: 'eeat-author-social',\n title: 'Author social presence',\n description: 'No social profiles linked. Add LinkedIn, Twitter/X, GitHub, or other professional profiles. Social presence signals that the author is a real, identifiable person (sameAs schema property).',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n\n // Analyze platform diversity\n const categories = new Set<string>();\n const platforms: string[] = [];\n\n for (const profile of profiles) {\n const detected = detectPlatform(profile.url);\n if (detected) {\n categories.add(detected.category);\n platforms.push(detected.platform);\n } else {\n platforms.push(profile.platform || 'other');\n categories.add('other');\n }\n }\n\n const hasLinkedIn = platforms.some(p => p === 'linkedin');\n const hasTechnical = categories.has('technical');\n const hasPublishing = categories.has('publishing');\n const hasAcademic = categories.has('academic');\n\n const diversityScore = categories.size;\n\n if (profiles.length >= 3 && diversityScore >= 3) {\n const details: string[] = [];\n if (hasLinkedIn) details.push('LinkedIn (professional identity)');\n if (hasTechnical) details.push('technical platforms');\n if (hasPublishing) details.push('publishing platforms');\n if (hasAcademic) details.push('academic profiles');\n return {\n id: 'eeat-author-social',\n title: 'Author social presence',\n description: `Strong cross-platform presence with ${profiles.length} profiles across ${diversityScore} categories: ${details.join(', ')}. Diverse presence strengthens author identity verification.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (profiles.length >= 2 || (profiles.length >= 1 && hasLinkedIn)) {\n const suggestions: string[] = [];\n if (!hasLinkedIn) suggestions.push('add LinkedIn for professional credibility');\n if (diversityScore < 2) suggestions.push('diversify across professional, technical, and publishing platforms');\n if (profiles.length < 3) suggestions.push('add more profiles for stronger identity signals');\n return {\n id: 'eeat-author-social',\n title: 'Author social presence',\n description: `${profiles.length} social profile${profiles.length > 1 ? 's' : ''} linked (${platforms.join(', ')}). ${suggestions.join('; ')}.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'eeat-author-social',\n title: 'Author social presence',\n description: `Only ${profiles.length} social profile linked (${platforms.join(', ')}). Add at least 3 profiles across different categories (LinkedIn, GitHub, publishing platforms) for stronger author identity verification.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — E-E-A-T: Organization & Affiliation\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\nexport function checkOrganization(input: ContentAnalysisInput): AnalysisResult {\n const { author } = input;\n\n if (!author) {\n return {\n id: 'eeat-organization',\n title: 'Organization affiliation',\n description: 'No author information provided. Add organization/affiliation data to strengthen authoritativeness signals.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n\n let orgScore = 0;\n const signals: string[] = [];\n const gaps: string[] = [];\n\n // Check worksFor organization\n if (author.worksFor) {\n if (author.worksFor.name) {\n orgScore += 2;\n signals.push(`works for \"${author.worksFor.name}\"`);\n }\n if (author.worksFor.url) {\n orgScore += 1;\n signals.push('organization URL provided');\n }\n if (author.worksFor.logo) {\n orgScore += 1;\n signals.push('organization logo provided');\n }\n } else {\n gaps.push('no worksFor organization');\n }\n\n // Check job title (implies organizational role)\n if (author.jobTitle && author.jobTitle.trim()) {\n orgScore += 1;\n signals.push(`role: ${author.jobTitle}`);\n } else {\n gaps.push('no job title');\n }\n\n // Check professional credentials (imply institutional backing)\n if (author.credentials && author.credentials.length > 0) {\n const withIssuers = author.credentials.filter(c => c.issuer);\n if (withIssuers.length > 0) {\n orgScore += 2;\n signals.push(`credentials from: ${withIssuers.map(c => c.issuer).join(', ')}`);\n } else {\n orgScore += 1;\n signals.push(`${author.credentials.length} credential(s) without issuer details`);\n gaps.push('add issuing organizations to credentials');\n }\n }\n\n // Check education (institutional affiliation)\n if (author.education && author.education.length > 0) {\n orgScore += 1;\n signals.push(`education: ${author.education.map(e => e.institution).join(', ')}`);\n }\n\n if (orgScore >= 5) {\n return {\n id: 'eeat-organization',\n title: 'Organization affiliation',\n description: `Strong organizational backing: ${signals.join('; ')}. Institutional affiliations strengthen authoritativeness.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (orgScore >= 2) {\n return {\n id: 'eeat-organization',\n title: 'Organization affiliation',\n description: `Partial organization data (${signals.join('; ')}). Missing: ${gaps.join('; ')}. Add complete worksFor schema (name, url, logo) and credential issuers.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'eeat-organization',\n title: 'Organization affiliation',\n description: `Weak organizational signals. ${gaps.join('; ')}. Add worksFor (organization name, URL, logo), job title, and credentialing institutions to demonstrate professional backing.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — E-E-A-T: Published Works & Credentials\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\nexport function checkPublishedWorks(input: ContentAnalysisInput): AnalysisResult {\n const { author } = input;\n\n if (!author) {\n return {\n id: 'eeat-published-works',\n title: 'Published works & credentials',\n description: 'No author information provided. Add publications, certifications, and awards to demonstrate authority.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n\n let score = 0;\n const signals: string[] = [];\n const gaps: string[] = [];\n\n // Publications\n if (author.publications && author.publications.length > 0) {\n const withUrls = author.publications.filter(p => p.url);\n score += Math.min(3, author.publications.length);\n signals.push(`${author.publications.length} publication${author.publications.length > 1 ? 's' : ''}${withUrls.length > 0 ? ` (${withUrls.length} with URLs)` : ''}`);\n if (withUrls.length < author.publications.length) {\n gaps.push('add URLs to all publications for verifiability');\n }\n } else {\n gaps.push('no publications listed');\n }\n\n // Credentials/Certifications\n if (author.credentials && author.credentials.length > 0) {\n score += Math.min(2, author.credentials.length);\n const credNames = author.credentials.map(c => c.name);\n signals.push(`credentials: ${credNames.join(', ')}`);\n\n // Check for credential quality (has issuer and date)\n const completeCredentials = author.credentials.filter(c => c.issuer && c.dateObtained);\n if (completeCredentials.length < author.credentials.length) {\n gaps.push('add issuer and date to all credentials for schema completeness');\n }\n } else {\n gaps.push('no professional certifications');\n }\n\n // Awards\n if (author.awards && author.awards.length > 0) {\n score += Math.min(2, author.awards.length);\n signals.push(`${author.awards.length} award${author.awards.length > 1 ? 's' : ''}: ${author.awards.slice(0, 3).join(', ')}`);\n }\n\n // Years of experience\n if (author.yearsOfExperience) {\n if (author.yearsOfExperience >= 10) {\n score += 2;\n signals.push(`${author.yearsOfExperience}+ years of experience`);\n } else if (author.yearsOfExperience >= 5) {\n score += 1;\n signals.push(`${author.yearsOfExperience} years of experience`);\n }\n }\n\n if (score >= 5) {\n return {\n id: 'eeat-published-works',\n title: 'Published works & credentials',\n description: `Strong authority signals: ${signals.join('; ')}. Published works and credentials demonstrate recognized expertise.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (score >= 2) {\n return {\n id: 'eeat-published-works',\n title: 'Published works & credentials',\n description: `Moderate authority (${signals.join('; ')}). To strengthen: ${gaps.slice(0, 2).join('; ')}.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'eeat-published-works',\n title: 'Published works & credentials',\n description: `Weak authority signals. ${gaps.join('; ')}. Add publications (articles, papers, books), professional certifications with issuers, and any industry awards or recognition.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — E-E-A-T: Expert Sourcing & Quotes\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\n\n// Expert attribution patterns\nconst EXPERT_QUOTE_PATTERNS: RegExp[] = [\n // Named expert citations\n /\\baccording\\s+to\\s+(?:Dr\\.?|Prof\\.?|Professor)\\s+[A-Z]/gi,\n /\\baccording\\s+to\\s+[A-Z][a-z]+\\s+[A-Z][a-z]+/g,\n /\\b(?:Dr\\.?|Prof\\.?|Professor)\\s+[A-Z][a-z]+\\s+(says?|said|explains?|explained|notes?|noted|suggests?|argues?|stated|believes?|recommends?|observes?|points?\\s+out)\\b/g,\n /\\b[A-Z][a-z]+\\s+[A-Z][a-z]+,?\\s+(?:a|an)\\s+(?:professor|researcher|scientist|expert|analyst|specialist|consultant|advisor|doctor|physician|engineer|author|founder|CEO|CTO|director)\\b/g,\n\n // Quote blocks\n /\\bas\\s+[A-Z][a-z]+\\s+(?:[A-Z][a-z]+\\s+)?(?:explains?|puts?\\s+it|notes?|says?|wrote|writes?|stated)\\b/g,\n /\\bin\\s+the\\s+words\\s+of\\b/gi,\n /\\b[A-Z][a-z]+\\s+(?:[A-Z][a-z]+\\s+)?told\\s+(?:us|me|the)\\b/g,\n\n // Interview/contribution markers\n /\\bwe\\s+(?:spoke|talked)\\s+(?:with|to)\\b/gi,\n /\\bin\\s+(?:an|our)\\s+interview\\s+with\\b/gi,\n /\\b[A-Z][a-z]+\\s+shared\\s+(?:that|their|his|her)\\b/g,\n /\\bcontribut(?:ed|or|ing)\\s+(?:expert|author|writer|analyst)\\b/gi,\n /\\bguest\\s+(?:expert|contributor|author|writer)\\b/gi,\n\n // Expert consensus\n /\\bexperts?\\s+(?:agree|recommend|suggest|advise|say|warn|note|point\\s+out)\\b/gi,\n /\\b(?:industry|leading|top|renowned)\\s+experts?\\b/gi,\n /\\baccording\\s+to\\s+(?:industry\\s+)?experts?\\b/gi,\n /\\b(?:medical|financial|legal|technical)\\s+(?:expert|professional|specialist)\\b/gi,\n];\n\n// HTML quote elements\nconst BLOCKQUOTE_PATTERN = /<blockquote\\b[^>]*>[\\s\\S]*?<\\/blockquote>/gi;\nconst CITE_PATTERN = /<cite\\b[^>]*>[^<]+<\\/cite>/gi;\nconst Q_PATTERN = /<q\\b[^>]*>[^<]+<\\/q>/gi;\n\nexport function checkExpertSourcing(input: ContentAnalysisInput): AnalysisResult {\n const content = input.content || '';\n const plainText = stripHtml(content);\n const words = getWords(plainText);\n const wordCount = words.length;\n\n if (wordCount < 100) {\n return {\n id: 'eeat-expert-sourcing',\n title: 'Expert sourcing',\n description: 'Content is too short to assess expert sourcing.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n let expertMentions = 0;\n const sourceTypes: Set<string> = new Set();\n\n // Check text patterns\n for (const pattern of EXPERT_QUOTE_PATTERNS) {\n const matches = plainText.match(pattern);\n if (matches) {\n expertMentions += matches.length;\n const src = pattern.source.toLowerCase();\n if (src.includes('interview') || src.includes('spoke') || src.includes('told')) {\n sourceTypes.add('interviews');\n } else if (src.includes('contribut') || src.includes('guest')) {\n sourceTypes.add('expert contributors');\n } else if (src.includes('according') || src.includes('says') || src.includes('explains')) {\n sourceTypes.add('expert citations');\n } else if (src.includes('experts\\\\s+')) {\n sourceTypes.add('expert consensus');\n }\n }\n }\n\n // Check HTML quote elements\n const blockquotes = content.match(BLOCKQUOTE_PATTERN) || [];\n const cites = content.match(CITE_PATTERN) || [];\n const quotes = content.match(Q_PATTERN) || [];\n\n if (blockquotes.length > 0) {\n expertMentions += blockquotes.length;\n sourceTypes.add('blockquotes');\n }\n if (cites.length > 0) {\n expertMentions += cites.length;\n sourceTypes.add('cited sources');\n }\n if (quotes.length > 0) {\n expertMentions += quotes.length;\n }\n\n const types = Array.from(sourceTypes);\n\n if (expertMentions >= 3 && types.length >= 2) {\n return {\n id: 'eeat-expert-sourcing',\n title: 'Expert sourcing',\n description: `Strong expert sourcing with ${expertMentions} references across ${types.join(', ')}. Expert quotes and attributed statements strengthen content authority.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (expertMentions >= 1) {\n const suggestions: string[] = [];\n if (blockquotes.length === 0) suggestions.push('use <blockquote> with <cite> for attributed quotes');\n if (types.length < 2) suggestions.push('diversify sources: add interviews, expert quotes, or contributor insights');\n if (expertMentions < 3) suggestions.push('cite at least 3 expert sources');\n return {\n id: 'eeat-expert-sourcing',\n title: 'Expert sourcing',\n description: `Some expert sourcing found (${expertMentions} reference${expertMentions > 1 ? 's' : ''}: ${types.join(', ')}). ${suggestions.join('; ')}.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'eeat-expert-sourcing',\n title: 'Expert sourcing',\n description: 'No expert sourcing detected. Add expert quotes (\"According to Dr. Smith...\"), attributed insights, interview data, or expert contributor sections. Use <blockquote> with <cite> for proper attribution.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — E-E-A-T: Editorial Review Indicators\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml } from '@power-seo/core';\n\n// Editorial review patterns in content text\nconst EDITORIAL_PATTERNS: RegExp[] = [\n /\\b(?:reviewed|fact[\\s-]?checked|verified|edited|proofread)\\s+by\\b/gi,\n /\\bmedically\\s+reviewed\\s+by\\b/gi,\n /\\bscientifically\\s+reviewed\\b/gi,\n /\\blegally\\s+reviewed\\b/gi,\n /\\bfinancially\\s+reviewed\\b/gi,\n /\\btechnically\\s+reviewed\\b/gi,\n /\\bpeer[\\s-]?reviewed\\b/gi,\n /\\beditor(?:ial)?\\s*:\\s*[A-Z]/g,\n /\\breviewer\\s*:\\s*[A-Z]/g,\n /\\bfact[\\s-]?checker\\s*:\\s*[A-Z]/g,\n /\\beditorial\\s+(?:team|board|review|oversight|standards?|guidelines?|policy|process)\\b/gi,\n /\\bcontent\\s+review\\s+(?:process|policy|team)\\b/gi,\n /\\bquality\\s+(?:assurance|review|control)\\b/gi,\n /\\blast\\s+(?:reviewed|updated|verified|checked)\\s+(?:on\\s+)?(?:\\w+\\s+\\d{1,2},?\\s+\\d{4}|\\d{4}[-/]\\d{2}[-/]\\d{2})\\b/gi,\n /\\breview\\s+date\\b/gi,\n];\n\nexport function checkEditorialReview(input: ContentAnalysisInput): AnalysisResult {\n const { editorialReviewer, content } = input;\n const plainText = stripHtml(content || '');\n\n let score = 0;\n const signals: string[] = [];\n const gaps: string[] = [];\n\n // Check structured editorial reviewer data\n if (editorialReviewer) {\n if (editorialReviewer.name) {\n score += 2;\n signals.push(`reviewed by ${editorialReviewer.name}`);\n }\n if (editorialReviewer.credentials) {\n score += 2;\n signals.push(`reviewer credentials: ${editorialReviewer.credentials}`);\n }\n if (editorialReviewer.url) {\n score += 1;\n signals.push('reviewer profile linked');\n }\n } else {\n gaps.push('no editorial reviewer specified');\n }\n\n // Check for editorial patterns in content\n let patternMatches = 0;\n for (const pattern of EDITORIAL_PATTERNS) {\n const matches = plainText.match(pattern);\n if (matches) {\n patternMatches += matches.length;\n }\n }\n\n // Also check HTML for review metadata\n const reviewMetaPatterns = [\n /class\\s*=\\s*[\"'][^\"']*(?:reviewed|fact-check|editor|reviewer)[^\"']*[\"']/gi,\n /data-reviewed/gi,\n /itemtype\\s*=\\s*[\"'][^\"']*ClaimReview/gi,\n ];\n\n for (const pattern of reviewMetaPatterns) {\n const matches = (content || '').match(pattern);\n if (matches) patternMatches += matches.length;\n }\n\n if (patternMatches > 0) {\n score += Math.min(3, patternMatches);\n signals.push(`${patternMatches} editorial indicator${patternMatches > 1 ? 's' : ''} in content`);\n }\n\n if (score >= 4) {\n return {\n id: 'eeat-editorial-review',\n title: 'Editorial review',\n description: `Strong editorial oversight: ${signals.join('; ')}. Third-party review is a key trustworthiness signal, especially for YMYL content.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (score >= 2) {\n if (!editorialReviewer) gaps.push('add structured editorialReviewer data (name, credentials, URL)');\n if (patternMatches === 0) gaps.push('add \"Reviewed by\" or \"Fact-checked by\" disclosure in content');\n return {\n id: 'eeat-editorial-review',\n title: 'Editorial review',\n description: `Partial editorial signals (${signals.join('; ')}). ${gaps.join('; ')}.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'eeat-editorial-review',\n title: 'Editorial review',\n description: 'No editorial review indicators found. Add: reviewer name & credentials (editorialReviewer), \"Reviewed by [Name]\" in content, review date, and editorial policy link. This is critical for YMYL topics.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — E-E-A-T: Source Quality & Diversity\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\n\n// Source categories by domain patterns\nconst SOURCE_CATEGORIES: Array<{ category: string; patterns: RegExp[] }> = [\n {\n category: 'academic',\n patterns: [\n /\\.edu\\b/i,\n /scholar\\.google/i,\n /pubmed/i,\n /ncbi\\.nlm/i,\n /arxiv\\.org/i,\n /doi\\.org/i,\n /jstor\\.org/i,\n /researchgate/i,\n /sciencedirect/i,\n /springer/i,\n /wiley\\.com/i,\n /nature\\.com/i,\n /science\\.org/i,\n /ieee\\.org/i,\n /acm\\.org/i,\n ],\n },\n {\n category: 'government',\n patterns: [\n /\\.gov\\b/i,\n /\\.gov\\.\\w{2}\\b/i,\n /who\\.int/i,\n /europa\\.eu/i,\n /un\\.org/i,\n ],\n },\n {\n category: 'authoritative',\n patterns: [\n /\\.org\\b/i,\n /wikipedia\\.org/i,\n /mozilla\\.org/i,\n /w3\\.org/i,\n /ietf\\.org/i,\n ],\n },\n {\n category: 'news',\n patterns: [\n /reuters/i,\n /apnews/i,\n /bbc\\./i,\n /nytimes/i,\n /washingtonpost/i,\n /theguardian/i,\n /bloomberg/i,\n /forbes/i,\n /techcrunch/i,\n /wired/i,\n /arstechnica/i,\n ],\n },\n {\n category: 'industry',\n patterns: [\n /google\\.com\\/\\w/i,\n /developers\\.google/i,\n /developer\\.mozilla/i,\n /docs\\.microsoft/i,\n /aws\\.amazon/i,\n /cloud\\.google/i,\n /developer\\.apple/i,\n /web\\.dev/i,\n ],\n },\n];\n\n// Detect references/bibliography section\nconst REFERENCES_SECTION_PATTERNS: RegExp[] = [\n /\\breferences?\\b/gi,\n /\\bbibliography\\b/gi,\n /\\bsources?\\b/gi,\n /\\bcitations?\\b/gi,\n /\\bworks?\\s+cited\\b/gi,\n /\\bfurther\\s+reading\\b/gi,\n];\n\nexport function checkSourceQuality(input: ContentAnalysisInput): AnalysisResult {\n const content = input.content || '';\n const plainText = stripHtml(content);\n const words = getWords(plainText);\n const wordCount = words.length;\n\n if (wordCount < 100) {\n return {\n id: 'eeat-source-quality',\n title: 'Source quality',\n description: 'Content is too short to assess source quality.',\n status: 'na',\n score: 0,\n maxScore: 10,\n };\n }\n\n // Extract all links from content HTML\n const linkPattern = /<a\\b[^>]*href\\s*=\\s*[\"']([^\"']+)[\"'][^>]*>/gi;\n const links: string[] = [];\n let match: RegExpExecArray | null;\n while ((match = linkPattern.exec(content)) !== null) {\n const href = match[1] || '';\n if (href.startsWith('http')) {\n links.push(href);\n }\n }\n\n // Also consider external links from input\n if (input.externalLinks) {\n for (const link of input.externalLinks) {\n if (!links.includes(link)) links.push(link);\n }\n }\n\n if (links.length === 0) {\n return {\n id: 'eeat-source-quality',\n title: 'Source quality',\n description: 'No external sources cited. Add links to authoritative sources (academic papers, government data, industry documentation) to back up claims and build trust.',\n status: 'poor',\n score: 0,\n maxScore: 10,\n };\n }\n\n // Categorize sources\n const categoryCounts: Record<string, number> = {};\n const categorizedLinks: Record<string, string[]> = {};\n\n for (const link of links) {\n let categorized = false;\n for (const { category, patterns } of SOURCE_CATEGORIES) {\n if (patterns.some(p => p.test(link))) {\n categoryCounts[category] = (categoryCounts[category] || 0) + 1;\n if (!categorizedLinks[category]) categorizedLinks[category] = [];\n categorizedLinks[category].push(link);\n categorized = true;\n break;\n }\n }\n if (!categorized) {\n categoryCounts['other'] = (categoryCounts['other'] || 0) + 1;\n }\n }\n\n // Check for references section in content\n const headings = content.match(/<h[2-6]\\b[^>]*>[\\s\\S]*?<\\/h[2-6]>/gi) || [];\n const hasReferencesSection = headings.some(h => {\n const headingText = stripHtml(h).toLowerCase();\n return REFERENCES_SECTION_PATTERNS.some(p => p.test(headingText));\n });\n\n const categories = Object.keys(categoryCounts).filter(c => c !== 'other');\n const highQualityCount = (categoryCounts['academic'] || 0) + (categoryCounts['government'] || 0);\n const diversity = categories.length;\n\n // Sources per 500 words\n const sourceDensity = (links.length / wordCount) * 500;\n\n let score = 0;\n if (links.length >= 3) score += 1;\n if (highQualityCount >= 1) score += 1;\n if (diversity >= 2) score += 1;\n if (sourceDensity >= 1) score += 1;\n if (hasReferencesSection) score += 1;\n\n const categoryDetails = categories.map(c => `${c}: ${categoryCounts[c]}`).join(', ');\n\n if (score >= 4) {\n return {\n id: 'eeat-source-quality',\n title: 'Source quality',\n description: `Strong source quality: ${links.length} external sources across ${diversity} categories (${categoryDetails}).${hasReferencesSection ? ' References section present.' : ''} Diverse, authoritative sourcing builds trust.`,\n status: 'good',\n score: 5,\n maxScore: 10,\n };\n }\n\n if (score >= 2) {\n const suggestions: string[] = [];\n if (highQualityCount === 0) suggestions.push('add academic (.edu) or government (.gov) sources');\n if (diversity < 2) suggestions.push('diversify source types (academic, government, industry)');\n if (!hasReferencesSection) suggestions.push('add a \"References\" or \"Sources\" section');\n if (links.length < 3) suggestions.push('cite at least 3 external sources');\n return {\n id: 'eeat-source-quality',\n title: 'Source quality',\n description: `Moderate source quality (${links.length} sources, ${categoryDetails}). ${suggestions.join('; ')}.`,\n status: 'ok',\n score: 3,\n maxScore: 10,\n };\n }\n\n return {\n id: 'eeat-source-quality',\n title: 'Source quality',\n description: `Weak source quality (${links.length} source${links.length > 1 ? 's' : ''}, mostly uncategorized). Add diverse, authoritative sources: academic (.edu, PubMed), government (.gov), industry documentation, and reputable news outlets. Include a \"References\" section.`,\n status: 'poor',\n score: 1,\n maxScore: 10,\n };\n}\n","// @power-seo/content-analysis — E-E-A-T: YMYL Content Detection & Compliance\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml } from '@power-seo/core';\n\n// YMYL category detection keywords\nconst YMYL_CATEGORIES: Array<{ category: string; keywords: RegExp[] }> = [\n {\n category: 'health/medical',\n keywords: [\n /\\b(symptoms?|diagnosis|treatment|medication|disease|disorder|medical|clinical|patient|dosage|side\\s+effects?|prescription|therapy|surgery|vaccine|illness|infection|chronic|acute|doctor|physician|healthcare|hospital|pharmaceutical)\\b/gi,\n ],\n },\n {\n category: 'finance',\n keywords: [\n /\\b(investment|mortgage|credit\\s+score|retirement|pension|tax\\s+(return|deduction|filing)|stock\\s+market|cryptocurrency|loan|debt|bankruptcy|insurance\\s+(claim|policy|premium)|financial\\s+planning|portfolio)\\b/gi,\n ],\n },\n {\n category: 'legal',\n keywords: [\n /\\b(lawsuit|attorney|legal\\s+(advice|rights|counsel)|court\\s+order|litigation|contract\\s+law|copyright|trademark|intellectual\\s+property|liability|negligence|criminal|felony|misdemeanor)\\b/gi,\n ],\n },\n {\n category: 'safety',\n keywords: [\n /\\b(emergency|evacuation|first\\s+aid|poison|hazardous|toxic|recall|warning\\s+sign|danger|life[\\s-]?threatening|safety\\s+protocol|protective\\s+equipment)\\b/gi,\n ],\n },\n {\n category: 'news/civic',\n keywords: [\n /\\b(election|voting|legislation|government\\s+policy|international\\s+relations|political\\s+party|civil\\s+rights|public\\s+policy|regulatory|supreme\\s+court)\\b/gi,\n ],\n },\n];\n\n// Required disclaimers by category\nconst DISCLAIMER_PATTERNS: Record<string, RegExp[]> = {\n 'health/medical': [\n /\\bnot\\s+(?:a\\s+substitute\\s+for\\s+)?(?:medical|professional)\\s+advice\\b/gi,\n /\\bconsult\\s+(?:your|a)\\s+(?:doctor|physician|healthcare|medical)\\b/gi,\n /\\bfor\\s+informational\\s+purposes?\\s+only\\b/gi,\n /\\bseek\\s+(?:immediate\\s+)?medical\\s+(?:attention|help|advice)\\b/gi,\n /\\bmedical\\s+disclaimer\\b/gi,\n ],\n 'finance': [\n /\\bnot\\s+(?:a\\s+substitute\\s+for\\s+)?financial\\s+advice\\b/gi,\n /\\bconsult\\s+(?:a|your)\\s+(?:financial|tax)\\s+(?:advisor|professional|consultant)\\b/gi,\n /\\bfor\\s+informational\\s+purposes?\\s+only\\b/gi,\n /\\bfinancial\\s+disclaimer\\b/gi,\n /\\bpast\\s+performance\\s+(?:is|does)\\s+not\\b/gi,\n ],\n 'legal': [\n /\\bnot\\s+(?:a\\s+substitute\\s+for\\s+)?legal\\s+advice\\b/gi,\n /\\bconsult\\s+(?:a|your)\\s+(?:attorney|lawyer|legal\\s+professional)\\b/gi,\n /\\bfor\\s+informational\\s+purposes?\\s+only\\b/gi,\n /\\blegal\\s+disclaimer\\b/gi,\n ],\n 'safety': [\n /\\b(?:call|contact|dial)\\s+(?:911|emergency|poison\\s+control)\\b/gi,\n /\\bseek\\s+(?:immediate|emergency)\\s+(?:help|assistance|medical)\\b/gi,\n /\\bin\\s+case\\s+of\\s+emergency\\b/gi,\n ],\n};\n\nexport function checkYmylCompliance(input: ContentAnalysisInput): AnalysisResult {\n const content = input.content || '';\n const plainText = stripHtml(content).toLowerCase();\n\n // Detect YMYL categories\n const detectedCategories: Array<{ category: string; matchCount: number }> = [];\n\n for (const { category, keywords } of YMYL_CATEGORIES) {\n let matchCount = 0;\n for (const pattern of keywords) {\n const matches = plainText.match(pattern);\n if (matches) matchCount += matches.length;\n }\n if (matchCount >= 3) { // Threshold: at least 3 keyword matches to classify\n detectedCategories.push({ category, matchCount });\n }\n }\n\n // Also check explicit category from input\n if (input.contentCategory) {\n const cat = input.contentCategory.toLowerCase();\n const isYMYL = YMYL_CATEGORIES.some(({ category }) =>\n cat.includes(category.split('/')[0] || '')\n );\n if (isYMYL && !detectedCategories.some(d => d.category.includes(cat))) {\n detectedCategories.push({ category: input.contentCategory, matchCount: 0 });\n }\n }\n\n if (detectedCategories.length === 0) {\n return {\n id: 'eeat-ymyl-compliance',\n title: 'YMYL compliance',\n description: 'Content does not appear to be YMYL (Your Money or Your Life). Standard E-E-A-T requirements apply.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n // Check for required disclaimers\n const categories = detectedCategories.map(d => d.category);\n const disclaimersFound: string[] = [];\n const disclaimersMissing: string[] = [];\n\n for (const category of categories) {\n const catKey = Object.keys(DISCLAIMER_PATTERNS).find(k => category.includes(k.split('/')[0] || ''));\n if (catKey && DISCLAIMER_PATTERNS[catKey]) {\n let found = false;\n for (const pattern of DISCLAIMER_PATTERNS[catKey]) {\n if (pattern.test(plainText)) {\n found = true;\n disclaimersFound.push(category);\n break;\n }\n }\n if (!found) {\n disclaimersMissing.push(category);\n }\n }\n }\n\n // Check for author credentials (critical for YMYL)\n const hasAuthorCredentials = !!(input.author?.credentials && input.author.credentials.length > 0);\n const hasEditorialReview = !!input.editorialReviewer;\n\n let score = 0;\n const signals: string[] = [];\n const gaps: string[] = [];\n\n if (disclaimersFound.length > 0) {\n score += 2;\n signals.push(`disclaimers present for ${disclaimersFound.join(', ')}`);\n }\n if (disclaimersMissing.length > 0) {\n gaps.push(`missing disclaimers for ${disclaimersMissing.join(', ')}`);\n }\n\n if (hasAuthorCredentials) {\n score += 2;\n signals.push('author has verifiable credentials');\n } else {\n gaps.push('YMYL content requires author with verifiable credentials');\n }\n\n if (hasEditorialReview) {\n score += 1;\n signals.push('editorial review present');\n } else {\n gaps.push('add editorial/fact-check review');\n }\n\n const ymylTypes = categories.join(', ');\n\n if (score >= 4) {\n return {\n id: 'eeat-ymyl-compliance',\n title: 'YMYL compliance',\n description: `YMYL content detected (${ymylTypes}). Good compliance: ${signals.join('; ')}. YMYL content is held to higher E-E-A-T standards by Google.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (score >= 2) {\n return {\n id: 'eeat-ymyl-compliance',\n title: 'YMYL compliance',\n description: `YMYL content detected (${ymylTypes}). Partial compliance: ${signals.join('; ')}. Gaps: ${gaps.join('; ')}. YMYL content requires strong E-E-A-T signals.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'eeat-ymyl-compliance',\n title: 'YMYL compliance',\n description: `YMYL content detected (${ymylTypes}) but lacks required trust signals. ${gaps.join('; ')}. YMYL content without proper disclaimers, credentials, and editorial review may be penalized in search rankings.`,\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — E-E-A-T: Conflict of Interest & Disclosure\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml } from '@power-seo/core';\n\n// Disclosure patterns in content\nconst DISCLOSURE_PATTERNS: RegExp[] = [\n /\\baffiliate\\s+(?:link|disclosure|commission)\\b/gi,\n /\\bthis\\s+(?:post|article|page|content)\\s+(?:contains?|includes?|may\\s+contain)\\s+affiliate/gi,\n /\\bwe?\\s+(?:may\\s+)?(?:earn|receive)\\s+(?:a\\s+)?commission/gi,\n /\\bcompensated\\s+(?:for|by)\\b/gi,\n /\\bsponsored\\s+(?:by|post|content|article)\\b/gi,\n /\\bpaid\\s+(?:partnership|promotion|collaboration)\\b/gi,\n /\\bin\\s+(?:partnership|collaboration)\\s+with\\b/gi,\n /\\bdisclosure\\s*:/gi,\n /\\btransparency\\s+(?:notice|disclosure|statement)\\b/gi,\n /\\bfull\\s+disclosure\\b/gi,\n /\\bmaterial\\s+connection\\b/gi,\n /\\bFTC\\s+(?:disclosure|guidelines?|compliance)\\b/gi,\n /\\bad\\b|\\badvertisement\\b|\\b#ad\\b|\\b#sponsored\\b/gi,\n /\\bgifted\\s+(?:product|item)\\b/gi,\n /\\bprovided\\s+(?:for\\s+review|by\\s+the\\s+(?:company|brand))\\b/gi,\n /\\bno\\s+(?:financial|monetary)\\s+(?:compensation|incentive)\\b/gi,\n /\\ball\\s+opinions?\\s+(?:are\\s+)?(?:my|our)\\s+own\\b/gi,\n];\n\n// Affiliate link patterns\nconst AFFILIATE_LINK_PATTERNS: RegExp[] = [\n /[?&](?:ref|tag|affiliate|aff|partner|tracking|utm_source|click_id|subid|hop)=/gi,\n /(?:amzn\\.to|bit\\.ly|awin1\\.com|shareasale|clickbank|jvzoo|commission\\s*junction|impact\\.com|partnerstack|referralcandy)/gi,\n /\\/ref=/gi,\n /affiliate/gi,\n];\n\nexport function checkConflictDisclosure(input: ContentAnalysisInput): AnalysisResult {\n const content = input.content || '';\n const plainText = stripHtml(content);\n\n // Detect affiliate links\n const linkPattern = /<a\\b[^>]*href\\s*=\\s*[\"']([^\"']+)[\"'][^>]*>/gi;\n const allLinks: string[] = [];\n let affiliateLinkCount = 0;\n let match: RegExpExecArray | null;\n\n while ((match = linkPattern.exec(content)) !== null) {\n const href = match[1] || '';\n allLinks.push(href);\n if (AFFILIATE_LINK_PATTERNS.some(p => p.test(href))) {\n affiliateLinkCount++;\n }\n }\n\n const totalLinks = allLinks.length;\n const affiliateRatio = totalLinks > 0 ? affiliateLinkCount / totalLinks : 0;\n\n // Check for disclosure text\n let disclosureCount = 0;\n for (const pattern of DISCLOSURE_PATTERNS) {\n const matches = plainText.match(pattern);\n if (matches) disclosureCount += matches.length;\n }\n\n // Check explicit flags from input\n const isSponsored = input.isSponsored === true;\n const hasAffiliateLinks = input.hasAffiliateLinks === true || affiliateLinkCount > 0;\n\n // If no commercial interests detected\n if (!isSponsored && !hasAffiliateLinks && affiliateLinkCount === 0) {\n if (disclosureCount > 0) {\n return {\n id: 'eeat-conflict-disclosure',\n title: 'Conflict disclosure',\n description: 'Disclosure present even without commercial interests. Proactive transparency builds reader trust.',\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n return {\n id: 'eeat-conflict-disclosure',\n title: 'Conflict disclosure',\n description: 'No commercial interests detected (no affiliate links, not sponsored). No disclosure needed.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n // Commercial interests exist — check compliance\n const issues: string[] = [];\n const positives: string[] = [];\n\n if (disclosureCount > 0) {\n positives.push('disclosure statement present');\n } else {\n issues.push('no disclosure/transparency statement found');\n }\n\n if (affiliateLinkCount > 0) {\n if (affiliateRatio > 0.5) {\n issues.push(`${Math.round(affiliateRatio * 100)}% of links are affiliate — excessive`);\n } else {\n positives.push(`${affiliateLinkCount} affiliate link${affiliateLinkCount > 1 ? 's' : ''} (${Math.round(affiliateRatio * 100)}% of total)`);\n }\n }\n\n if (isSponsored) {\n if (disclosureCount > 0) {\n positives.push('sponsored content is disclosed');\n } else {\n issues.push('sponsored content not disclosed — FTC violation risk');\n }\n }\n\n if (disclosureCount > 0 && issues.length === 0) {\n return {\n id: 'eeat-conflict-disclosure',\n title: 'Conflict disclosure',\n description: `Good transparency: ${positives.join('; ')}. Proper disclosure builds reader trust and ensures regulatory compliance.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (disclosureCount > 0 && issues.length <= 1) {\n return {\n id: 'eeat-conflict-disclosure',\n title: 'Conflict disclosure',\n description: `Partial disclosure (${positives.join('; ')}). Issues: ${issues.join('; ')}. Ensure all material connections are transparently disclosed.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'eeat-conflict-disclosure',\n title: 'Conflict disclosure',\n description: `Commercial interests detected but not properly disclosed. Issues: ${issues.join('; ')}. Add a clear disclosure statement (\"This post contains affiliate links\", \"Sponsored by...\") near the top of the content. FTC requires transparent disclosure of material connections.`,\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — E-E-A-T: Content Accuracy Patterns\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\n\n// Misleading/accuracy-undermining patterns\nconst MISLEADING_PATTERNS: Array<{ pattern: RegExp; type: string }> = [\n // False urgency\n { pattern: /\\bact\\s+now\\s+(?:before|or)\\b/gi, type: 'false urgency' },\n { pattern: /\\blimited\\s+time\\s+(?:only|offer)\\b/gi, type: 'false urgency' },\n { pattern: /\\bbefore\\s+it['']?s?\\s+too\\s+late\\b/gi, type: 'false urgency' },\n { pattern: /\\bhurry\\s+(?:up|before)\\b/gi, type: 'false urgency' },\n { pattern: /\\bdon['']t\\s+miss\\s+(?:out|this)\\b/gi, type: 'false urgency' },\n { pattern: /\\bexpires?\\s+(?:soon|today|tonight)\\b/gi, type: 'false urgency' },\n { pattern: /\\blast\\s+chance\\b/gi, type: 'false urgency' },\n { pattern: /\\bonly\\s+\\d+\\s+(?:left|remaining|spots?)\\b/gi, type: 'false scarcity' },\n\n // Unsubstantiated superlatives\n { pattern: /\\bthe\\s+(?:absolute|very|single)\\s+best\\b/gi, type: 'unsubstantiated superlative' },\n { pattern: /\\b(?:best|greatest|most\\s+\\w+)\\s+(?:ever|in\\s+the\\s+world|of\\s+all\\s+time)\\b/gi, type: 'unsubstantiated superlative' },\n { pattern: /\\bnothing\\s+(?:else\\s+)?(?:compares?|comes?\\s+close|beats?)\\b/gi, type: 'unsubstantiated superlative' },\n { pattern: /\\bthe\\s+only\\s+(?:solution|answer|way|product|tool)\\s+you['']?ll?\\s+(?:ever\\s+)?need\\b/gi, type: 'unsubstantiated superlative' },\n\n // Clickbait exaggeration\n { pattern: /\\byou\\s+won['']t\\s+believe\\b/gi, type: 'clickbait' },\n { pattern: /\\bshocking\\s+(?:truth|reason|secret|fact)\\b/gi, type: 'clickbait' },\n { pattern: /\\bwhat\\s+(?:they|nobody|no\\s+one)\\s+(?:don['']t|won['']t)\\s+tell\\s+you\\b/gi, type: 'clickbait' },\n { pattern: /\\bsecret\\s+(?:that|they|nobody)\\b/gi, type: 'clickbait' },\n { pattern: /\\bdoctors?\\s+(?:hate|don['']t\\s+want)\\b/gi, type: 'clickbait' },\n { pattern: /\\bone\\s+weird\\s+trick\\b/gi, type: 'clickbait' },\n { pattern: /\\bmind[\\s-]?blow(?:ing|n)\\b/gi, type: 'clickbait' },\n\n // Deceptive framing\n { pattern: /\\bguaranteed\\s+(?:results?|success|income|returns?)\\b/gi, type: 'deceptive claim' },\n { pattern: /\\b100\\s*%\\s+(?:guaranteed|proven|risk[\\s-]?free|safe|effective|success)\\b/gi, type: 'deceptive claim' },\n { pattern: /\\bget\\s+rich\\s+(?:quick|fast)\\b/gi, type: 'deceptive claim' },\n { pattern: /\\bmake\\s+(?:\\$[\\d,]+|money)\\s+(?:fast|easily|overnight|while\\s+you\\s+sleep)\\b/gi, type: 'deceptive claim' },\n { pattern: /\\bno\\s+(?:risk|effort|experience)\\s+(?:required|needed|necessary)\\b/gi, type: 'deceptive claim' },\n { pattern: /\\binstant\\s+(?:results?|success|cure|fix)\\b/gi, type: 'deceptive claim' },\n { pattern: /\\bmiracle\\s+(?:cure|solution|product|formula)\\b/gi, type: 'deceptive claim' },\n];\n\n// Evidence-backing patterns (claims supported by data)\nconst EVIDENCE_PATTERNS: RegExp[] = [\n /\\baccording\\s+to\\s+(?:a\\s+)?(?:study|research|survey|report|data)\\b/gi,\n /\\b(?:studies?|research|data|evidence)\\s+(?:shows?|suggests?|indicates?|demonstrates?|confirms?|supports?)\\b/gi,\n /\\b\\[\\d+\\]\\b/g, // Citation markers [1], [2]\n /\\bsource\\s*:/gi,\n /\\bcited?\\s+(?:in|from|by)\\b/gi,\n /\\breference\\s*:/gi,\n /\\b(?:published|reported)\\s+(?:in|by)\\b/gi,\n];\n\nexport function checkContentAccuracy(input: ContentAnalysisInput): AnalysisResult {\n const plainText = stripHtml(input.content || '');\n const words = getWords(plainText);\n const wordCount = words.length;\n\n if (wordCount < 50) {\n return {\n id: 'eeat-content-accuracy',\n title: 'Content accuracy',\n description: 'Content is too short to assess accuracy patterns.',\n status: 'na',\n score: 0,\n maxScore: 10,\n };\n }\n\n // Detect misleading patterns\n const foundIssues: Array<{ text: string; type: string }> = [];\n const issueTypes = new Set<string>();\n\n for (const { pattern, type } of MISLEADING_PATTERNS) {\n const matches = plainText.match(pattern);\n if (matches) {\n for (const m of matches) {\n if (foundIssues.length < 5) {\n foundIssues.push({ text: m.trim(), type });\n }\n issueTypes.add(type);\n }\n }\n }\n\n // Detect evidence-backing\n let evidenceCount = 0;\n for (const pattern of EVIDENCE_PATTERNS) {\n const matches = plainText.match(pattern);\n if (matches) evidenceCount += matches.length;\n }\n\n const issueCount = foundIssues.length;\n\n if (issueCount === 0 && evidenceCount >= 2) {\n return {\n id: 'eeat-content-accuracy',\n title: 'Content accuracy',\n description: `No misleading language detected. ${evidenceCount} evidence-backed claims found. Content maintains factual, trustworthy tone.`,\n status: 'good',\n score: 5,\n maxScore: 10,\n };\n }\n\n if (issueCount === 0) {\n return {\n id: 'eeat-content-accuracy',\n title: 'Content accuracy',\n description: 'No misleading language detected. Consider adding more evidence-backed claims (\"research shows\", \"according to studies\") to strengthen trustworthiness.',\n status: 'good',\n score: 5,\n maxScore: 10,\n };\n }\n\n if (issueCount <= 2 && evidenceCount >= 1) {\n const examples = foundIssues.slice(0, 2).map(i => `\"${i.text}\" (${i.type})`);\n return {\n id: 'eeat-content-accuracy',\n title: 'Content accuracy',\n description: `Minor accuracy concerns: ${examples.join('; ')}. Consider softening or removing these phrases. ${evidenceCount} evidence-backed claims help balance credibility.`,\n status: 'ok',\n score: 3,\n maxScore: 10,\n };\n }\n\n const typeList = Array.from(issueTypes).join(', ');\n const examples = foundIssues.slice(0, 3).map(i => `\"${i.text}\"`);\n return {\n id: 'eeat-content-accuracy',\n title: 'Content accuracy',\n description: `${issueCount} accuracy issues detected (${typeList}): ${examples.join(', ')}. Remove misleading language, unsubstantiated claims, and clickbait. Back claims with evidence and use calibrated language.`,\n status: 'poor',\n score: 0,\n maxScore: 10,\n };\n}\n","// @power-seo/content-analysis — E-E-A-T: Correction & Update Policy\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml } from '@power-seo/core';\n\n// Update/correction indicators in content\nconst UPDATE_PATTERNS: RegExp[] = [\n /\\b(?:last\\s+)?updated?\\s*(?:on|:)\\s*(?:\\w+\\s+\\d{1,2},?\\s+\\d{4}|\\d{4}[-/]\\d{2}[-/]\\d{2})/gi,\n /\\b(?:originally\\s+)?published\\s*(?:on|:)\\s*(?:\\w+\\s+\\d{1,2},?\\s+\\d{4}|\\d{4}[-/]\\d{2}[-/]\\d{2})/gi,\n /\\beditor['']?s?\\s+note\\b/gi,\n /\\bupdate\\s*(?:\\d{4}[-/]\\d{2}|\\w+\\s+\\d{4})\\s*:/gi,\n /\\bcorrection\\s*:/gi,\n /\\berrata\\b/gi,\n /\\b\\[updated?\\]/gi,\n /\\bthis\\s+(?:article|post|guide|content)\\s+(?:was\\s+)?(?:last\\s+)?updated/gi,\n /\\bchangelog\\b/gi,\n /\\bversion\\s+history\\b/gi,\n /\\brevision\\s+history\\b/gi,\n /\\bupdate\\s+history\\b/gi,\n /\\bcorrections?\\s+policy\\b/gi,\n /\\beditorial\\s+(?:policy|standards|guidelines)\\b/gi,\n];\n\nexport function checkCorrectionPolicy(input: ContentAnalysisInput): AnalysisResult {\n const content = input.content || '';\n const plainText = stripHtml(content);\n\n let score = 0;\n const signals: string[] = [];\n const gaps: string[] = [];\n\n // Check for publish and modified dates from input\n if (input.publishDate) {\n score += 1;\n const pubDate = input.publishDate instanceof Date\n ? input.publishDate.toISOString().split('T')[0]\n : String(input.publishDate);\n signals.push(`publish date: ${pubDate}`);\n } else {\n gaps.push('no publish date provided');\n }\n\n if (input.modifiedDate) {\n score += 2;\n const modDate = input.modifiedDate instanceof Date\n ? input.modifiedDate.toISOString().split('T')[0]\n : String(input.modifiedDate);\n signals.push(`last modified: ${modDate}`);\n\n // Check if modified date is after publish date\n if (input.publishDate) {\n const pub = new Date(input.publishDate);\n const mod = new Date(input.modifiedDate);\n if (mod > pub) {\n signals.push('content has been updated since publication');\n }\n }\n } else {\n gaps.push('no modified date provided');\n }\n\n // Check for correction policy URL\n if (input.correctionPolicyUrl) {\n score += 1;\n signals.push('correction policy URL provided');\n }\n\n // Check for update/correction patterns in content\n let updatePatternCount = 0;\n for (const pattern of UPDATE_PATTERNS) {\n const matches = plainText.match(pattern);\n if (matches) updatePatternCount += matches.length;\n }\n\n if (updatePatternCount > 0) {\n score += Math.min(2, updatePatternCount);\n signals.push(`${updatePatternCount} update/correction indicator${updatePatternCount > 1 ? 's' : ''} in content`);\n } else {\n gaps.push('no update notices or correction markers in content');\n }\n\n // Check HTML for structured date metadata\n const dateMetaPatterns = [\n /datetime\\s*=\\s*[\"']\\d{4}/gi,\n /dateModified/gi,\n /datePublished/gi,\n /class\\s*=\\s*[\"'][^\"']*(?:updated|modified|published)[\\s-]?date[^\"']*[\"']/gi,\n ];\n\n for (const pattern of dateMetaPatterns) {\n if (pattern.test(content)) {\n score += 1;\n signals.push('structured date metadata found');\n break;\n }\n }\n\n if (score >= 4) {\n return {\n id: 'eeat-correction-policy',\n title: 'Correction & update policy',\n description: `Strong transparency: ${signals.join('; ')}. Date tracking and correction policies signal content maintenance commitment.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (score >= 2) {\n return {\n id: 'eeat-correction-policy',\n title: 'Correction & update policy',\n description: `Partial transparency (${signals.join('; ')}). Add: ${gaps.join('; ')}. Showing content is actively maintained builds trust.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'eeat-correction-policy',\n title: 'Correction & update policy',\n description: 'No correction/update policy signals found. Add: publish date, last updated date, \"[Updated March 2026]\" notices, editor\\'s notes for corrections, and link to editorial/correction policy.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — E-E-A-T: Privacy & Safety Signals\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml } from '@power-seo/core';\n\n// Privacy/safety mentions in content\nconst PRIVACY_PATTERNS: RegExp[] = [\n /\\bprivacy\\s+policy\\b/gi,\n /\\bterms\\s+(?:of\\s+(?:service|use)|and\\s+conditions)\\b/gi,\n /\\bcookie\\s+(?:policy|consent|notice)\\b/gi,\n /\\bdata\\s+(?:protection|privacy|handling|processing)\\b/gi,\n /\\bGDPR\\b/g,\n /\\bCCPA\\b/g,\n /\\bSOC\\s+2\\b/gi,\n /\\bISO\\s+27001\\b/gi,\n /\\bcompliance\\b/gi,\n /\\bencrypt(?:ed|ion)\\b/gi,\n /\\bsecure(?:ly|d)?\\b/gi,\n /\\bSSL\\b/g,\n /\\bTLS\\b/g,\n /\\btwo[\\s-]?factor\\s+auth/gi,\n /\\b2FA\\b/g,\n /\\bMFA\\b/g,\n];\n\nexport function checkPrivacySafety(input: ContentAnalysisInput): AnalysisResult {\n const content = input.content || '';\n const plainText = stripHtml(content);\n\n let score = 0;\n const signals: string[] = [];\n const gaps: string[] = [];\n\n // Check HTTPS in canonical URL\n if (input.canonicalUrl) {\n if (input.canonicalUrl.startsWith('https://')) {\n score += 2;\n signals.push('HTTPS canonical URL');\n } else if (input.canonicalUrl.startsWith('http://')) {\n gaps.push('canonical URL uses HTTP instead of HTTPS');\n }\n } else if (input.siteUrl) {\n if (input.siteUrl.startsWith('https://')) {\n score += 2;\n signals.push('HTTPS site URL');\n } else {\n gaps.push('site URL uses HTTP instead of HTTPS');\n }\n } else {\n gaps.push('no canonical URL to verify HTTPS');\n }\n\n // Check privacy policy URL from input\n if (input.privacyPolicyUrl) {\n score += 1;\n signals.push('privacy policy URL provided');\n } else {\n gaps.push('no privacy policy URL');\n }\n\n // Check for privacy/safety mentions in content\n let privacyMentionCount = 0;\n for (const pattern of PRIVACY_PATTERNS) {\n const matches = plainText.match(pattern);\n if (matches) privacyMentionCount += matches.length;\n }\n\n if (privacyMentionCount > 0) {\n score += 1;\n signals.push(`${privacyMentionCount} privacy/security reference${privacyMentionCount > 1 ? 's' : ''} in content`);\n }\n\n // Check for privacy-related links in HTML\n const privacyLinkPatterns = [\n /href\\s*=\\s*[\"'][^\"']*privac[^\"']*[\"']/gi,\n /href\\s*=\\s*[\"'][^\"']*terms[^\"']*[\"']/gi,\n /href\\s*=\\s*[\"'][^\"']*cookie[^\"']*[\"']/gi,\n /href\\s*=\\s*[\"'][^\"']*gdpr[^\"']*[\"']/gi,\n /href\\s*=\\s*[\"'][^\"']*legal[^\"']*[\"']/gi,\n ];\n\n let privacyLinks = 0;\n for (const pattern of privacyLinkPatterns) {\n const matches = content.match(pattern);\n if (matches) privacyLinks += matches.length;\n }\n\n if (privacyLinks > 0) {\n score += 1;\n signals.push(`${privacyLinks} privacy/legal link${privacyLinks > 1 ? 's' : ''} found`);\n }\n\n if (score >= 3) {\n return {\n id: 'eeat-privacy-safety',\n title: 'Privacy & safety',\n description: `Good trust signals: ${signals.join('; ')}. HTTPS, privacy policies, and security references build user trust.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (score >= 1) {\n return {\n id: 'eeat-privacy-safety',\n title: 'Privacy & safety',\n description: `Partial trust signals (${signals.join('; ')}). Gaps: ${gaps.join('; ')}. Ensure HTTPS, link to privacy policy, and reference data handling practices.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'eeat-privacy-safety',\n title: 'Privacy & safety',\n description: `No privacy/safety signals found. ${gaps.join('; ')}. Use HTTPS, link to privacy policy and terms of service, and reference data protection when handling user data.`,\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — E-E-A-T: Overall Score Aggregation\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\n\n// First-person experience markers (subset for quick pillar scan)\nconst EXPERIENCE_MARKERS: RegExp[] = [\n /\\bi\\s+tested\\b/gi,\n /\\bi\\s+used\\b/gi,\n /\\bi\\s+tried\\b/gi,\n /\\bi\\s+found\\s+that\\b/gi,\n /\\bi\\s+experienced\\b/gi,\n /\\bi\\s+personally\\b/gi,\n /\\bi\\s+recommend\\b/gi,\n /\\bi\\s+built\\b/gi,\n /\\bi\\s+implemented\\b/gi,\n /\\bi\\s+measured\\b/gi,\n /\\bi\\s+compared\\b/gi,\n /\\bin\\s+my\\s+experience\\b/gi,\n /\\bfrom\\s+my\\s+experience\\b/gi,\n /\\bhaving\\s+used\\b/gi,\n /\\bhaving\\s+tested\\b/gi,\n /\\bwhat\\s+i\\s+found\\b/gi,\n /\\bwhat\\s+worked\\s+for\\s+me\\b/gi,\n /\\bhands.on\\b/gi,\n /\\breal.world\\b/gi,\n];\n\n// Temporal experience patterns (stronger signal)\nconst TEMPORAL_EXPERIENCE: RegExp[] = [\n /\\bafter\\s+\\d+\\s+(months?|years?|weeks?|days?)\\s+of\\s+using\\b/gi,\n /\\bover\\s+the\\s+past\\s+\\d+\\s+(months?|years?|weeks?)\\b/gi,\n /\\bfor\\s+the\\s+last\\s+\\d+\\s+(months?|years?|weeks?)\\b/gi,\n /\\bi['']ve\\s+been\\s+using\\b/gi,\n /\\bi['']ve\\s+spent\\b/gi,\n /\\bi['']ve\\s+worked\\s+with\\b/gi,\n /\\bfor\\s+over\\s+\\d+\\s+years?\\b/gi,\n /\\bsince\\s+\\d{4}\\b/gi,\n];\n\ninterface PillarAssessment {\n name: string;\n score: number;\n maxScore: number;\n strong: boolean;\n}\n\nfunction assessExperience(plainText: string, wordCount: number): PillarAssessment {\n let score = 0;\n\n // Check first-person experience markers\n let markerCount = 0;\n for (const pattern of EXPERIENCE_MARKERS) {\n const matches = plainText.match(pattern);\n if (matches) markerCount += matches.length;\n }\n\n const density = wordCount > 0 ? (markerCount / wordCount) * 500 : 0;\n if (density >= 2) score += 2;\n else if (density >= 1) score += 1;\n\n // Check temporal experience patterns (stronger signal)\n let temporalCount = 0;\n for (const pattern of TEMPORAL_EXPERIENCE) {\n const matches = plainText.match(pattern);\n if (matches) temporalCount += matches.length;\n }\n\n if (temporalCount >= 2) score += 1;\n\n return {\n name: 'Experience',\n score,\n maxScore: 3,\n strong: score >= 2,\n };\n}\n\nfunction assessExpertise(input: ContentAnalysisInput): PillarAssessment {\n const { author } = input;\n let score = 0;\n\n if (!author) {\n return { name: 'Expertise', score: 0, maxScore: 3, strong: false };\n }\n\n // Credentials signal deep expertise\n if (author.credentials && author.credentials.length > 0) {\n score += 1;\n }\n\n // knowsAbout shows topical expertise\n if (author.knowsAbout && author.knowsAbout.length > 0) {\n score += 1;\n }\n\n // Bio + jobTitle demonstrate professional standing\n if (author.bio && author.bio.trim().length >= 20 && author.jobTitle && author.jobTitle.trim()) {\n score += 1;\n }\n\n return {\n name: 'Expertise',\n score,\n maxScore: 3,\n strong: score >= 2,\n };\n}\n\nfunction assessAuthoritativeness(input: ContentAnalysisInput): PillarAssessment {\n const { author } = input;\n let score = 0;\n\n if (!author) {\n return { name: 'Authority', score: 0, maxScore: 3, strong: false };\n }\n\n // Social profiles breadth signals cross-platform authority\n if (author.socialProfiles && author.socialProfiles.length >= 3) {\n score += 1;\n }\n\n // Publications demonstrate recognized expertise\n if (author.publications && author.publications.length > 0) {\n score += 1;\n }\n\n // Organization affiliation (worksFor) provides institutional backing\n if (author.worksFor && author.worksFor.name) {\n score += 1;\n }\n\n return {\n name: 'Authority',\n score,\n maxScore: 3,\n strong: score >= 2,\n };\n}\n\nfunction assessTrustWorthiness(input: ContentAnalysisInput): PillarAssessment {\n let score = 0;\n\n // HTTPS canonical URL\n const url = input.canonicalUrl || input.siteUrl || '';\n if (url.startsWith('https://')) {\n score += 1;\n }\n\n // Publish date signals transparency and freshness\n if (input.publishDate) {\n score += 1;\n }\n\n // Privacy policy URL\n if (input.privacyPolicyUrl) {\n score += 1;\n }\n\n // Penalize: sponsored content without proper disclosure is a trust issue\n // If sponsored, we require at least privacy policy or publish date to offset\n if (input.isSponsored && score < 2) {\n score = Math.max(0, score - 1);\n }\n\n return {\n name: 'Trust',\n score,\n maxScore: 3,\n strong: score >= 2,\n };\n}\n\nexport function checkEeatOverallScore(input: ContentAnalysisInput): AnalysisResult {\n const plainText = stripHtml(input.content || '');\n const words = getWords(plainText);\n const wordCount = words.length;\n\n if (wordCount < 50) {\n return {\n id: 'eeat-overall-score',\n title: 'E-E-A-T overall score',\n description: 'Content is too short to assess E-E-A-T signals.',\n status: 'na',\n score: 0,\n maxScore: 8,\n };\n }\n\n const experience = assessExperience(plainText.toLowerCase(), wordCount);\n const expertise = assessExpertise(input);\n const authority = assessAuthoritativeness(input);\n const trust = assessTrustWorthiness(input);\n\n const pillars = [experience, expertise, authority, trust];\n const strongCount = pillars.filter(p => p.strong).length;\n const pillarSummary = pillars\n .map(p => `${p.name} ${p.score}/${p.maxScore}`)\n .join(', ');\n\n if (strongCount >= 3) {\n return {\n id: 'eeat-overall-score',\n title: 'E-E-A-T overall score',\n description: `Strong E-E-A-T profile with ${strongCount}/4 pillars solid. ${pillarSummary}. Content demonstrates real experience, author expertise, authoritative backing, and trustworthiness.`,\n status: 'good',\n score: 5,\n maxScore: 8,\n };\n }\n\n if (strongCount >= 2) {\n const weakPillars = pillars.filter(p => !p.strong).map(p => p.name);\n return {\n id: 'eeat-overall-score',\n title: 'E-E-A-T overall score',\n description: `Moderate E-E-A-T profile with ${strongCount}/4 pillars solid. ${pillarSummary}. Strengthen ${weakPillars.join(' and ')} to improve overall quality signals.`,\n status: 'ok',\n score: 3,\n maxScore: 8,\n };\n }\n\n const weakPillars = pillars.filter(p => !p.strong).map(p => p.name);\n return {\n id: 'eeat-overall-score',\n title: 'E-E-A-T overall score',\n description: `Weak E-E-A-T profile with only ${strongCount}/4 pillars solid. ${pillarSummary}. ${weakPillars.join(', ')} need improvement. Add first-person experience, author credentials, social profiles, publications, and trust signals (HTTPS, publish date, privacy policy).`,\n status: 'poor',\n score: 0,\n maxScore: 8,\n };\n}\n","// @power-seo/content-analysis — E-E-A-T: YMYL Multiplier\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml } from '@power-seo/core';\n\n// YMYL category detection keywords (health, finance, legal, safety, civic)\nconst YMYL_CATEGORIES: Array<{ category: string; keywords: RegExp[] }> = [\n {\n category: 'health/medical',\n keywords: [\n /\\b(symptoms?|diagnosis|treatment|medication|disease|disorder|medical|clinical|patient|dosage|side\\s+effects?|prescription|therapy|surgery|vaccine|illness|infection|chronic|acute|doctor|physician|healthcare|hospital|pharmaceutical)\\b/gi,\n ],\n },\n {\n category: 'finance',\n keywords: [\n /\\b(investment|mortgage|credit\\s+score|retirement|pension|tax\\s+(return|deduction|filing)|stock\\s+market|cryptocurrency|loan|debt|bankruptcy|insurance\\s+(claim|policy|premium)|financial\\s+planning|portfolio)\\b/gi,\n ],\n },\n {\n category: 'legal',\n keywords: [\n /\\b(lawsuit|attorney|legal\\s+(advice|rights|counsel)|court\\s+order|litigation|contract\\s+law|copyright|trademark|intellectual\\s+property|liability|negligence|criminal|felony|misdemeanor)\\b/gi,\n ],\n },\n {\n category: 'safety',\n keywords: [\n /\\b(emergency|evacuation|first\\s+aid|poison|hazardous|toxic|recall|warning\\s+sign|danger|life[\\s-]?threatening|safety\\s+protocol|protective\\s+equipment)\\b/gi,\n ],\n },\n {\n category: 'news/civic',\n keywords: [\n /\\b(election|voting|legislation|government\\s+policy|international\\s+relations|political\\s+party|civil\\s+rights|public\\s+policy|regulatory|supreme\\s+court)\\b/gi,\n ],\n },\n];\n\n// Disclaimer patterns by category\nconst DISCLAIMER_PATTERNS: Record<string, RegExp[]> = {\n 'health/medical': [\n /\\bnot\\s+(?:a\\s+substitute\\s+for\\s+)?(?:medical|professional)\\s+advice\\b/gi,\n /\\bconsult\\s+(?:your|a)\\s+(?:doctor|physician|healthcare|medical)\\b/gi,\n /\\bfor\\s+informational\\s+purposes?\\s+only\\b/gi,\n /\\bseek\\s+(?:immediate\\s+)?medical\\s+(?:attention|help|advice)\\b/gi,\n /\\bmedical\\s+disclaimer\\b/gi,\n ],\n 'finance': [\n /\\bnot\\s+(?:a\\s+substitute\\s+for\\s+)?financial\\s+advice\\b/gi,\n /\\bconsult\\s+(?:a|your)\\s+(?:financial|tax)\\s+(?:advisor|professional|consultant)\\b/gi,\n /\\bfor\\s+informational\\s+purposes?\\s+only\\b/gi,\n /\\bfinancial\\s+disclaimer\\b/gi,\n /\\bpast\\s+performance\\s+(?:is|does)\\s+not\\b/gi,\n ],\n 'legal': [\n /\\bnot\\s+(?:a\\s+substitute\\s+for\\s+)?legal\\s+advice\\b/gi,\n /\\bconsult\\s+(?:a|your)\\s+(?:attorney|lawyer|legal\\s+professional)\\b/gi,\n /\\bfor\\s+informational\\s+purposes?\\s+only\\b/gi,\n /\\blegal\\s+disclaimer\\b/gi,\n ],\n 'safety': [\n /\\b(?:call|contact|dial)\\s+(?:911|emergency|poison\\s+control)\\b/gi,\n /\\bseek\\s+(?:immediate|emergency)\\s+(?:help|assistance|medical)\\b/gi,\n /\\bin\\s+case\\s+of\\s+emergency\\b/gi,\n ],\n};\n\nfunction detectYmylCategories(plainText: string, contentCategory?: string): string[] {\n const detected: string[] = [];\n\n for (const { category, keywords } of YMYL_CATEGORIES) {\n let matchCount = 0;\n for (const pattern of keywords) {\n const matches = plainText.match(pattern);\n if (matches) matchCount += matches.length;\n }\n if (matchCount >= 3) {\n detected.push(category);\n }\n }\n\n // Also check explicit category from input\n if (contentCategory) {\n const cat = contentCategory.toLowerCase();\n const isYMYL = YMYL_CATEGORIES.some(({ category }) =>\n cat.includes(category.split('/')[0] || '')\n );\n if (isYMYL && !detected.some(d => d.includes(cat.split('/')[0] || ''))) {\n detected.push(contentCategory);\n }\n }\n\n return detected;\n}\n\nexport function checkYmylMultiplier(input: ContentAnalysisInput): AnalysisResult {\n const content = input.content || '';\n const plainText = stripHtml(content).toLowerCase();\n\n // Detect YMYL categories\n const ymylCategories = detectYmylCategories(plainText, input.contentCategory);\n\n if (ymylCategories.length === 0) {\n return {\n id: 'eeat-ymyl-multiplier',\n title: 'YMYL multiplier',\n description: 'Content is not YMYL (Your Money or Your Life). Standard E-E-A-T requirements apply; no stricter multiplier needed.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const ymylTypes = ymylCategories.join(', ');\n\n // Assess E-E-A-T signal strength under YMYL scrutiny\n let eeatScore = 0;\n const signals: string[] = [];\n const gaps: string[] = [];\n\n // 1. Author credentials (critical for YMYL)\n if (input.author?.credentials && input.author.credentials.length > 0) {\n eeatScore += 2;\n const credNames = input.author.credentials.map(c => c.name);\n signals.push(`author credentials: ${credNames.slice(0, 3).join(', ')}`);\n } else {\n gaps.push('YMYL content requires author with verifiable credentials');\n }\n\n // 2. Editorial reviewer (fact-checking)\n if (input.editorialReviewer) {\n eeatScore += 2;\n const reviewerInfo = input.editorialReviewer.name || 'unnamed';\n signals.push(`editorial reviewer: ${reviewerInfo}`);\n if (input.editorialReviewer.credentials) {\n eeatScore += 1;\n signals.push(`reviewer credentials: ${input.editorialReviewer.credentials}`);\n }\n } else {\n gaps.push('add editorial/fact-check reviewer for YMYL content');\n }\n\n // 3. Category-appropriate disclaimers\n let hasDisclaimer = false;\n for (const category of ymylCategories) {\n const catKey = Object.keys(DISCLAIMER_PATTERNS).find(k => category.includes(k.split('/')[0] || ''));\n if (catKey && DISCLAIMER_PATTERNS[catKey]) {\n for (const pattern of DISCLAIMER_PATTERNS[catKey]) {\n if (pattern.test(plainText)) {\n hasDisclaimer = true;\n break;\n }\n }\n }\n if (hasDisclaimer) break;\n }\n\n if (hasDisclaimer) {\n eeatScore += 1;\n signals.push('appropriate disclaimers present');\n } else {\n gaps.push('add category-appropriate disclaimers (e.g., \"consult a professional\", \"for informational purposes only\")');\n }\n\n // 4. HTTPS (baseline trust for YMYL)\n const url = input.canonicalUrl || input.siteUrl || '';\n if (url.startsWith('https://')) {\n eeatScore += 1;\n signals.push('HTTPS verified');\n } else {\n gaps.push('YMYL content must be served over HTTPS');\n }\n\n // 5. Publish/modified dates (transparency)\n if (input.publishDate) {\n eeatScore += 1;\n signals.push('publish date provided');\n } else {\n gaps.push('add publish date for content freshness transparency');\n }\n\n // 6. Author bio and expertise areas\n if (input.author?.bio && input.author.bio.trim().length >= 20 && input.author.knowsAbout && input.author.knowsAbout.length > 0) {\n eeatScore += 1;\n signals.push('author bio with expertise areas');\n }\n\n // 7. Correction policy (accountability for YMYL)\n if (input.correctionPolicyUrl) {\n eeatScore += 1;\n signals.push('correction policy linked');\n }\n\n if (eeatScore >= 6) {\n return {\n id: 'eeat-ymyl-multiplier',\n title: 'YMYL multiplier',\n description: `YMYL content detected (${ymylTypes}) with strong E-E-A-T compliance. ${signals.join('; ')}. Content meets the higher trust bar Google applies to YMYL topics.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (eeatScore >= 3) {\n return {\n id: 'eeat-ymyl-multiplier',\n title: 'YMYL multiplier',\n description: `YMYL content detected (${ymylTypes}) with moderate E-E-A-T signals. Present: ${signals.join('; ')}. Gaps: ${gaps.join('; ')}. YMYL topics face stricter quality evaluation.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'eeat-ymyl-multiplier',\n title: 'YMYL multiplier',\n description: `YMYL content detected (${ymylTypes}) with insufficient E-E-A-T signals. Gaps: ${gaps.join('; ')}. YMYL content without strong author credentials, editorial review, disclaimers, and trust signals faces significant ranking penalties.`,\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Previously Used Keyphrase Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\n/**\n * Normalize a keyphrase for comparison: lowercase, collapse whitespace, trim.\n */\nfunction normalize(kp: string): string {\n return kp.toLowerCase().replace(/\\s+/g, ' ').trim();\n}\n\n/**\n * Check whether two keyphrases have a partial/fuzzy overlap\n * (one contains the other as a substring).\n */\nfunction hasPartialOverlap(a: string, b: string): boolean {\n return a.includes(b) || b.includes(a);\n}\n\n/**\n * Check if the focus keyphrase was already used in another post.\n *\n * - Exact match: the same keyphrase is used word-for-word elsewhere.\n * - Partial overlap: one keyphrase contains the other (e.g. \"running shoes\" vs \"best running shoes\").\n * - Unique: no conflict found.\n *\n * This helps avoid keyword cannibalization where multiple pages compete\n * for the same search query.\n */\nexport function checkPreviouslyUsedKeyphrase(input: ContentAnalysisInput): AnalysisResult {\n const { focusKeyphrase, previouslyUsedKeyphrases } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n return {\n id: 'previously-used-keyphrase',\n title: 'Previously used keyphrase',\n description: 'No focus keyphrase set. Set one to check for duplicate keyphrase usage.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n if (!previouslyUsedKeyphrases || previouslyUsedKeyphrases.length === 0) {\n return {\n id: 'previously-used-keyphrase',\n title: 'Previously used keyphrase',\n description:\n 'No previously used keyphrases data available. Provide this data to detect keyword cannibalization.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const normalizedFocus = normalize(focusKeyphrase);\n\n // Check for exact match first\n for (const entry of previouslyUsedKeyphrases) {\n const normalizedExisting = normalize(entry.keyphrase);\n if (normalizedFocus === normalizedExisting) {\n const urlNote = entry.postUrl ? ` (${entry.postUrl})` : '';\n return {\n id: 'previously-used-keyphrase',\n title: 'Previously used keyphrase',\n description:\n `This exact keyphrase has already been used in \"${entry.postTitle}\"${urlNote}. ` +\n 'Using the same keyphrase on multiple pages causes keyword cannibalization. ' +\n 'Choose a unique keyphrase for this content.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n }\n\n // Check for partial overlap (one contains the other)\n for (const entry of previouslyUsedKeyphrases) {\n const normalizedExisting = normalize(entry.keyphrase);\n if (hasPartialOverlap(normalizedFocus, normalizedExisting)) {\n return {\n id: 'previously-used-keyphrase',\n title: 'Previously used keyphrase',\n description:\n `This keyphrase partially overlaps with \"${entry.keyphrase}\" used in \"${entry.postTitle}\". ` +\n 'Consider differentiating your keyphrase further to avoid competing with your own content.',\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n }\n\n // No conflicts\n return {\n id: 'previously-used-keyphrase',\n title: 'Previously used keyphrase',\n description:\n 'This keyphrase has not been used on any other page. No keyword cannibalization risk detected.',\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Keyphrase Even Distribution Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\n\nconst MIN_WORDS_FOR_ANALYSIS = 100;\nconst MIN_PARAGRAPHS_FOR_ANALYSIS = 4;\n\n/**\n * Split HTML content into paragraphs using block-level boundaries.\n */\nfunction splitParagraphs(html: string): string[] {\n const blocks = html\n .split(/<\\/p>|<\\/div>|<\\/li>|<\\/blockquote>|<br\\s*\\/?>\\s*<br\\s*\\/?>/gi)\n .map((block) => stripHtml(block).trim())\n .filter((block) => block.length > 0);\n\n if (blocks.length === 0) {\n return stripHtml(html)\n .split(/\\n\\s*\\n/)\n .map((p) => p.trim())\n .filter((p) => p.length > 0);\n }\n\n return blocks;\n}\n\n/**\n * Check whether a text segment contains the keyphrase (case-insensitive).\n */\nfunction containsKeyphrase(text: string, keyphrase: string): boolean {\n return text.toLowerCase().includes(keyphrase.toLowerCase());\n}\n\n/**\n * Divide an array into N roughly equal segments.\n */\nfunction divideIntoSegments<T>(arr: T[], segmentCount: number): T[][] {\n const segments: T[][] = [];\n const segmentSize = Math.max(1, Math.ceil(arr.length / segmentCount));\n for (let i = 0; i < segmentCount; i++) {\n const start = i * segmentSize;\n const end = Math.min(start + segmentSize, arr.length);\n if (start < arr.length) {\n segments.push(arr.slice(start, end));\n }\n }\n return segments;\n}\n\n/**\n * Check that the focus keyphrase is evenly distributed throughout the content.\n *\n * Splits the content into 4 quarters by paragraph count and checks whether\n * the keyphrase appears in each quarter. Also verifies the keyphrase appears\n * in the first 10% (hook/introduction) and last 10% (conclusion) of the text.\n */\nexport function checkKeyphraseEvenDistribution(input: ContentAnalysisInput): AnalysisResult {\n const { focusKeyphrase, content } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n return {\n id: 'keyphrase-even-distribution',\n title: 'Keyphrase distribution across content',\n description: 'No focus keyphrase set. Set one to analyze keyphrase distribution.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const words = getWords(content);\n if (words.length < MIN_WORDS_FOR_ANALYSIS) {\n return {\n id: 'keyphrase-even-distribution',\n title: 'Keyphrase distribution across content',\n description:\n `Content is only ${words.length} words. At least ${MIN_WORDS_FOR_ANALYSIS} words are needed ` +\n 'to meaningfully analyze keyphrase distribution.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const paragraphs = splitParagraphs(content);\n if (paragraphs.length < MIN_PARAGRAPHS_FOR_ANALYSIS) {\n return {\n id: 'keyphrase-even-distribution',\n title: 'Keyphrase distribution across content',\n description:\n `Only ${paragraphs.length} paragraph(s) found. At least ${MIN_PARAGRAPHS_FOR_ANALYSIS} paragraphs ` +\n 'are needed to analyze distribution across content quarters.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const kp = focusKeyphrase.trim();\n\n // Divide paragraphs into 4 quarters\n const quarters = divideIntoSegments(paragraphs, 4);\n const quarterLabels = ['first quarter', 'second quarter', 'third quarter', 'fourth quarter'];\n const missingQuarters: string[] = [];\n\n for (let i = 0; i < quarters.length; i++) {\n const quarterText = quarters[i]!.join(' ');\n if (!containsKeyphrase(quarterText, kp)) {\n missingQuarters.push(quarterLabels[i]!);\n }\n }\n\n // Check first 10% (hook/introduction) and last 10% (conclusion)\n const plainText = stripHtml(content);\n const tenPercentLength = Math.max(1, Math.floor(plainText.length * 0.1));\n const introText = plainText.slice(0, tenPercentLength);\n const conclusionText = plainText.slice(-tenPercentLength);\n\n const missingZones: string[] = [];\n if (!containsKeyphrase(introText, kp)) {\n missingZones.push('introduction (first 10%)');\n }\n if (!containsKeyphrase(conclusionText, kp)) {\n missingZones.push('conclusion (last 10%)');\n }\n\n const quartersPresent = quarters.length - missingQuarters.length;\n const allZonesPresent = missingZones.length === 0;\n\n // Score: all 4 quarters + intro/conclusion = good; 2-3 quarters = ok; 0-1 = poor\n if (quartersPresent >= 4 && allZonesPresent) {\n return {\n id: 'keyphrase-even-distribution',\n title: 'Keyphrase distribution across content',\n description:\n 'The focus keyphrase is well-distributed across all content sections, including the introduction and conclusion.',\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (quartersPresent >= 2) {\n const missing = [...missingQuarters, ...missingZones];\n return {\n id: 'keyphrase-even-distribution',\n title: 'Keyphrase distribution across content',\n description:\n `The keyphrase is present in ${quartersPresent} of 4 content quarters. ` +\n `It is missing from: ${missing.join(', ')}. ` +\n 'Distribute the keyphrase more evenly for better SEO.',\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n const missing = [...missingQuarters, ...missingZones];\n return {\n id: 'keyphrase-even-distribution',\n title: 'Keyphrase distribution across content',\n description:\n `The keyphrase only appears in ${quartersPresent} of 4 content quarters. ` +\n `Missing from: ${missing.join(', ')}. ` +\n 'The keyphrase should be spread throughout the content for optimal SEO.',\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Single H1 Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml } from '@power-seo/core';\n\ninterface HeadingInfo {\n level: number;\n text: string;\n rawHtml: string;\n}\n\n/**\n * Parse all headings (h1-h6) from HTML using plain string search.\n * Avoids regex ReDoS on crafted inputs.\n */\nfunction parseHeadings(html: string): HeadingInfo[] {\n const headings: HeadingInfo[] = [];\n const lc = html.toLowerCase();\n let pos = 0;\n\n while (pos < lc.length) {\n let earliest = -1;\n let earliestLevel = 0;\n for (let level = 1; level <= 6; level++) {\n const idx = lc.indexOf(`<h${level}`, pos);\n if (idx !== -1 && (earliest === -1 || idx < earliest)) {\n earliest = idx;\n earliestLevel = level;\n }\n }\n if (earliest === -1) break;\n\n const contentStart = lc.indexOf('>', earliest);\n if (contentStart === -1) break;\n\n const closeTag = `</h${earliestLevel}>`;\n const closeIdx = lc.indexOf(closeTag, contentStart + 1);\n if (closeIdx === -1) {\n pos = contentStart + 1;\n continue;\n }\n\n const rawInner = html.slice(contentStart + 1, closeIdx);\n headings.push({\n level: earliestLevel,\n text: stripHtml(rawInner).trim(),\n rawHtml: rawInner,\n });\n pos = closeIdx + closeTag.length;\n }\n\n return headings;\n}\n\n/**\n * Check that the page has exactly 0-1 H1 tags, none are empty or duplicated,\n * and the heading hierarchy is correct (no skipped levels).\n */\nexport function checkSingleH1(input: ContentAnalysisInput): AnalysisResult {\n const { content } = input;\n const headings = parseHeadings(content);\n const h1s = headings.filter((h) => h.level === 1);\n\n const issues: string[] = [];\n let severity: 'good' | 'ok' | 'poor' = 'good';\n\n // --- Multiple H1s ---\n if (h1s.length > 1) {\n issues.push(`Found ${h1s.length} H1 tags. Use exactly one H1 per page.`);\n severity = 'poor';\n }\n\n // --- Empty H1s ---\n const emptyH1s = h1s.filter((h) => h.text.length === 0);\n if (emptyH1s.length > 0) {\n issues.push(\n `Found ${emptyH1s.length} empty H1 tag${emptyH1s.length > 1 ? 's' : ''}. ` +\n 'H1 tags should contain meaningful text.'\n );\n if (severity !== 'poor') severity = 'poor';\n }\n\n // --- Duplicate H1 text ---\n if (h1s.length > 1) {\n const h1Texts = h1s.map((h) => h.text.toLowerCase()).filter((t) => t.length > 0);\n const seen = new Set<string>();\n const duplicates = new Set<string>();\n for (const text of h1Texts) {\n if (seen.has(text)) {\n duplicates.add(text);\n }\n seen.add(text);\n }\n if (duplicates.size > 0) {\n issues.push(\n `Duplicate H1 text found: \"${[...duplicates].join('\", \"')}\". Each H1 should be unique.`\n );\n }\n }\n\n // --- Heading hierarchy check ---\n // Only relevant if there are headings to check\n if (headings.length >= 2) {\n const hierarchyIssues: string[] = [];\n\n // Check if content starts with a non-H1 heading when there are no H1s\n if (h1s.length === 0 && headings.length > 0 && headings[0]!.level > 1) {\n hierarchyIssues.push(\n `Content starts with an H${headings[0]!.level} instead of an H1.`\n );\n }\n\n // Check for skipped levels (e.g., H1 -> H3, skipping H2)\n for (let i = 1; i < headings.length; i++) {\n const prev = headings[i - 1]!;\n const curr = headings[i]!;\n if (curr.level > prev.level + 1) {\n hierarchyIssues.push(\n `H${curr.level} follows H${prev.level}, skipping H${prev.level + 1}.`\n );\n break; // Report only the first skip to avoid noise\n }\n }\n\n if (hierarchyIssues.length > 0) {\n issues.push(\n 'Heading hierarchy issue: ' + hierarchyIssues.join(' ') +\n ' Use sequential heading levels (H1, H2, H3...) for better accessibility and SEO.'\n );\n if (severity === 'good') severity = 'ok';\n }\n }\n\n // --- Build result ---\n if (severity === 'good') {\n const h1Note = h1s.length === 0\n ? 'No H1 tag found in the content body, which is fine if the page title serves as the H1.'\n : 'The page has a single H1 with proper heading hierarchy.';\n return {\n id: 'single-h1',\n title: 'Single H1',\n description: h1Note,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (severity === 'ok') {\n return {\n id: 'single-h1',\n title: 'Single H1',\n description: issues.join(' '),\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'single-h1',\n title: 'Single H1',\n description: issues.join(' '),\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Word Complexity Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords, getSentences, countSyllables, countTotalSyllables } from '@power-seo/core';\n\n/**\n * Dictionary of unnecessarily complex words with simpler alternatives.\n * Keys are lowercase complex words, values are recommended replacements.\n */\nconst COMPLEX_SYNONYMS: Record<string, string> = {\n utilize: 'use',\n approximately: 'about',\n subsequently: 'then',\n commence: 'start',\n facilitate: 'help',\n demonstrate: 'show',\n leverage: 'use',\n modification: 'change',\n necessitate: 'need',\n procure: 'get',\n diminish: 'reduce',\n ascertain: 'find out',\n endeavor: 'try',\n endeavour: 'try',\n elucidate: 'explain',\n expedite: 'speed up',\n formulate: 'create',\n implement: 'do',\n inaugurate: 'begin',\n methodology: 'method',\n notwithstanding: 'despite',\n perpetuate: 'continue',\n prioritize: 'rank',\n promulgate: 'announce',\n substantiate: 'prove',\n terminate: 'end',\n remuneration: 'pay',\n ameliorate: 'improve',\n disseminate: 'spread',\n proliferate: 'spread',\n aforementioned: 'previous',\n henceforth: 'from now on',\n hereinafter: 'below',\n inasmuch: 'because',\n juxtapose: 'compare',\n paradigm: 'model',\n synergy: 'teamwork',\n ubiquitous: 'common',\n cognizant: 'aware',\n enumerate: 'list',\n exacerbate: 'worsen',\n amelioration: 'improvement',\n commencement: 'start',\n discontinue: 'stop',\n effectuate: 'carry out',\n supplementary: 'extra',\n transformative: 'major',\n components: 'parts',\n consequently: 'so',\n functionality: 'features',\n infrastructure: 'system',\n nevertheless: 'still',\n numerous: 'many',\n objectives: 'goals',\n parameters: 'limits',\n specifications: 'specs',\n sufficient: 'enough',\n additional: 'more',\n acquisition: 'purchase',\n};\n\ninterface ComplexWordMatch {\n word: string;\n suggestion: string;\n}\n\n/**\n * Check content readability via Flesch-Kincaid Grade Level and detect\n * unnecessarily complex words that have simpler alternatives.\n *\n * Flesch-Kincaid Grade Level formula:\n * 0.39 * (totalWords / totalSentences) + 11.8 * (totalSyllables / totalWords) - 15.59\n */\nexport function checkWordComplexity(input: ContentAnalysisInput): AnalysisResult {\n const plainText = stripHtml(input.content).trim();\n\n if (!plainText || plainText.length === 0) {\n return {\n id: 'word-complexity',\n title: 'Word complexity',\n description: 'No content to analyze. Add content to get a complexity assessment.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const words = getWords(input.content);\n const sentences = getSentences(input.content);\n\n if (words.length === 0 || sentences.length === 0) {\n return {\n id: 'word-complexity',\n title: 'Word complexity',\n description: 'Not enough content to calculate readability grade. Add more text.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const totalWords = words.length;\n const totalSentences = sentences.length;\n const totalSyllables = countTotalSyllables(input.content);\n\n // Flesch-Kincaid Grade Level\n const gradeLevel =\n 0.39 * (totalWords / totalSentences) +\n 11.8 * (totalSyllables / totalWords) -\n 15.59;\n const roundedGrade = Math.round(gradeLevel * 10) / 10;\n\n // Count complex words (3+ syllables)\n const complexWords: string[] = [];\n for (const word of words) {\n const cleaned = word.toLowerCase().replace(/[^a-z]/g, '');\n if (cleaned.length > 0 && countSyllables(cleaned) >= 3) {\n complexWords.push(cleaned);\n }\n }\n const complexPercentage = Math.round((complexWords.length / totalWords) * 100);\n\n // Deduplicate and get top 10 most frequent complex words\n const complexFrequency = new Map<string, number>();\n for (const w of complexWords) {\n complexFrequency.set(w, (complexFrequency.get(w) || 0) + 1);\n }\n const top10Complex = [...complexFrequency.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, 10)\n .map(([word]) => word);\n\n // Detect unnecessarily complex synonyms\n const foundSynonyms: ComplexWordMatch[] = [];\n const seenSynonyms = new Set<string>();\n for (const word of words) {\n const cleaned = word.toLowerCase().replace(/[^a-z]/g, '');\n if (cleaned && COMPLEX_SYNONYMS[cleaned] && !seenSynonyms.has(cleaned)) {\n seenSynonyms.add(cleaned);\n foundSynonyms.push({\n word: cleaned,\n suggestion: COMPLEX_SYNONYMS[cleaned]!,\n });\n }\n }\n\n // Build description\n const parts: string[] = [];\n parts.push(`Flesch-Kincaid Grade Level: ${roundedGrade}.`);\n parts.push(`${complexPercentage}% of words (${complexWords.length}/${totalWords}) have 3+ syllables.`);\n\n if (top10Complex.length > 0) {\n parts.push(`Most frequent complex words: ${top10Complex.join(', ')}.`);\n }\n\n if (foundSynonyms.length > 0) {\n const suggestions = foundSynonyms\n .slice(0, 5)\n .map((s) => `\"${s.word}\" -> \"${s.suggestion}\"`)\n .join(', ');\n parts.push(\n `Consider simpler alternatives: ${suggestions}${foundSynonyms.length > 5 ? ` (+${foundSynonyms.length - 5} more)` : ''}.`\n );\n }\n\n // Score based on grade level\n if (roundedGrade <= 8) {\n return {\n id: 'word-complexity',\n title: 'Word complexity',\n description: parts.join(' ') + ' The content reads at an accessible grade level.',\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (roundedGrade <= 12) {\n return {\n id: 'word-complexity',\n title: 'Word complexity',\n description:\n parts.join(' ') +\n ' The reading level is moderately advanced. Consider simplifying for a broader audience.',\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'word-complexity',\n title: 'Word complexity',\n description:\n parts.join(' ') +\n ' The reading level is very advanced. Simplify language and shorten sentences for better readability.',\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Inclusive Language Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml } from '@power-seo/core';\n\ntype InclusiveCategory =\n | 'gender'\n | 'ability'\n | 'tech'\n | 'age'\n | 'race/ethnicity'\n | 'violence metaphor';\n\ninterface NonInclusiveTerm {\n term: string;\n replacement: string;\n category: InclusiveCategory;\n}\n\ninterface TermMatch {\n term: string;\n replacement: string;\n category: InclusiveCategory;\n}\n\n/**\n * Comprehensive dictionary of non-inclusive terms with suggested replacements,\n * organized by category.\n */\nconst NON_INCLUSIVE_TERMS: NonInclusiveTerm[] = [\n // --- Gender ---\n { term: 'manpower', replacement: 'workforce', category: 'gender' },\n { term: 'chairman', replacement: 'chairperson', category: 'gender' },\n { term: 'chairmen', replacement: 'chairpersons', category: 'gender' },\n { term: 'fireman', replacement: 'firefighter', category: 'gender' },\n { term: 'firemen', replacement: 'firefighters', category: 'gender' },\n { term: 'mankind', replacement: 'humankind', category: 'gender' },\n { term: 'policeman', replacement: 'police officer', category: 'gender' },\n { term: 'policemen', replacement: 'police officers', category: 'gender' },\n { term: 'stewardess', replacement: 'flight attendant', category: 'gender' },\n { term: 'stewardesses', replacement: 'flight attendants', category: 'gender' },\n { term: 'waitress', replacement: 'server', category: 'gender' },\n { term: 'waitresses', replacement: 'servers', category: 'gender' },\n { term: 'salesman', replacement: 'salesperson', category: 'gender' },\n { term: 'salesmen', replacement: 'salespeople', category: 'gender' },\n { term: 'postman', replacement: 'mail carrier', category: 'gender' },\n { term: 'postmen', replacement: 'mail carriers', category: 'gender' },\n { term: 'man-made', replacement: 'artificial/synthetic', category: 'gender' },\n { term: 'manmade', replacement: 'artificial/synthetic', category: 'gender' },\n { term: 'manhole', replacement: 'maintenance hole', category: 'gender' },\n { term: 'manholes', replacement: 'maintenance holes', category: 'gender' },\n { term: 'freshman', replacement: 'first-year student', category: 'gender' },\n { term: 'freshmen', replacement: 'first-year students', category: 'gender' },\n { term: 'housewife', replacement: 'homemaker', category: 'gender' },\n { term: 'housewives', replacement: 'homemakers', category: 'gender' },\n { term: 'businessman', replacement: 'businessperson', category: 'gender' },\n { term: 'businessmen', replacement: 'businesspeople', category: 'gender' },\n { term: 'congressmen', replacement: 'members of congress', category: 'gender' },\n { term: 'spokesman', replacement: 'spokesperson', category: 'gender' },\n { term: 'spokesmen', replacement: 'spokespersons', category: 'gender' },\n { term: 'craftsman', replacement: 'craftsperson', category: 'gender' },\n { term: 'craftsmen', replacement: 'craftspeople', category: 'gender' },\n { term: 'foreman', replacement: 'supervisor', category: 'gender' },\n\n // --- Ability ---\n { term: 'blind spot', replacement: 'oversight', category: 'ability' },\n { term: 'crippled', replacement: 'impaired/broken', category: 'ability' },\n { term: 'crippling', replacement: 'severely limiting', category: 'ability' },\n { term: 'lame', replacement: 'inadequate', category: 'ability' },\n { term: 'crazy', replacement: 'unexpected/surprising', category: 'ability' },\n { term: 'insane', replacement: 'intense/extreme', category: 'ability' },\n { term: 'handicapped', replacement: 'disabled', category: 'ability' },\n { term: 'wheelchair-bound', replacement: 'wheelchair user', category: 'ability' },\n { term: 'wheelchair bound', replacement: 'wheelchair user', category: 'ability' },\n { term: 'suffers from', replacement: 'has/lives with', category: 'ability' },\n { term: 'suffering from', replacement: 'living with', category: 'ability' },\n { term: 'special needs', replacement: 'disability/disabled', category: 'ability' },\n { term: 'mentally retarded', replacement: 'intellectually disabled', category: 'ability' },\n { term: 'retarded', replacement: 'delayed/impaired', category: 'ability' },\n { term: 'tone deaf', replacement: 'unaware/oblivious', category: 'ability' },\n { term: 'tone-deaf', replacement: 'unaware/oblivious', category: 'ability' },\n { term: 'dumb', replacement: 'silent/mute', category: 'ability' },\n\n // --- Tech ---\n { term: 'master/slave', replacement: 'primary/replica', category: 'tech' },\n { term: 'master slave', replacement: 'primary replica', category: 'tech' },\n { term: 'whitelist', replacement: 'allowlist', category: 'tech' },\n { term: 'whitelisted', replacement: 'added to allowlist', category: 'tech' },\n { term: 'whitelisting', replacement: 'adding to allowlist', category: 'tech' },\n { term: 'blacklist', replacement: 'blocklist', category: 'tech' },\n { term: 'blacklisted', replacement: 'blocked', category: 'tech' },\n { term: 'blacklisting', replacement: 'blocking', category: 'tech' },\n { term: 'sanity check', replacement: 'validation check', category: 'tech' },\n { term: 'dummy value', replacement: 'placeholder value', category: 'tech' },\n { term: 'dummy variable', replacement: 'placeholder variable', category: 'tech' },\n { term: 'native feature', replacement: 'built-in feature', category: 'tech' },\n { term: 'grandfathered', replacement: 'legacy/exempt', category: 'tech' },\n { term: 'grandfather clause', replacement: 'legacy provision', category: 'tech' },\n\n // --- Age ---\n { term: 'elderly', replacement: 'older adults', category: 'age' },\n { term: 'senior citizen', replacement: 'older adult', category: 'age' },\n { term: 'senior citizens', replacement: 'older adults', category: 'age' },\n { term: 'the aged', replacement: 'older people', category: 'age' },\n { term: 'the elderly', replacement: 'older adults', category: 'age' },\n { term: 'old people', replacement: 'older people', category: 'age' },\n\n // --- Race/ethnicity ---\n { term: 'black market', replacement: 'underground market', category: 'race/ethnicity' },\n { term: 'blackball', replacement: 'reject/exclude', category: 'race/ethnicity' },\n { term: 'blackballed', replacement: 'rejected/excluded', category: 'race/ethnicity' },\n { term: 'black sheep', replacement: 'outcast/outlier', category: 'race/ethnicity' },\n { term: 'blackmark', replacement: 'negative record', category: 'race/ethnicity' },\n\n // --- Violence metaphors ---\n { term: 'killing it', replacement: 'excelling', category: 'violence metaphor' },\n { term: 'take a stab at', replacement: 'attempt', category: 'violence metaphor' },\n { term: 'taking a stab at', replacement: 'attempting', category: 'violence metaphor' },\n { term: 'trigger warning', replacement: 'content warning', category: 'violence metaphor' },\n { term: 'pull the trigger', replacement: 'make the decision', category: 'violence metaphor' },\n { term: 'bite the bullet', replacement: 'accept the challenge', category: 'violence metaphor' },\n { term: 'silver bullet', replacement: 'perfect solution', category: 'violence metaphor' },\n { term: 'war room', replacement: 'situation room', category: 'violence metaphor' },\n { term: 'go ballistic', replacement: 'react strongly', category: 'violence metaphor' },\n { term: 'shoot down', replacement: 'reject/dismiss', category: 'violence metaphor' },\n];\n\n/**\n * Find all non-inclusive term matches in the text. Uses word-boundary-aware\n * matching to avoid false positives inside unrelated words.\n */\nfunction findMatches(text: string): TermMatch[] {\n const lowerText = text.toLowerCase();\n const matches: TermMatch[] = [];\n const seen = new Set<string>();\n\n for (const entry of NON_INCLUSIVE_TERMS) {\n if (seen.has(entry.term)) continue;\n\n const termLower = entry.term.toLowerCase();\n let searchPos = 0;\n\n while (searchPos < lowerText.length) {\n const idx = lowerText.indexOf(termLower, searchPos);\n if (idx === -1) break;\n\n // Word boundary checks to avoid partial matches\n const charBefore = idx > 0 ? lowerText[idx - 1]! : ' ';\n const charAfter =\n idx + termLower.length < lowerText.length\n ? lowerText[idx + termLower.length]!\n : ' ';\n\n const isWordBoundaryBefore = /[\\s.,;:!?'\"()-/]/.test(charBefore) || idx === 0;\n const isWordBoundaryAfter =\n /[\\s.,;:!?'\"()-/]/.test(charAfter) || idx + termLower.length === lowerText.length;\n\n if (isWordBoundaryBefore && isWordBoundaryAfter) {\n seen.add(entry.term);\n matches.push({\n term: entry.term,\n replacement: entry.replacement,\n category: entry.category,\n });\n break; // One match per term is sufficient\n }\n\n searchPos = idx + 1;\n }\n }\n\n return matches;\n}\n\n/**\n * Group matches by category for clearer reporting.\n */\nfunction groupByCategory(matches: TermMatch[]): Map<InclusiveCategory, TermMatch[]> {\n const groups = new Map<InclusiveCategory, TermMatch[]>();\n for (const match of matches) {\n const group = groups.get(match.category) || [];\n group.push(match);\n groups.set(match.category, group);\n }\n return groups;\n}\n\n/**\n * Check content for non-inclusive language across six categories:\n * gender, ability, tech, age, race/ethnicity, and violence metaphors.\n *\n * For each match, reports the term found, its category, and a suggested\n * inclusive replacement.\n */\nexport function checkInclusiveLanguage(input: ContentAnalysisInput): AnalysisResult {\n const plainText = stripHtml(input.content).trim();\n\n if (!plainText || plainText.length === 0) {\n return {\n id: 'inclusive-language',\n title: 'Inclusive language',\n description: 'No content to analyze. Add content to check for inclusive language.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n // Also check the title and meta description\n const fullText = [\n input.title || '',\n input.metaDescription || '',\n plainText,\n ].join(' ');\n\n const matches = findMatches(fullText);\n\n if (matches.length === 0) {\n return {\n id: 'inclusive-language',\n title: 'Inclusive language',\n description:\n 'No non-inclusive language detected. Your content uses inclusive terminology.',\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n // Build detailed report\n const grouped = groupByCategory(matches);\n const reportParts: string[] = [];\n\n for (const [category, categoryMatches] of grouped) {\n const items = categoryMatches\n .map((m) => `\"${m.term}\" -> \"${m.replacement}\"`)\n .join(', ');\n reportParts.push(`${category}: ${items}`);\n }\n\n const report = reportParts.join('; ') + '.';\n\n if (matches.length <= 2) {\n return {\n id: 'inclusive-language',\n title: 'Inclusive language',\n description:\n `Found ${matches.length} non-inclusive term${matches.length === 1 ? '' : 's'}. ` +\n `Consider replacing: ${report}`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'inclusive-language',\n title: 'Inclusive language',\n description:\n `Found ${matches.length} non-inclusive terms across your content. ` +\n `Replace the following: ${report}`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Competing Links Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml } from '@power-seo/core';\n\ninterface ParsedLink {\n href: string;\n anchorText: string;\n isExternal: boolean;\n}\n\n/**\n * Extract all <a href> links from HTML, capturing href and anchor text.\n */\nfunction extractLinks(html: string, siteUrl?: string): ParsedLink[] {\n const links: ParsedLink[] = [];\n const linkRegex = /<a\\s[^>]*href=[\"']([^\"'#]+)[\"'][^>]*>([\\s\\S]*?)<\\/a>/gi;\n let match;\n\n while ((match = linkRegex.exec(html)) !== null) {\n const href = match[1]!.trim();\n const rawAnchor = match[2]!;\n\n // Skip non-navigable links\n if (\n !href ||\n href.startsWith('mailto:') ||\n href.startsWith('tel:') ||\n href.startsWith('javascript:')\n ) {\n continue;\n }\n\n const anchorText = stripHtml(rawAnchor).toLowerCase().trim();\n\n // Determine if external\n let isExternal = false;\n if (href.startsWith('/') || href.startsWith('./') || href.startsWith('../')) {\n isExternal = false;\n } else if (siteUrl && href.toLowerCase().startsWith(siteUrl.toLowerCase())) {\n isExternal = false;\n } else if (href.startsWith('http://') || href.startsWith('https://')) {\n isExternal = true;\n }\n\n links.push({ href, anchorText, isExternal });\n }\n\n return links;\n}\n\n/**\n * Check whether anchor text or URL path contains the keyphrase or a close variant.\n * A close variant is checked by matching individual keyphrase words (for multi-word keyphrases).\n */\nfunction matchesKeyphrase(text: string, keyphrase: string): boolean {\n const kpLower = keyphrase.toLowerCase().trim();\n const textLower = text.toLowerCase();\n\n // Exact match\n if (textLower.includes(kpLower)) return true;\n\n // For multi-word keyphrases, check if all significant words appear\n const kpWords = kpLower.split(/\\s+/).filter((w) => w.length > 2);\n if (kpWords.length > 1) {\n const matchingWords = kpWords.filter((w) => textLower.includes(w));\n // Consider it a variant if 80%+ of significant words match\n if (matchingWords.length >= Math.ceil(kpWords.length * 0.8)) return true;\n }\n\n return false;\n}\n\n/**\n * Supporting context patterns — links with these phrases are citations/references,\n * not competing content.\n */\nconst SUPPORTING_PATTERNS = [\n 'learn more about',\n 'read more about',\n 'according to',\n 'source:',\n 'reference:',\n 'cited by',\n 'as reported by',\n 'study by',\n 'research from',\n 'data from',\n 'published by',\n 'via ',\n 'see also',\n];\n\n/**\n * Determine if a link is a supporting reference or a competing link.\n */\nfunction isSupportingLink(anchorText: string): boolean {\n return SUPPORTING_PATTERNS.some((pattern) => anchorText.includes(pattern));\n}\n\n/**\n * Extract the URL path for keyphrase matching in URLs.\n */\nfunction getUrlPath(href: string): string {\n try {\n const url = new URL(href);\n return url.pathname.replace(/[-_/]/g, ' ').toLowerCase();\n } catch {\n return href.replace(/[-_/]/g, ' ').toLowerCase();\n }\n}\n\nexport function checkCompetingLinks(input: ContentAnalysisInput): AnalysisResult {\n const { focusKeyphrase, content, siteUrl } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n return {\n id: 'competing-links',\n title: 'Competing links',\n description: 'No focus keyphrase set. Set one to check for competing links.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const links = extractLinks(content, siteUrl);\n const externalLinks = links.filter((l) => l.isExternal);\n\n const competingLinks: { href: string; anchorText: string }[] = [];\n\n for (const link of externalLinks) {\n const anchorMatches = matchesKeyphrase(link.anchorText, focusKeyphrase);\n const urlMatches = matchesKeyphrase(getUrlPath(link.href), focusKeyphrase);\n\n if ((anchorMatches || urlMatches) && !isSupportingLink(link.anchorText)) {\n competingLinks.push({ href: link.href, anchorText: link.anchorText });\n }\n }\n\n if (competingLinks.length === 0) {\n return {\n id: 'competing-links',\n title: 'Competing links',\n description:\n 'No competing links found. Your external links do not compete with your focus keyphrase.',\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n const linkList = competingLinks\n .map((l) => `\"${l.anchorText || '(no text)'}\" -> ${l.href}`)\n .join('; ');\n\n if (competingLinks.length === 1) {\n return {\n id: 'competing-links',\n title: 'Competing links',\n description: `Found 1 competing external link that targets your focus keyphrase: ${linkList}. Consider removing it or changing the anchor text to avoid sending link equity to a competitor.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'competing-links',\n title: 'Competing links',\n description: `Found ${competingLinks.length} competing external links targeting your focus keyphrase: ${linkList}. These links send link equity to competitors for the same keyword. Remove them or change their anchor text.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Content Freshness Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml } from '@power-seo/core';\n\n/** Current date used for age calculations. */\nconst NOW = new Date('2026-03-23T00:00:00Z');\nconst CURRENT_YEAR = NOW.getFullYear();\n\n/** Milliseconds in a day. */\nconst MS_PER_DAY = 86_400_000;\n\n/**\n * Parse a date value (string or Date) into a Date object, or null if invalid.\n */\nfunction parseDate(value: string | Date | undefined): Date | null {\n if (!value) return null;\n const d = value instanceof Date ? value : new Date(value);\n return isNaN(d.getTime()) ? null : d;\n}\n\n/**\n * Calculate the number of days between two dates.\n */\nfunction daysBetween(a: Date, b: Date): number {\n return Math.abs(a.getTime() - b.getTime()) / MS_PER_DAY;\n}\n\n/**\n * Detect stale temporal references in plain text content.\n */\nfunction findStaleReferences(text: string, publishDate: Date | null): string[] {\n const stale: string[] = [];\n const textLower = text.toLowerCase();\n\n // Check for \"in 20XX\" references where XX is old\n const yearRefRegex = /\\bin\\s+(20[0-9]{2})\\b/gi;\n let match;\n while ((match = yearRefRegex.exec(text)) !== null) {\n const year = parseInt(match[1]!, 10);\n if (year < CURRENT_YEAR - 1) {\n stale.push(`Outdated year reference: \"${match[0]}\"`);\n }\n }\n\n // Check for \"according to a 20XX study\" where XX < current year - 2\n const studyRegex = /according\\s+to\\s+a\\s+(20[0-9]{2})\\s+study/gi;\n while ((match = studyRegex.exec(text)) !== null) {\n const year = parseInt(match[1]!, 10);\n if (year < CURRENT_YEAR - 2) {\n stale.push(`Stale study reference: \"${match[0]}\"`);\n }\n }\n\n // Check \"last year\" — stale if publish date is >1 year old\n if (textLower.includes('last year') && publishDate) {\n const age = daysBetween(NOW, publishDate);\n if (age > 365) {\n stale.push('\"last year\" reference in content older than 1 year');\n }\n }\n\n // Check \"this year\" without specific date context\n if (textLower.includes('this year') && publishDate) {\n const pubYear = publishDate.getFullYear();\n if (pubYear < CURRENT_YEAR) {\n stale.push(`\"this year\" reference but content was published in ${pubYear}`);\n }\n }\n\n // Check \"recently\" in old content (>6 months)\n if (textLower.includes('recently') && publishDate) {\n const age = daysBetween(NOW, publishDate);\n if (age > 180) {\n stale.push('\"recently\" used in content older than 6 months');\n }\n }\n\n // Check \"latest version\" without a specific version number following it\n const latestVersionRegex = /latest\\s+version(?!\\s+\\d)/gi;\n if (latestVersionRegex.test(text)) {\n stale.push('\"latest version\" used without specifying a version number');\n }\n\n return stale;\n}\n\nexport function checkContentFreshness(input: ContentAnalysisInput): AnalysisResult {\n const publishDate = parseDate(input.publishDate);\n const modifiedDate = parseDate(input.modifiedDate);\n\n if (!publishDate && !modifiedDate) {\n return {\n id: 'content-freshness',\n title: 'Content freshness',\n description: 'No publish or modified date available. Set dates to evaluate content freshness.',\n status: 'na',\n score: 0,\n maxScore: 10,\n };\n }\n\n // Calculate content age\n const referenceDate = publishDate || modifiedDate!;\n const ageDays = daysBetween(NOW, referenceDate);\n const ageMonths = ageDays / 30.44; // average days per month\n\n // Check if recently updated\n const updateDays = modifiedDate ? daysBetween(NOW, modifiedDate) : null;\n const updatedWithin3Months = updateDays !== null && updateDays <= 91;\n\n // Detect stale temporal references\n const plainText = stripHtml(input.content);\n const staleRefs = findStaleReferences(plainText, publishDate);\n\n // Build description parts\n const parts: string[] = [];\n\n if (publishDate) {\n parts.push(`Published ${Math.round(ageMonths)} month${Math.round(ageMonths) === 1 ? '' : 's'} ago`);\n }\n if (modifiedDate && updateDays !== null) {\n const updateMonths = Math.round(updateDays / 30.44);\n parts.push(`last updated ${updateMonths} month${updateMonths === 1 ? '' : 's'} ago`);\n }\n\n if (staleRefs.length > 0) {\n parts.push(\n `${staleRefs.length} stale temporal reference${staleRefs.length === 1 ? '' : 's'} found: ${staleRefs.join('; ')}`,\n );\n }\n\n // Determine score\n // Good: < 6 months old OR updated within 3 months\n if (ageMonths < 6 || updatedWithin3Months) {\n return {\n id: 'content-freshness',\n title: 'Content freshness',\n description: `${parts.join('. ')}. Content is fresh${staleRefs.length > 0 ? ', but consider updating the stale references' : ''}.`,\n status: 'good',\n score: 5,\n maxScore: 10,\n };\n }\n\n // OK: 6-12 months without update\n if (ageMonths <= 12) {\n return {\n id: 'content-freshness',\n title: 'Content freshness',\n description: `${parts.join('. ')}. Content is aging — consider reviewing and updating it to maintain relevance.`,\n status: 'ok',\n score: 3,\n maxScore: 10,\n };\n }\n\n // Poor: > 12 months without update\n return {\n id: 'content-freshness',\n title: 'Content freshness',\n description: `${parts.join('. ')}. Content is over 12 months old without a recent update. Refresh it to improve rankings and accuracy.`,\n status: 'poor',\n score: 1,\n maxScore: 10,\n };\n}\n","// @power-seo/content-analysis — Keyphrase Markup Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\n/**\n * Emphasis tags to scan for keyphrase emphasis.\n */\nconst EMPHASIS_TAGS = ['strong', 'b', 'em', 'i', 'mark'] as const;\n\n/**\n * Extract the inner text content of all instances of the given tags in HTML.\n * Returns an array of plain-text strings found inside those tags.\n */\nfunction extractEmphasizedTexts(html: string): string[] {\n const texts: string[] = [];\n\n for (const tag of EMPHASIS_TAGS) {\n const regex = new RegExp(`<${tag}[^>]*>([\\\\s\\\\S]*?)<\\\\/${tag}>`, 'gi');\n let match;\n while ((match = regex.exec(html)) !== null) {\n const inner = match[1]!\n .replace(/<[^>]*>/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n .toLowerCase();\n if (inner.length > 0) {\n texts.push(inner);\n }\n }\n }\n\n return texts;\n}\n\n/**\n * Count total occurrences of a keyphrase in plain text (case-insensitive).\n */\nfunction countOccurrences(text: string, keyphrase: string): number {\n const kpLower = keyphrase.toLowerCase().trim();\n const textLower = text.toLowerCase();\n if (!kpLower) return 0;\n\n let count = 0;\n let pos = 0;\n while ((pos = textLower.indexOf(kpLower, pos)) !== -1) {\n count++;\n pos += kpLower.length;\n }\n\n return count;\n}\n\nexport function checkKeyphraseMarkup(input: ContentAnalysisInput): AnalysisResult {\n const { focusKeyphrase, content } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n return {\n id: 'keyphrase-markup',\n title: 'Keyphrase in emphasis',\n description: 'No focus keyphrase set. Set one to check keyphrase emphasis markup.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const kpLower = focusKeyphrase.toLowerCase().trim();\n\n // Count total keyphrase occurrences in the full content (plain text extraction)\n const plainText = content\n .replace(/<[^>]*>/g, ' ')\n .replace(/\\s+/g, ' ')\n .toLowerCase();\n const totalOccurrences = countOccurrences(plainText, kpLower);\n\n if (totalOccurrences === 0) {\n return {\n id: 'keyphrase-markup',\n title: 'Keyphrase in emphasis',\n description:\n 'The focus keyphrase does not appear in the content, so emphasis cannot be evaluated. Add the keyphrase to your content first.',\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n }\n\n // Count how many times the keyphrase appears inside emphasis tags\n const emphasizedTexts = extractEmphasizedTexts(content);\n let emphasizedCount = 0;\n for (const text of emphasizedTexts) {\n emphasizedCount += countOccurrences(text, kpLower);\n }\n\n const emphasisRatio = totalOccurrences > 0 ? emphasizedCount / totalOccurrences : 0;\n\n // Optimal: 1-2 emphasized instances\n if (emphasizedCount >= 1 && emphasizedCount <= 2) {\n return {\n id: 'keyphrase-markup',\n title: 'Keyphrase in emphasis',\n description: `The focus keyphrase is emphasized ${emphasizedCount} time${emphasizedCount === 1 ? '' : 's'} out of ${totalOccurrences} occurrence${totalOccurrences === 1 ? '' : 's'}. This is optimal for signaling importance to search engines.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n // Not emphasized at all\n if (emphasizedCount === 0) {\n return {\n id: 'keyphrase-markup',\n title: 'Keyphrase in emphasis',\n description: `The focus keyphrase appears ${totalOccurrences} time${totalOccurrences === 1 ? '' : 's'} but is never emphasized with <strong>, <b>, <em>, <i>, or <mark>. Consider bolding or italicizing the keyphrase once to signal its importance.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n // Over-emphasized: >50% of instances are in emphasis tags\n if (emphasisRatio > 0.5) {\n return {\n id: 'keyphrase-markup',\n title: 'Keyphrase in emphasis',\n description: `The focus keyphrase is emphasized ${emphasizedCount} out of ${totalOccurrences} time${totalOccurrences === 1 ? '' : 's'} (${Math.round(emphasisRatio * 100)}%). This is over-emphasized and may appear as keyword stuffing. Reduce emphasis to 1-2 instances.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n }\n\n // More than 2 emphasized but ratio is <=50% — still somewhat excessive\n return {\n id: 'keyphrase-markup',\n title: 'Keyphrase in emphasis',\n description: `The focus keyphrase is emphasized ${emphasizedCount} out of ${totalOccurrences} time${totalOccurrences === 1 ? '' : 's'}. While the ratio is acceptable, consider reducing emphasis to 1-2 instances for optimal signaling.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Headline Analyzer Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { getWords } from '@power-seo/core';\n\n// --- Word Categories ---\n\nconst COMMON_WORDS = new Set([\n 'the', 'is', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for',\n 'of', 'with', 'by', 'from', 'as', 'it', 'that', 'this', 'was', 'are', 'be',\n 'has', 'had', 'have', 'will', 'would', 'could', 'should', 'can', 'may', 'its',\n 'not', 'no', 'up', 'out', 'if', 'how', 'what', 'when', 'where', 'why', 'who',\n 'which', 'all', 'each', 'every', 'do', 'does', 'so', 'than', 'then', 'into',\n 'over', 'after', 'your', 'our', 'my', 'you', 'we', 'they', 'he', 'she',\n]);\n\nconst EMOTIONAL_WORDS = new Set([\n 'amazing', 'devastating', 'thrilling', 'heartbreaking', 'incredible', 'shocking',\n 'terrifying', 'inspiring', 'hilarious', 'painful', 'beautiful', 'horrible',\n 'brilliant', 'awful', 'spectacular', 'tragic', 'magnificent', 'alarming',\n 'delightful', 'frustrating', 'extraordinary', 'overwhelming', 'captivating',\n 'disturbing', 'remarkable',\n]);\n\nconst POWER_WORDS = new Set([\n 'ultimate', 'essential', 'proven', 'powerful', 'effective', 'guaranteed',\n 'instantly', 'revolutionary', 'breakthrough', 'exclusive', 'limited', 'urgent',\n 'secret', 'free', 'new', 'discover', 'master', 'unleash', 'dominate', 'epic',\n 'insane', 'jaw-dropping', 'life-changing', 'mind-blowing',\n]);\n\n/**\n * Categorize a word into one of the four categories.\n */\nfunction categorizeWord(word: string): 'common' | 'emotional' | 'power' | 'uncommon' {\n const lower = word.toLowerCase().replace(/[^a-z-]/g, '');\n if (!lower) return 'common';\n if (EMOTIONAL_WORDS.has(lower)) return 'emotional';\n if (POWER_WORDS.has(lower)) return 'power';\n if (COMMON_WORDS.has(lower)) return 'common';\n return 'uncommon';\n}\n\n/**\n * Comprehensive headline scoring system.\n * Returns a score from 0-100 based on multiple factors.\n */\nfunction analyzeHeadline(title: string): {\n score: number;\n wordCount: number;\n charCount: number;\n commonPct: number;\n uncommonPct: number;\n emotionalPct: number;\n powerWordCount: number;\n hasNumber: boolean;\n isQuestion: boolean;\n hasBrackets: boolean;\n details: string[];\n} {\n const details: string[] = [];\n let score = 0;\n\n const words = getWords(title);\n const wordCount = words.length;\n const charCount = title.length;\n\n // Categorize words\n let commonCount = 0;\n let uncommonCount = 0;\n let emotionalCount = 0;\n let powerWordCount = 0;\n\n for (const word of words) {\n const cat = categorizeWord(word);\n switch (cat) {\n case 'common': commonCount++; break;\n case 'uncommon': uncommonCount++; break;\n case 'emotional': emotionalCount++; break;\n case 'power': powerWordCount++; break;\n }\n }\n\n const commonPct = wordCount > 0 ? Math.round((commonCount / wordCount) * 100) : 0;\n const uncommonPct = wordCount > 0 ? Math.round((uncommonCount / wordCount) * 100) : 0;\n const emotionalPct = wordCount > 0 ? Math.round((emotionalCount / wordCount) * 100) : 0;\n\n // --- Scoring ---\n\n // 1. Word count (max 20 points): 6-13 words is optimal\n if (wordCount >= 6 && wordCount <= 13) {\n score += 20;\n details.push(`Word count (${wordCount}) is in the optimal 6-13 range`);\n } else if (wordCount >= 4 && wordCount <= 15) {\n score += 10;\n details.push(`Word count (${wordCount}) is acceptable but not optimal (aim for 6-13)`);\n } else {\n score += 3;\n details.push(`Word count (${wordCount}) is outside the recommended range (6-13 words)`);\n }\n\n // 2. Character count (max 20 points): 50-60 chars optimal for SERP\n if (charCount >= 50 && charCount <= 60) {\n score += 20;\n details.push(`Character count (${charCount}) is optimal for search engine display`);\n } else if (charCount >= 40 && charCount <= 70) {\n score += 12;\n details.push(`Character count (${charCount}) is acceptable (50-60 is optimal for SERP)`);\n } else if (charCount < 40) {\n score += 5;\n details.push(`Title is too short (${charCount} characters). Aim for 50-60 characters`);\n } else {\n score += 5;\n details.push(`Title may be truncated in SERP (${charCount} characters). Aim for 50-60`);\n }\n\n // 3. Word balance (max 20 points)\n // Ideal: 20-30% common, 10-20% uncommon, some emotional\n if (commonPct >= 20 && commonPct <= 40) {\n score += 8;\n } else if (commonPct < 20) {\n score += 4;\n } else {\n score += 3;\n }\n\n if (uncommonPct >= 10 && uncommonPct <= 40) {\n score += 7;\n } else if (uncommonPct > 0) {\n score += 4;\n }\n\n if (emotionalPct > 0) {\n score += 5;\n details.push(`Contains ${emotionalCount} emotional word${emotionalCount === 1 ? '' : 's'} (${emotionalPct}%)`);\n } else {\n details.push('No emotional words — adding one can improve CTR');\n }\n\n // 4. Power words (max 15 points)\n if (powerWordCount >= 1) {\n score += Math.min(15, powerWordCount * 8);\n details.push(`Contains ${powerWordCount} power word${powerWordCount === 1 ? '' : 's'}`);\n } else {\n details.push('No power words — consider adding one like \"ultimate\", \"proven\", or \"essential\"');\n }\n\n // 5. Bonus features (max 25 points)\n const hasNumber = /\\d/.test(title);\n if (hasNumber) {\n score += 8;\n details.push('Contains a number — numbers increase click-through rates');\n }\n\n const titleLower = title.toLowerCase().trim();\n const isQuestion =\n titleLower.startsWith('how to') ||\n titleLower.startsWith('what is') ||\n titleLower.startsWith('what are') ||\n titleLower.startsWith('why ') ||\n titleLower.startsWith('how ') ||\n titleLower.startsWith('when ') ||\n titleLower.startsWith('where ') ||\n titleLower.startsWith('who ') ||\n titleLower.startsWith('which ') ||\n title.trim().endsWith('?');\n\n if (isQuestion) {\n score += 8;\n details.push('Question format — questions engage reader curiosity');\n }\n\n const hasBrackets = /[[(].*[\\])]/.test(title);\n if (hasBrackets) {\n score += 9;\n details.push('Contains brackets/parentheses — these increase CTR by ~38%');\n }\n\n // Cap at 100\n score = Math.min(100, score);\n\n return {\n score,\n wordCount,\n charCount,\n commonPct,\n uncommonPct,\n emotionalPct,\n powerWordCount,\n hasNumber,\n isQuestion,\n hasBrackets,\n details,\n };\n}\n\nexport function checkHeadlineAnalyzer(input: ContentAnalysisInput): AnalysisResult {\n const { title } = input;\n\n if (!title || title.trim().length === 0) {\n return {\n id: 'headline-analyzer',\n title: 'Headline analyzer',\n description: 'No title provided. Add a title to get a headline analysis.',\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n }\n\n const analysis = analyzeHeadline(title.trim());\n const { score, wordCount, charCount, commonPct, uncommonPct, emotionalPct, powerWordCount, details } = analysis;\n\n const summary = [\n `Headline score: ${score}/100`,\n `${wordCount} words, ${charCount} characters`,\n `Word balance: ${commonPct}% common, ${uncommonPct}% uncommon, ${emotionalPct}% emotional, ${powerWordCount} power word${powerWordCount === 1 ? '' : 's'}`,\n ].join('. ');\n\n const feedback = details.join('. ');\n\n if (score >= 70) {\n return {\n id: 'headline-analyzer',\n title: 'Headline analyzer',\n description: `${summary}. ${feedback}.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (score >= 40) {\n return {\n id: 'headline-analyzer',\n title: 'Headline analyzer',\n description: `${summary}. ${feedback}. Improve the headline to score 70+ for optimal performance.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'headline-analyzer',\n title: 'Headline analyzer',\n description: `${summary}. ${feedback}. This headline needs significant improvement — aim for a score of 70+.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Inbound Internal Links Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\nexport function checkInboundInternalLinks(input: ContentAnalysisInput): AnalysisResult {\n const { inboundInternalLinkCount, isPillarContent } = input;\n\n if (inboundInternalLinkCount === undefined || inboundInternalLinkCount === null) {\n return {\n id: 'inbound-internal-links',\n title: 'Inbound internal links',\n description:\n 'Inbound internal link count is not available. Provide this data to evaluate internal linking health.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const count = inboundInternalLinkCount;\n const pillar = isPillarContent === true;\n\n // --- Pillar Content Thresholds ---\n if (pillar) {\n if (count >= 5) {\n return {\n id: 'inbound-internal-links',\n title: 'Inbound internal links',\n description: `This pillar content has ${count} inbound internal link${count === 1 ? '' : 's'}. Pillar pages should be well-linked, and this meets the recommended minimum of 5.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (count >= 3) {\n return {\n id: 'inbound-internal-links',\n title: 'Inbound internal links',\n description: `This pillar content has ${count} inbound internal link${count === 1 ? '' : 's'}. Pillar pages need strong internal linking — aim for at least 5 inbound links from related cluster content.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n if (count === 0) {\n return {\n id: 'inbound-internal-links',\n title: 'Inbound internal links',\n description:\n 'This pillar content is orphaned — no other pages link to it. Pillar pages are critical hub pages and must have at least 5 inbound internal links from supporting cluster articles.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n\n return {\n id: 'inbound-internal-links',\n title: 'Inbound internal links',\n description: `This pillar content only has ${count} inbound internal link${count === 1 ? '' : 's'}. Pillar pages need at least 5 — add links from related cluster content to strengthen the topic hub.`,\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n\n // --- Normal Content Thresholds ---\n if (count >= 3) {\n return {\n id: 'inbound-internal-links',\n title: 'Inbound internal links',\n description: `This page has ${count} inbound internal link${count === 1 ? '' : 's'}. Good internal linking helps search engines discover and rank your content.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n if (count >= 1) {\n return {\n id: 'inbound-internal-links',\n title: 'Inbound internal links',\n description: `This page has ${count} inbound internal link${count === 1 ? '' : 's'}. Add links from at least ${3 - count} more related page${3 - count === 1 ? '' : 's'} to improve discoverability and distribute link equity.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n // count === 0\n return {\n id: 'inbound-internal-links',\n title: 'Inbound internal links',\n description:\n 'This is orphaned content — no other pages on your site link to it. Search engines may struggle to discover and rank it. Add internal links from at least 3 related pages.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis -- Intent Detection Utilities\n// ----------------------------------------------------------------------------\n\n/** Primary search intent types following Google's intent taxonomy. */\nexport type IntentType =\n | 'informational'\n | 'navigational'\n | 'transactional'\n | 'commercial-investigation'\n | 'unknown';\n\n/** Sub-intent categories that refine the primary intent. */\nexport type IntentSubType =\n | 'definitional'\n | 'tutorial'\n | 'troubleshooting'\n | 'comparison'\n | 'review-seeking'\n | 'purchase'\n | 'download'\n | 'local'\n | 'reference'\n | 'news'\n | 'unknown';\n\n/** A modifier token found in the keyphrase and the intent it signals. */\nexport interface IntentModifier {\n word: string;\n signalsIntent: IntentType;\n}\n\n/** An individual intent signal detected from the keyphrase. */\nexport interface IntentSignal {\n type: IntentType;\n confidence: number;\n reason: string;\n}\n\n/** Full result returned by detectIntent. */\nexport interface IntentResult {\n primary: IntentType;\n confidence: number;\n subType: IntentSubType;\n modifiers: IntentModifier[];\n signals: IntentSignal[];\n}\n\n// ---------------------------------------------------------------------------\n// Modifier dictionaries\n// ---------------------------------------------------------------------------\n\nconst INFORMATIONAL_MODIFIERS: readonly string[] = [\n 'what', 'how', 'why', 'when', 'where', 'who', 'which',\n 'guide', 'tutorial', 'tips', 'learn', 'example', 'examples',\n 'definition', 'meaning', 'explained', 'overview', 'introduction',\n 'basics', 'fundamentals', 'understanding', 'difference', 'differences',\n 'ways', 'ideas', 'steps', 'methods', 'techniques', 'strategies',\n 'benefits', 'advantages', 'disadvantages', 'pros', 'cons',\n 'causes', 'effects', 'history', 'types', 'list',\n];\n\nconst TRANSACTIONAL_MODIFIERS: readonly string[] = [\n 'buy', 'purchase', 'order', 'shop', 'deal', 'deals',\n 'discount', 'coupon', 'price', 'pricing', 'cheap', 'cheapest',\n 'affordable', 'free', 'download', 'subscribe', 'sign up', 'signup',\n 'register', 'hire', 'book', 'reserve', 'get', 'sale',\n 'promo', 'offer', 'shipping', 'delivery',\n];\n\nconst COMMERCIAL_MODIFIERS: readonly string[] = [\n 'best', 'top', 'review', 'reviews', 'comparison', 'compare',\n 'vs', 'versus', 'alternative', 'alternatives', 'recommended',\n 'rating', 'ratings', 'ranked', 'ranking', 'winner',\n 'most popular', 'leading', 'premium', 'professional',\n 'enterprise', 'budget', 'worth', 'quality',\n];\n\nconst NAVIGATIONAL_MODIFIERS: readonly string[] = [\n 'login', 'log in', 'signin', 'sign in', 'website', 'site',\n 'official', 'homepage', 'app', 'portal', 'dashboard',\n 'account', 'contact', 'support', 'help', 'docs', 'documentation',\n 'api', 'download page',\n];\n\nconst TROUBLESHOOTING_MODIFIERS: readonly string[] = [\n 'fix', 'error', 'issue', 'problem', 'not working',\n 'troubleshoot', 'troubleshooting', 'debug', 'resolve',\n 'solution', 'solved', 'stuck', 'broken', 'crash', 'bug',\n 'fails', 'failure', 'wrong', 'help',\n];\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nfunction findModifiers(keyphrase: string): IntentModifier[] {\n const lower = keyphrase.toLowerCase();\n const found: IntentModifier[] = [];\n\n const scan = (words: readonly string[], intent: IntentType): void => {\n for (const w of words) {\n // Use word boundary matching to avoid partial matches (e.g. \"site\" in \"website\")\n const escaped = w.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const re = new RegExp(`(?:^|\\\\b)${escaped}(?:\\\\b|$)`);\n if (re.test(lower)) {\n found.push({ word: w, signalsIntent: intent });\n }\n }\n };\n\n scan(INFORMATIONAL_MODIFIERS, 'informational');\n scan(TRANSACTIONAL_MODIFIERS, 'transactional');\n scan(COMMERCIAL_MODIFIERS, 'commercial-investigation');\n scan(NAVIGATIONAL_MODIFIERS, 'navigational');\n scan(TROUBLESHOOTING_MODIFIERS, 'informational'); // troubleshooting is informational\n\n return found;\n}\n\nfunction inferSubType(keyphrase: string, primary: IntentType): IntentSubType {\n const lower = keyphrase.toLowerCase();\n\n if (/\\b(what\\s+is|definition|meaning|define|explained)\\b/.test(lower)) {\n return 'definitional';\n }\n if (/\\b(how\\s+to|tutorial|guide|step[\\s-]by[\\s-]step|walkthrough)\\b/.test(lower)) {\n return 'tutorial';\n }\n if (/\\b(fix|error|issue|problem|not\\s+working|troubleshoot|debug|resolve)\\b/.test(lower)) {\n return 'troubleshooting';\n }\n if (/\\b(vs|versus|compare|comparison|difference|differences|alternative|alternatives)\\b/.test(lower)) {\n return 'comparison';\n }\n if (/\\b(review|reviews|rating|ratings|best|top|recommended|worth\\s+it)\\b/.test(lower)) {\n return 'review-seeking';\n }\n if (/\\b(buy|purchase|order|shop|deal|price|pricing|coupon|discount|sale)\\b/.test(lower)) {\n return 'purchase';\n }\n if (/\\b(download|install|free\\s+download|get\\s+free)\\b/.test(lower)) {\n return 'download';\n }\n if (/\\b(near\\s+me|nearby|local|in\\s+\\w+|city|town|neighborhood)\\b/.test(lower)) {\n return 'local';\n }\n if (/\\b(list|types|examples?|resources?|tools?|reference)\\b/.test(lower)) {\n return 'reference';\n }\n if (/\\b(news|update|latest|breaking|announcement|release|launched|2026|2025)\\b/.test(lower)) {\n return 'news';\n }\n\n if (primary === 'transactional') return 'purchase';\n if (primary === 'commercial-investigation') return 'review-seeking';\n if (primary === 'navigational') return 'unknown';\n\n return 'unknown';\n}\n\nfunction buildSignals(modifiers: IntentModifier[], keyphrase: string): IntentSignal[] {\n const intentScores = new Map<IntentType, { total: number; reasons: string[] }>();\n\n for (const mod of modifiers) {\n const entry = intentScores.get(mod.signalsIntent);\n if (entry) {\n entry.total += 1;\n entry.reasons.push('\"' + mod.word + '\"');\n } else {\n intentScores.set(mod.signalsIntent, { total: 1, reasons: ['\"' + mod.word + '\"'] });\n }\n }\n\n // If no modifiers found, assign baseline signals for bare keywords\n if (intentScores.size === 0) {\n const wordCount = keyphrase.trim().split(/\\s+/).length;\n if (wordCount <= 2) {\n intentScores.set('navigational', {\n total: 1,\n reasons: ['short bare keyword, possibly a brand or entity'],\n });\n }\n intentScores.set('informational', {\n total: 1,\n reasons: ['default: bare keyword with no clear modifiers'],\n });\n }\n\n const totalPoints = Array.from(intentScores.values()).reduce((s, v) => s + v.total, 0);\n\n const signals: IntentSignal[] = [];\n for (const [type, data] of intentScores) {\n signals.push({\n type,\n confidence: totalPoints > 0 ? Number((data.total / totalPoints).toFixed(2)) : 0,\n reason: data.reasons.join(', '),\n });\n }\n\n // Sort by confidence descending\n signals.sort((a, b) => b.confidence - a.confidence);\n\n return signals;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Detect the search intent of a focus keyphrase.\n *\n * Analyzes modifier words, phrase patterns, and structural cues to determine\n * the primary intent type, sub-type, confidence score, and any ambiguity.\n */\nexport function detectIntent(keyphrase: string): IntentResult {\n const trimmed = keyphrase.trim();\n\n if (trimmed.length === 0) {\n return {\n primary: 'unknown',\n confidence: 0,\n subType: 'unknown',\n modifiers: [],\n signals: [],\n };\n }\n\n const modifiers = findModifiers(trimmed);\n const signals = buildSignals(modifiers, trimmed);\n\n const topSignal: IntentSignal | undefined = signals[0];\n const primary: IntentType = topSignal?.type ?? 'unknown';\n const confidence: number = topSignal?.confidence ?? 0;\n\n const subType = inferSubType(trimmed, primary);\n\n return {\n primary,\n confidence,\n subType,\n modifiers,\n signals,\n };\n}\n","// @power-seo/content-analysis -- Keyword Intent Classification Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\n/** Map intent types to human-friendly strategy explanations. */\nconst INTENT_EXPLANATIONS: Record<string, string> = {\n informational:\n 'Users want to learn or understand something. Create comprehensive, educational content with clear explanations.',\n navigational:\n 'Users are looking for a specific website or page. Ensure strong brand signals and clear site structure.',\n transactional:\n 'Users are ready to take action (buy, download, sign up). Optimize for conversions with clear CTAs and trust signals.',\n 'commercial-investigation':\n 'Users are researching before a purchase decision. Provide comparisons, reviews, and evidence-based recommendations.',\n unknown:\n 'Intent could not be clearly determined. Consider adding intent-signaling modifiers to sharpen your keyphrase.',\n};\n\nexport function checkIntentKeywordClassification(input: ContentAnalysisInput): AnalysisResult {\n const { focusKeyphrase } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n return {\n id: 'intent-keyword-classification',\n title: 'Keyword intent classification',\n description: 'No focus keyphrase set. Set one to analyze keyword intent.',\n status: 'na',\n score: 0,\n maxScore: 10,\n };\n }\n\n const result = detectIntent(focusKeyphrase);\n const explanation: string =\n INTENT_EXPLANATIONS[result.primary] ?? INTENT_EXPLANATIONS['unknown'] ?? '';\n const pct = Math.round(result.confidence * 100);\n\n if (result.confidence >= 0.7) {\n return {\n id: 'intent-keyword-classification',\n title: 'Keyword intent classification',\n description: `Clear ${result.primary} intent detected (${pct}% confidence). ${explanation}`,\n status: 'good',\n score: 5,\n maxScore: 10,\n };\n }\n\n if (result.confidence >= 0.4) {\n return {\n id: 'intent-keyword-classification',\n title: 'Keyword intent classification',\n description:\n `Likely ${result.primary} intent, but confidence is moderate (${pct}%). ${explanation}` +\n ' Consider adding clearer intent modifiers to strengthen the signal.',\n status: 'ok',\n score: 3,\n maxScore: 10,\n };\n }\n\n return {\n id: 'intent-keyword-classification',\n title: 'Keyword intent classification',\n description:\n `Weak intent signal (${pct}% confidence for ${result.primary}). ${explanation}` +\n ' Add modifier words like \"how to\", \"best\", \"buy\", or \"review\" to clarify intent.',\n status: 'poor',\n score: 1,\n maxScore: 10,\n };\n}\n","// @power-seo/content-analysis -- Intent Sub-Type Detection Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\n/** Maps sub-types to the content format they require. */\nconst SUB_TYPE_FORMATS: Record<string, string> = {\n definitional:\n 'Use a concise definition in the first paragraph, followed by expanded explanation. Target featured snippets with a clear \"X is...\" sentence.',\n tutorial:\n 'Structure content as numbered steps with clear instructions. Include code samples, screenshots, or diagrams where appropriate.',\n troubleshooting:\n 'Lead with the problem statement, then provide solutions in order of likelihood. Include error messages verbatim for search matching.',\n comparison:\n 'Use a side-by-side format with a comparison table. Cover pricing, features, pros/cons, and a clear recommendation.',\n 'review-seeking':\n 'Include hands-on experience, ratings, pros/cons lists, and a verdict. Add schema markup for reviews.',\n purchase:\n 'Optimize for conversions: prominent CTAs, pricing, availability, trust badges, and shipping information.',\n download:\n 'Provide a clear download button/link, system requirements, file size, and version information.',\n local:\n 'Include address, hours, map embed, and local schema markup. Mention the specific location in title and headings.',\n reference:\n 'Create a well-organized list or resource page with brief descriptions. Use anchor links for easy navigation.',\n news:\n 'Use an inverted pyramid structure (most important info first). Include dates, sources, and NewsArticle schema.',\n unknown:\n 'Sub-type could not be determined. The primary intent was detected but the specific content format needed is unclear.',\n};\n\nexport function checkIntentSubType(input: ContentAnalysisInput): AnalysisResult {\n const { focusKeyphrase } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n return {\n id: 'intent-sub-type',\n title: 'Intent sub-type detection',\n description: 'No focus keyphrase set. Set one to detect intent sub-type.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const result = detectIntent(focusKeyphrase);\n const formatAdvice: string =\n SUB_TYPE_FORMATS[result.subType] ?? SUB_TYPE_FORMATS['unknown'] ?? '';\n\n if (result.subType !== 'unknown') {\n return {\n id: 'intent-sub-type',\n title: 'Intent sub-type detection',\n description: `Sub-type detected: ${result.subType}. ${formatAdvice}`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n // subType is unknown but we may still have a primary intent\n if (result.primary !== 'unknown') {\n return {\n id: 'intent-sub-type',\n title: 'Intent sub-type detection',\n description:\n `Primary intent is ${result.primary}, but the specific sub-type is unclear. ${formatAdvice}` +\n ' Try adding a more specific modifier (e.g., \"how to\", \"vs\", \"review\", \"buy\") to clarify the expected content format.',\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'intent-sub-type',\n title: 'Intent sub-type detection',\n description:\n `Cannot determine intent sub-type for \"${focusKeyphrase}\". ${formatAdvice}` +\n ' Refine the keyphrase with descriptive modifiers so the required content format is clear.',\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis -- Intent Modifier Analysis Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\n/** Human-readable labels for intent types. */\nconst INTENT_LABELS: Record<string, string> = {\n informational: 'informational intent',\n navigational: 'navigational intent',\n transactional: 'transactional/action intent',\n 'commercial-investigation': 'commercial investigation intent',\n unknown: 'unclear intent',\n};\n\nexport function checkIntentModifierAnalysis(input: ContentAnalysisInput): AnalysisResult {\n const { focusKeyphrase } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n return {\n id: 'intent-modifier-analysis',\n title: 'Intent modifier analysis',\n description: 'No focus keyphrase set. Set one to analyze intent modifiers.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const result = detectIntent(focusKeyphrase);\n const modifiers = result.modifiers;\n\n if (modifiers.length === 0) {\n return {\n id: 'intent-modifier-analysis',\n title: 'Intent modifier analysis',\n description:\n 'No intent modifier words found in the keyphrase. Bare keywords are harder to optimize ' +\n 'because search engines must guess user intent. Add modifiers like \"how to\", \"best\", ' +\n '\"buy\", \"review\", \"vs\", or \"guide\" to signal clear intent.',\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n }\n\n // Build a deduplicated summary of modifiers grouped by intent\n const byIntent = new Map<string, string[]>();\n for (const mod of modifiers) {\n const label: string = INTENT_LABELS[mod.signalsIntent] ?? 'unclear intent';\n const existing = byIntent.get(label);\n if (existing) {\n if (!existing.includes(mod.word)) {\n existing.push(mod.word);\n }\n } else {\n byIntent.set(label, [mod.word]);\n }\n }\n\n const parts: string[] = [];\n for (const [label, words] of byIntent) {\n const quoted = words.map(w => '\"' + w + '\"').join(', ');\n parts.push(quoted + ' (' + label + ')');\n }\n\n const summary = 'Modifiers found: ' + parts.join('; ') + '.';\n\n if (modifiers.length >= 2) {\n return {\n id: 'intent-modifier-analysis',\n title: 'Intent modifier analysis',\n description:\n modifiers.length + ' intent modifiers detected. ' + summary +\n ' Multiple modifiers give search engines strong signals about what the user expects.',\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n // Exactly 1 modifier\n const firstMod = modifiers[0];\n const singleLabel: string = firstMod\n ? (INTENT_LABELS[firstMod.signalsIntent] ?? 'unclear intent')\n : 'unclear intent';\n\n return {\n id: 'intent-modifier-analysis',\n title: 'Intent modifier analysis',\n description:\n '1 intent modifier detected. ' + summary +\n ' A single modifier signals ' + singleLabel +\n ', but adding a second modifier would strengthen the intent signal and help search engines ' +\n 'match your content more precisely.',\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis -- Multi-Intent Detection Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\n/** Human-readable labels for intent types. */\nconst INTENT_LABELS: Record<string, string> = {\n informational: 'informational',\n navigational: 'navigational',\n transactional: 'transactional',\n 'commercial-investigation': 'commercial investigation',\n unknown: 'unknown',\n};\n\nexport function checkIntentMultiDetection(input: ContentAnalysisInput): AnalysisResult {\n const { focusKeyphrase } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n return {\n id: 'intent-multi-detection',\n title: 'Multi-intent detection',\n description: 'No focus keyphrase set. Set one to check for mixed intent signals.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const result = detectIntent(focusKeyphrase);\n const signals = result.signals;\n\n // Count how many distinct intent types have meaningful confidence (> 0)\n const meaningfulSignals = signals.filter(s => s.confidence > 0 && s.type !== 'unknown');\n const count = meaningfulSignals.length;\n\n if (count <= 1) {\n // Single clear intent\n const primary: { type: string; confidence: number } | undefined = meaningfulSignals[0];\n const label: string = primary ? (INTENT_LABELS[primary.type] ?? primary.type) : 'unknown';\n const pct = primary ? Math.round(primary.confidence * 100) : 0;\n\n return {\n id: 'intent-multi-detection',\n title: 'Multi-intent detection',\n description:\n 'Single clear intent detected: ' + label + ' (' + pct + '% confidence). ' +\n 'No ambiguity found. Search engines can confidently match this keyphrase to the right content type.',\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n // Build descriptions of each signal\n const signalDescriptions = meaningfulSignals.map(s => {\n const label: string = INTENT_LABELS[s.type] ?? s.type;\n return label + ' (' + Math.round(s.confidence * 100) + '%)';\n });\n\n if (count === 2) {\n const primary: { type: string; confidence: number } | undefined = meaningfulSignals[0];\n const secondary: { type: string; confidence: number } | undefined = meaningfulSignals[1];\n\n if (!primary || !secondary) {\n return {\n id: 'intent-multi-detection',\n title: 'Multi-intent detection',\n description: 'Could not fully analyze intent signals. Consider refining your keyphrase.',\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n // Check if secondary is weak enough to not be a real conflict\n if (secondary.confidence < 0.3) {\n const primaryLabel: string = INTENT_LABELS[primary.type] ?? primary.type;\n const secondaryLabel: string = INTENT_LABELS[secondary.type] ?? secondary.type;\n\n return {\n id: 'intent-multi-detection',\n title: 'Multi-intent detection',\n description:\n 'Mild ambiguity: primary intent is ' + primaryLabel +\n ' (' + Math.round(primary.confidence * 100) + '%) with a weak secondary signal for ' +\n secondaryLabel + ' (' + Math.round(secondary.confidence * 100) +\n '%). Your content can address both by leading with ' + primaryLabel +\n ' content and including a brief ' + secondaryLabel + ' section.',\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n // Two competing intents\n const primaryLabel: string = INTENT_LABELS[primary.type] ?? primary.type;\n const secondaryLabel: string = INTENT_LABELS[secondary.type] ?? secondary.type;\n\n return {\n id: 'intent-multi-detection',\n title: 'Multi-intent detection',\n description:\n 'Competing intents detected: ' + signalDescriptions.join(' vs. ') +\n '. The keyphrase signals both ' + primaryLabel + ' and ' + secondaryLabel +\n ' intent nearly equally. Consider splitting into two pages or narrowing the keyphrase ' +\n 'to target one intent. For example, add \"how to\" for informational or \"buy\" for transactional.',\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n }\n\n // 3+ conflicting intents\n return {\n id: 'intent-multi-detection',\n title: 'Multi-intent detection',\n description:\n 'Heavily ambiguous keyphrase with ' + count + ' conflicting intent signals: ' +\n signalDescriptions.join(', ') +\n '. Search engines will struggle to determine what content to serve. ' +\n 'Narrow your keyphrase by removing ambiguous words or adding a clear intent modifier ' +\n 'to target a single intent type.',\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Content-Intent Alignment Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\n// ---------------------------------------------------------------------------\n// Intent Signal Phrases\n// ---------------------------------------------------------------------------\n\nconst INFORMATIONAL_SIGNALS: readonly string[] = [\n 'how to', 'what is', 'guide', 'learn', 'understand', 'explained',\n 'definition', 'steps', 'tutorial', 'tips', 'example', 'for example',\n 'such as', 'in this article', \"we'll cover\", \"you'll learn\",\n \"let's explore\", 'introduction',\n] as const;\n\nconst TRANSACTIONAL_SIGNALS: readonly string[] = [\n 'buy', 'purchase', 'order', 'add to cart', 'shop', 'deal', 'discount',\n 'price', 'pricing', '$', 'free shipping', 'checkout', 'subscribe',\n 'sign up', 'get started', 'try free', 'limited time', 'in stock',\n 'available now',\n] as const;\n\nconst COMMERCIAL_SIGNALS: readonly string[] = [\n 'best', 'top', 'review', 'compared', 'comparison', 'vs', 'versus',\n 'pros and cons', 'advantages', 'disadvantages', 'rating', 'rated',\n 'recommend', 'our pick', \"editor's choice\", 'winner', 'runner-up',\n 'alternative',\n] as const;\n\nconst NAVIGATIONAL_SIGNALS: readonly string[] = [\n 'official', 'login', 'sign in', 'dashboard', 'my account', 'support',\n 'contact us', 'help center', 'visit', 'go to', 'homepage',\n] as const;\n\n// ---------------------------------------------------------------------------\n// Signal list lookup\n// ---------------------------------------------------------------------------\n\ntype IntentCategory = 'informational' | 'navigational' | 'transactional' | 'commercial-investigation' | 'unknown';\n\nfunction getSignalsForIntent(intent: IntentCategory): readonly string[] {\n switch (intent) {\n case 'informational':\n return INFORMATIONAL_SIGNALS;\n case 'transactional':\n return TRANSACTIONAL_SIGNALS;\n case 'commercial-investigation':\n return COMMERCIAL_SIGNALS;\n case 'navigational':\n return NAVIGATIONAL_SIGNALS;\n default:\n return INFORMATIONAL_SIGNALS;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Count signal matches in a text segment\n// ---------------------------------------------------------------------------\n\nfunction countSignals(text: string, signals: readonly string[]): number {\n let count = 0;\n for (const signal of signals) {\n if (signal === '$') {\n // Special case: dollar sign is not a word, just check presence\n if (text.includes('$')) {\n count++;\n }\n } else {\n const escaped = signal.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const re = new RegExp(`(?:^|\\\\b)${escaped}(?:\\\\b|$)`, 'i');\n if (re.test(text)) {\n count++;\n }\n }\n }\n return count;\n}\n\n// ---------------------------------------------------------------------------\n// Section analysis\n// ---------------------------------------------------------------------------\n\ninterface SectionResult {\n introSignals: number;\n bodySignals: number;\n conclusionSignals: number;\n totalSignals: number;\n sectionsWithSignals: number;\n}\n\nfunction analyzeBySection(words: string[], signals: readonly string[]): SectionResult {\n const totalWords = words.length;\n if (totalWords === 0) {\n return { introSignals: 0, bodySignals: 0, conclusionSignals: 0, totalSignals: 0, sectionsWithSignals: 0 };\n }\n\n // Split into 3 sections: first 20%, middle 50%, last 30%\n const introEnd = Math.max(1, Math.floor(totalWords * 0.2));\n const bodyEnd = Math.max(introEnd + 1, Math.floor(totalWords * 0.7));\n\n const introText = words.slice(0, introEnd).join(' ');\n const bodyText = words.slice(introEnd, bodyEnd).join(' ');\n const conclusionText = words.slice(bodyEnd).join(' ');\n\n const introSignals = countSignals(introText, signals);\n const bodySignals = countSignals(bodyText, signals);\n const conclusionSignals = countSignals(conclusionText, signals);\n const totalSignals = introSignals + bodySignals + conclusionSignals;\n\n let sectionsWithSignals = 0;\n if (introSignals > 0) sectionsWithSignals++;\n if (bodySignals > 0) sectionsWithSignals++;\n if (conclusionSignals > 0) sectionsWithSignals++;\n\n return { introSignals, bodySignals, conclusionSignals, totalSignals, sectionsWithSignals };\n}\n\n// ---------------------------------------------------------------------------\n// Check\n// ---------------------------------------------------------------------------\n\nexport function checkIntentContentAlignment(input: ContentAnalysisInput): AnalysisResult {\n const { focusKeyphrase, content } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n return {\n id: 'intent-content-alignment',\n title: 'Content-intent alignment',\n description: 'No focus keyphrase set. Set one to evaluate content-intent alignment.',\n status: 'na',\n score: 0,\n maxScore: 10,\n };\n }\n\n const detected = detectIntent(focusKeyphrase);\n const signals = getSignalsForIntent(detected.primary);\n const plainText = stripHtml(content);\n const words = getWords(plainText);\n const result = analyzeBySection(words, signals);\n\n const intentLabel = detected.primary === 'commercial-investigation' ? 'commercial' : detected.primary;\n\n // good (5): 5+ signals spread across sections (2+ sections)\n if (result.totalSignals >= 5 && result.sectionsWithSignals >= 2) {\n return {\n id: 'intent-content-alignment',\n title: 'Content-intent alignment',\n description: `Content aligns well with ${intentLabel} intent. Found ${result.totalSignals} intent signals spread across ${result.sectionsWithSignals} section${result.sectionsWithSignals === 1 ? '' : 's'} (intro: ${result.introSignals}, body: ${result.bodySignals}, conclusion: ${result.conclusionSignals}).`,\n status: 'good',\n score: 5,\n maxScore: 10,\n };\n }\n\n // ok (3): 2-4 signals OR 5+ concentrated in one section\n if (result.totalSignals >= 2) {\n const concentrated = result.sectionsWithSignals <= 1 && result.totalSignals >= 5;\n const detail = concentrated\n ? `Signals are concentrated in one section — distribute them across intro, body, and conclusion`\n : `Add more ${intentLabel} intent signals throughout the content`;\n\n return {\n id: 'intent-content-alignment',\n title: 'Content-intent alignment',\n description: `Partial ${intentLabel} intent alignment. Found ${result.totalSignals} intent signal${result.totalSignals === 1 ? '' : 's'} in ${result.sectionsWithSignals} section${result.sectionsWithSignals === 1 ? '' : 's'}. ${detail}.`,\n status: 'ok',\n score: 3,\n maxScore: 10,\n };\n }\n\n // poor (0): 0-1 signals\n return {\n id: 'intent-content-alignment',\n title: 'Content-intent alignment',\n description: `Content does not match ${intentLabel} intent. Found only ${result.totalSignals} intent signal${result.totalSignals === 1 ? '' : 's'}. Add ${intentLabel} language throughout the content to align with the keyphrase intent.`,\n status: 'poor',\n score: 0,\n maxScore: 10,\n };\n}\n","// @power-seo/content-analysis — Title-Intent Match Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\n// ---------------------------------------------------------------------------\n// Intent-specific title signal detectors\n// ---------------------------------------------------------------------------\n\nfunction hasInformationalTitleSignals(title: string): { strong: boolean; weak: boolean } {\n const lower = title.toLowerCase();\n\n // Strong: question words, \"How to\", \"Guide\", \"Tutorial\", \"Tips\"\n const questionPattern = /^(?:how|what|why|when|where|who|which)\\b/i;\n const strongPattern = /\\b(?:how to|guide|tutorial|tips|explained|walkthrough)\\b/i;\n const numberListPattern = /\\b\\d+\\s+(?:ways|steps|tips|tricks|methods|reasons|things|examples|ideas)\\b/i;\n\n const hasStrong = questionPattern.test(lower) || strongPattern.test(lower) || numberListPattern.test(lower);\n\n // Weak: \"learn\", \"understand\", \"introduction\", \"basics\", \"overview\"\n const weakPattern = /\\b(?:learn|understand|introduction|basics|overview|101|beginners?|faq)\\b/i;\n const hasWeak = weakPattern.test(lower);\n\n return { strong: hasStrong, weak: hasWeak };\n}\n\nfunction hasTransactionalTitleSignals(title: string): { strong: boolean; weak: boolean } {\n const lower = title.toLowerCase();\n\n // Strong: action words, price/currency, \"Free\", \"Deal\"\n const strongPattern = /\\b(?:buy|order|get|shop|purchase|deal|free|discount|sale|subscribe)\\b/i;\n const pricePattern = /\\$\\d|€\\d|\\d+%\\s*off/i;\n\n const hasStrong = strongPattern.test(lower) || pricePattern.test(lower);\n\n // Weak: \"affordable\", \"cheap\", \"cost\", \"pricing\"\n const weakPattern = /\\b(?:affordable|cheap|cheapest|cost|pricing|price|coupon|promo|offer)\\b/i;\n const hasWeak = weakPattern.test(lower);\n\n return { strong: hasStrong, weak: hasWeak };\n}\n\nfunction hasCommercialTitleSignals(title: string): { strong: boolean; weak: boolean } {\n const lower = title.toLowerCase();\n\n // Strong: \"Best\", \"Top\", \"Review\", \"vs\", \"Compared\", year\n const strongPattern = /\\b(?:best|top|review|reviews|vs|versus|compared|comparison)\\b/i;\n const yearPattern = /\\b20(?:2[4-9]|[3-9]\\d)\\b/;\n\n const hasStrong = strongPattern.test(lower) || yearPattern.test(lower);\n\n // Weak: \"pros and cons\", \"alternatives\", \"rated\", \"rating\"\n const weakPattern = /\\b(?:pros and cons|alternatives?|rated|rating|recommend|pick|choice|winner)\\b/i;\n const hasWeak = weakPattern.test(lower);\n\n return { strong: hasStrong, weak: hasWeak };\n}\n\nfunction hasNavigationalTitleSignals(title: string, keyphrase: string): { strong: boolean; weak: boolean } {\n const lower = title.toLowerCase();\n\n // Strong: \"Official\", \"Login\", brand name (from keyphrase)\n const strongPattern = /\\b(?:official|login|log in|sign in)\\b/i;\n const keyphraseWords = getWords(stripHtml(keyphrase.toLowerCase()));\n // Brand presence: check if keyphrase words appear in the title\n const brandPresent = keyphraseWords.length > 0 &&\n keyphraseWords.every((w) => lower.includes(w));\n\n const hasStrong = strongPattern.test(lower) || brandPresent;\n\n // Weak: \"dashboard\", \"account\", \"support\", \"homepage\"\n const weakPattern = /\\b(?:dashboard|account|support|contact|homepage|portal|help)\\b/i;\n const hasWeak = weakPattern.test(lower);\n\n return { strong: hasStrong, weak: hasWeak };\n}\n\n// ---------------------------------------------------------------------------\n// Check\n// ---------------------------------------------------------------------------\n\nexport function checkIntentTitleMatch(input: ContentAnalysisInput): AnalysisResult {\n const { focusKeyphrase, title } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n return {\n id: 'intent-title-match',\n title: 'Title-intent match',\n description: 'No focus keyphrase set. Set one to evaluate title-intent alignment.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n if (!title || title.trim().length === 0) {\n return {\n id: 'intent-title-match',\n title: 'Title-intent match',\n description: 'No title provided. Add a title to evaluate intent alignment.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n\n const detected = detectIntent(focusKeyphrase);\n const intentLabel = detected.primary === 'commercial-investigation' ? 'commercial' : detected.primary;\n\n let signals: { strong: boolean; weak: boolean };\n\n switch (detected.primary) {\n case 'informational':\n signals = hasInformationalTitleSignals(title);\n break;\n case 'transactional':\n signals = hasTransactionalTitleSignals(title);\n break;\n case 'commercial-investigation':\n signals = hasCommercialTitleSignals(title);\n break;\n case 'navigational':\n signals = hasNavigationalTitleSignals(title, focusKeyphrase);\n break;\n default:\n signals = hasInformationalTitleSignals(title);\n }\n\n // good (5): title clearly signals intent\n if (signals.strong) {\n return {\n id: 'intent-title-match',\n title: 'Title-intent match',\n description: `Title clearly signals ${intentLabel} intent. This helps search engines and users understand the page purpose.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n // ok (3): partial/weak intent signal\n if (signals.weak) {\n return {\n id: 'intent-title-match',\n title: 'Title-intent match',\n description: `Title has a weak ${intentLabel} intent signal. Strengthen it by using clearer ${intentLabel} language in the title.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n // poor (0): no intent signal\n return {\n id: 'intent-title-match',\n title: 'Title-intent match',\n description: `Title does not signal ${intentLabel} intent. Rewrite it to include ${intentLabel}-appropriate language so users and search engines can identify the page purpose.`,\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Meta Description-Intent Match Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\n\nimport { detectIntent } from './intent-utils.js';\n\n// ---------------------------------------------------------------------------\n// Intent-specific meta signal patterns\n// ---------------------------------------------------------------------------\n\nconst META_SIGNALS: Record<string, readonly string[]> = {\n informational: [\n 'how to', 'what is', 'learn', 'guide', 'discover', 'understand',\n 'explained', 'tutorial', 'tips', 'steps', 'find out', 'introduction',\n 'overview', 'basics', 'everything you need to know',\n ],\n transactional: [\n 'buy', 'purchase', 'order', 'shop', 'deal', 'discount', 'price',\n 'pricing', 'free shipping', 'subscribe', 'sign up', 'get started',\n 'try free', 'limited time', 'in stock', 'available now', 'save',\n 'offer', '$',\n ],\n 'commercial-investigation': [\n 'best', 'top', 'review', 'compared', 'comparison', 'vs', 'versus',\n 'pros and cons', 'advantages', 'disadvantages', 'rating', 'rated',\n 'recommend', 'our pick', 'alternative', 'winner',\n ],\n navigational: [\n 'official', 'login', 'sign in', 'dashboard', 'my account', 'support',\n 'contact us', 'help center', 'visit', 'go to', 'homepage', 'access',\n ],\n};\n\n// Intent-appropriate CTAs\nconst CTA_SIGNALS: Record<string, readonly string[]> = {\n informational: [\n 'learn', 'discover', 'find out', 'explore', 'read more', 'see how',\n 'get the guide', 'start learning',\n ],\n transactional: [\n 'shop now', 'order today', 'get', 'buy now', 'subscribe today',\n 'sign up now', 'start your free', 'claim your', 'grab your',\n 'don\\'t miss',\n ],\n 'commercial-investigation': [\n 'compare', 'see our picks', 'read our review', 'find the best',\n 'see the results', 'view comparison', 'check out our',\n ],\n navigational: [\n 'visit', 'access', 'go to', 'log in to', 'sign in to', 'get to',\n ],\n};\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction countSignalMatches(text: string, signals: readonly string[]): number {\n let count = 0;\n for (const signal of signals) {\n if (signal === '$') {\n if (text.includes('$')) count++;\n } else {\n const escaped = signal.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const re = new RegExp(`(?:^|\\\\b)${escaped}(?:\\\\b|$)`, 'i');\n if (re.test(text)) count++;\n }\n }\n return count;\n}\n\nfunction hasAnyCta(text: string, ctas: readonly string[]): boolean {\n for (const cta of ctas) {\n const escaped = cta.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const re = new RegExp(`(?:^|\\\\b)${escaped}(?:\\\\b|$)`, 'i');\n if (re.test(text)) return true;\n }\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Check\n// ---------------------------------------------------------------------------\n\nexport function checkIntentMetaMatch(input: ContentAnalysisInput): AnalysisResult {\n const { focusKeyphrase, metaDescription } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n return {\n id: 'intent-meta-match',\n title: 'Meta description-intent match',\n description: 'No focus keyphrase set. Set one to evaluate meta description-intent alignment.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n if (!metaDescription || metaDescription.trim().length === 0) {\n return {\n id: 'intent-meta-match',\n title: 'Meta description-intent match',\n description: 'No meta description provided. Add one to evaluate intent alignment.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n\n const detected = detectIntent(focusKeyphrase);\n const intentLabel = detected.primary === 'commercial-investigation' ? 'commercial' : detected.primary;\n\n const signals = META_SIGNALS[detected.primary] ?? META_SIGNALS['informational']!;\n const ctas = CTA_SIGNALS[detected.primary] ?? CTA_SIGNALS['informational']!;\n\n const metaLower = metaDescription.toLowerCase();\n const signalCount = countSignalMatches(metaLower, signals);\n const hasCta = hasAnyCta(metaLower, ctas);\n\n // good (5): meta description aligns with intent + has CTA\n if (signalCount >= 1 && hasCta) {\n return {\n id: 'intent-meta-match',\n title: 'Meta description-intent match',\n description: `Meta description aligns with ${intentLabel} intent and includes an appropriate call to action. Found ${signalCount} intent signal${signalCount === 1 ? '' : 's'} and a CTA.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n // ok (3): partial alignment (signals but no CTA, or CTA but weak signals)\n if (signalCount >= 1 || hasCta) {\n const missing = signalCount >= 1\n ? 'Add an intent-appropriate CTA to improve click-through rate'\n : `Add ${intentLabel} intent language to the meta description`;\n\n return {\n id: 'intent-meta-match',\n title: 'Meta description-intent match',\n description: `Meta description partially aligns with ${intentLabel} intent. ${missing}.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n // poor (0): no alignment\n return {\n id: 'intent-meta-match',\n title: 'Meta description-intent match',\n description: `Meta description does not align with ${intentLabel} intent. Rewrite it to include ${intentLabel} language and an appropriate call to action.`,\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Heading Structure-Intent Match Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\n// ---------------------------------------------------------------------------\n// Intent-specific heading language patterns\n// ---------------------------------------------------------------------------\n\nconst HEADING_SIGNALS: Record<string, readonly string[]> = {\n informational: [\n 'what', 'how', 'why', 'when', 'step', 'tip', 'example', 'guide',\n 'overview', 'introduction', 'basics', 'definition', 'explained',\n 'understanding', 'learn', 'tutorial', 'walkthrough', 'faq',\n ],\n transactional: [\n 'price', 'pricing', 'features', 'specs', 'specifications', 'order',\n 'buy', 'shipping', 'delivery', 'payment', 'checkout', 'subscribe',\n 'plan', 'plans', 'package', 'packages', 'cost', 'deal', 'offer',\n ],\n 'commercial-investigation': [\n 'best', 'top', 'pros', 'cons', 'review', 'comparison', 'alternative',\n 'vs', 'versus', 'compared', 'advantages', 'disadvantages', 'rating',\n 'verdict', 'winner', 'runner-up', 'recommendation', 'pick',\n ],\n navigational: [\n 'contact', 'support', 'about', 'login', 'sign in', 'account',\n 'dashboard', 'help', 'getting started', 'resources', 'documentation',\n ],\n};\n\n// ---------------------------------------------------------------------------\n// Heading extraction\n// ---------------------------------------------------------------------------\n\nfunction extractHeadings(html: string): string[] {\n const headings: string[] = [];\n const regex = /<h[23][^>]*>([\\s\\S]*?)<\\/h[23]>/gi;\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(html)) !== null) {\n const rawContent = match[1];\n if (rawContent !== undefined) {\n const cleaned = stripHtml(rawContent).trim();\n if (cleaned.length > 0) {\n headings.push(cleaned);\n }\n }\n }\n\n return headings;\n}\n\n// ---------------------------------------------------------------------------\n// Check if a heading contains intent-aligned language\n// ---------------------------------------------------------------------------\n\nfunction isHeadingAligned(heading: string, signals: readonly string[]): boolean {\n const lower = heading.toLowerCase();\n for (const signal of signals) {\n const escaped = signal.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const re = new RegExp(`(?:^|\\\\b)${escaped}(?:\\\\b|$)`, 'i');\n if (re.test(lower)) {\n return true;\n }\n }\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Check\n// ---------------------------------------------------------------------------\n\nexport function checkIntentHeadingMatch(input: ContentAnalysisInput): AnalysisResult {\n const { focusKeyphrase, content } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n return {\n id: 'intent-heading-match',\n title: 'Heading structure-intent match',\n description: 'No focus keyphrase set. Set one to evaluate heading-intent alignment.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const detected = detectIntent(focusKeyphrase);\n const intentLabel = detected.primary === 'commercial-investigation' ? 'commercial' : detected.primary;\n const signals = HEADING_SIGNALS[detected.primary] ?? HEADING_SIGNALS['informational']!;\n\n const headings = extractHeadings(content);\n\n if (headings.length === 0) {\n return {\n id: 'intent-heading-match',\n title: 'Heading structure-intent match',\n description: `No H2 or H3 headings found. Add headings with ${intentLabel} intent language to improve content structure and alignment.`,\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n\n let alignedCount = 0;\n for (const heading of headings) {\n if (isHeadingAligned(heading, signals)) {\n alignedCount++;\n }\n }\n\n const alignedPct = (alignedCount / headings.length) * 100;\n\n // good (5): >= 30% of headings aligned\n if (alignedPct >= 30) {\n return {\n id: 'intent-heading-match',\n title: 'Heading structure-intent match',\n description: `${alignedCount} of ${headings.length} headings (${Math.round(alignedPct)}%) contain ${intentLabel} intent language. Heading structure aligns well with the detected intent.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n // ok (3): 15-29% aligned\n if (alignedPct >= 15) {\n return {\n id: 'intent-heading-match',\n title: 'Heading structure-intent match',\n description: `${alignedCount} of ${headings.length} headings (${Math.round(alignedPct)}%) contain ${intentLabel} intent language. Add more ${intentLabel}-aligned language to your H2/H3 headings.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n // poor (0): < 15% aligned\n return {\n id: 'intent-heading-match',\n title: 'Heading structure-intent match',\n description: `Only ${alignedCount} of ${headings.length} heading${headings.length === 1 ? '' : 's'} (${Math.round(alignedPct)}%) contain ${intentLabel} intent language. Restructure headings to reflect the ${intentLabel} intent of the keyphrase.`,\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Opening Paragraph Intent Signal Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\n// ---------------------------------------------------------------------------\n// Intent-specific opening signal patterns\n// ---------------------------------------------------------------------------\n\n/** Informational: poses a question OR defines the topic OR states what reader will learn */\nconst INFORMATIONAL_STRONG: readonly RegExp[] = [\n // Question patterns\n /\\b(?:what is|what are|how to|how do|how does|how can|why do|why does|why is)\\b/i,\n // Definition patterns\n /\\b(?:is defined as|refers to|is a type of|means that|is known as)\\b/i,\n // Learning promise patterns\n /\\b(?:you(?:'ll| will) learn|we(?:'ll| will) (?:cover|explore|explain)|in this (?:article|guide|tutorial|post))\\b/i,\n /\\b(?:this guide|this tutorial|this article) (?:will|covers|explains|shows)\\b/i,\n];\n\nconst INFORMATIONAL_WEAK: readonly RegExp[] = [\n /\\b(?:learn|understand|discover|find out|explore)\\b/i,\n /\\b(?:tips|steps|guide|tutorial|introduction|overview)\\b/i,\n /\\?/,\n];\n\n/** Transactional: mentions product/service/price OR presents an offer */\nconst TRANSACTIONAL_STRONG: readonly RegExp[] = [\n /\\b(?:buy|purchase|order|shop|subscribe|sign up|get started)\\b/i,\n /\\$\\d+|\\d+%\\s*off|\\bfree shipping\\b|\\blimited time\\b/i,\n /\\b(?:add to cart|checkout|in stock|available now|try free)\\b/i,\n /\\b(?:deal|discount|offer|sale|promo|coupon)\\b/i,\n];\n\nconst TRANSACTIONAL_WEAK: readonly RegExp[] = [\n /\\b(?:price|pricing|cost|affordable|cheap|value)\\b/i,\n /\\b(?:product|service|solution|tool|platform)\\b/i,\n /\\b(?:features|plans?|packages?|subscription)\\b/i,\n];\n\n/** Commercial: frames a comparison OR mentions evaluating options */\nconst COMMERCIAL_STRONG: readonly RegExp[] = [\n /\\b(?:best|top \\d+|compare|comparison|vs|versus)\\b/i,\n /\\b(?:pros and cons|advantages and disadvantages)\\b/i,\n /\\b(?:we (?:reviewed|tested|compared|evaluated))\\b/i,\n /\\b(?:which (?:is|are) (?:best|better|right))\\b/i,\n];\n\nconst COMMERCIAL_WEAK: readonly RegExp[] = [\n /\\b(?:review|alternative|option|choice|pick|rated|rating)\\b/i,\n /\\b(?:looking for|searching for|trying to find|choosing|evaluating)\\b/i,\n /\\b(?:recommend|recommendation|suggest)\\b/i,\n];\n\n/** Navigational: directs to the resource */\nconst NAVIGATIONAL_STRONG: readonly RegExp[] = [\n /\\b(?:official|log ?in|sign ?in|go to|visit)\\b/i,\n /\\b(?:access your|your (?:account|dashboard))\\b/i,\n /\\b(?:welcome to|you(?:'ve| have) reached)\\b/i,\n];\n\nconst NAVIGATIONAL_WEAK: readonly RegExp[] = [\n /\\b(?:support|help|contact|homepage|portal|dashboard)\\b/i,\n /\\b(?:click here|navigate to|find us at)\\b/i,\n];\n\n// ---------------------------------------------------------------------------\n// Pattern matching helper\n// ---------------------------------------------------------------------------\n\nfunction matchesAny(text: string, patterns: readonly RegExp[]): boolean {\n for (const pattern of patterns) {\n if (pattern.test(text)) return true;\n }\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Check\n// ---------------------------------------------------------------------------\n\nexport function checkIntentOpeningMatch(input: ContentAnalysisInput): AnalysisResult {\n const { focusKeyphrase, content } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n return {\n id: 'intent-opening-match',\n title: 'Opening paragraph intent signal',\n description: 'No focus keyphrase set. Set one to evaluate opening paragraph intent alignment.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const detected = detectIntent(focusKeyphrase);\n const intentLabel = detected.primary === 'commercial-investigation' ? 'commercial' : detected.primary;\n\n const plainText = stripHtml(content);\n const allWords = getWords(plainText);\n\n // Extract first 150 words\n const openingWords = allWords.slice(0, 150);\n\n if (openingWords.length === 0) {\n return {\n id: 'intent-opening-match',\n title: 'Opening paragraph intent signal',\n description: 'Content is empty. Add content to evaluate opening paragraph intent.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n\n const openingText = openingWords.join(' ');\n\n let strongPatterns: readonly RegExp[];\n let weakPatterns: readonly RegExp[];\n\n switch (detected.primary) {\n case 'informational':\n strongPatterns = INFORMATIONAL_STRONG;\n weakPatterns = INFORMATIONAL_WEAK;\n break;\n case 'transactional':\n strongPatterns = TRANSACTIONAL_STRONG;\n weakPatterns = TRANSACTIONAL_WEAK;\n break;\n case 'commercial-investigation':\n strongPatterns = COMMERCIAL_STRONG;\n weakPatterns = COMMERCIAL_WEAK;\n break;\n case 'navigational':\n strongPatterns = NAVIGATIONAL_STRONG;\n weakPatterns = NAVIGATIONAL_WEAK;\n break;\n default:\n strongPatterns = INFORMATIONAL_STRONG;\n weakPatterns = INFORMATIONAL_WEAK;\n }\n\n const hasStrongSignal = matchesAny(openingText, strongPatterns);\n const hasWeakSignal = matchesAny(openingText, weakPatterns);\n\n // good (5): clear intent signal in first 150 words\n if (hasStrongSignal) {\n return {\n id: 'intent-opening-match',\n title: 'Opening paragraph intent signal',\n description: `The opening clearly establishes ${intentLabel} intent. This helps readers and search engines understand the page purpose immediately.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n // ok (3): weak/partial signal\n if (hasWeakSignal) {\n return {\n id: 'intent-opening-match',\n title: 'Opening paragraph intent signal',\n description: `The opening has a weak ${intentLabel} intent signal. Strengthen the first 150 words by clearly establishing the ${intentLabel} purpose of the content.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n // poor (0): no intent signal or contradicting signal\n return {\n id: 'intent-opening-match',\n title: 'Opening paragraph intent signal',\n description: `The opening paragraph does not signal ${intentLabel} intent. Rewrite the first 150 words to clearly establish the ${intentLabel} purpose so readers and search engines can identify the page intent.`,\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Conclusion-Intent Alignment Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\n// ---------------------------------------------------------------------------\n// Intent-specific conclusion resolution patterns\n// ---------------------------------------------------------------------------\n\n/** Informational: summary patterns */\nconst INFORMATIONAL_STRONG: readonly RegExp[] = [\n /\\b(?:in conclusion|to summarize|key takeaway|final thoughts|in summary)\\b/i,\n /\\b(?:to wrap up|to sum up|the bottom line|in short)\\b/i,\n /\\b(?:now you (?:know|understand)|we(?:'ve| have) covered)\\b/i,\n /\\b(?:as (?:we(?:'ve| have)|you(?:'ve| have)) (?:seen|learned))\\b/i,\n];\n\nconst INFORMATIONAL_WEAK: readonly RegExp[] = [\n /\\b(?:overall|ultimately|lastly|finally|remember)\\b/i,\n /\\b(?:keep in mind|don't forget|the (?:main|key) (?:point|thing))\\b/i,\n /\\b(?:takeaway|recap|summary)\\b/i,\n];\n\n/** Transactional: CTA patterns */\nconst TRANSACTIONAL_STRONG: readonly RegExp[] = [\n /\\b(?:buy now|order today|get started|sign up|don't miss)\\b/i,\n /\\b(?:shop now|subscribe today|claim your|grab your)\\b/i,\n /\\b(?:start your free|try (?:it )?(?:now|today|free))\\b/i,\n /\\b(?:act now|limited time|order (?:now|yours))\\b/i,\n];\n\nconst TRANSACTIONAL_WEAK: readonly RegExp[] = [\n /\\b(?:ready to|what are you waiting for|take the next step)\\b/i,\n /\\b(?:don't wait|available (?:now|today)|get yours)\\b/i,\n /\\b(?:purchase|checkout|add to cart|place your order)\\b/i,\n];\n\n/** Commercial: recommendation patterns */\nconst COMMERCIAL_STRONG: readonly RegExp[] = [\n /\\b(?:we recommend|our (?:top )?pick|the winner|best overall|verdict)\\b/i,\n /\\b(?:our recommendation|editor's choice|top choice)\\b/i,\n /\\b(?:the clear winner|our favorite|best (?:option|choice|value))\\b/i,\n];\n\nconst COMMERCIAL_WEAK: readonly RegExp[] = [\n /\\b(?:if you(?:'re| are) looking for|the best (?:for|in))\\b/i,\n /\\b(?:choose|go with|opt for|consider|runner-up)\\b/i,\n /\\b(?:depending on your (?:needs|budget)|it depends)\\b/i,\n /\\b(?:all things considered|when it comes to)\\b/i,\n];\n\n/** Navigational: direct link reference */\nconst NAVIGATIONAL_STRONG: readonly RegExp[] = [\n /\\b(?:visit|go to|access|log ?in|sign ?in)\\b/i,\n /\\b(?:click (?:here|the link|below)|head (?:to|over))\\b/i,\n /https?:\\/\\//i,\n];\n\nconst NAVIGATIONAL_WEAK: readonly RegExp[] = [\n /\\b(?:for more (?:information|help|details)|contact us)\\b/i,\n /\\b(?:support|help center|official)\\b/i,\n /\\b(?:reach out|get in touch)\\b/i,\n];\n\n// ---------------------------------------------------------------------------\n// Pattern matching helper\n// ---------------------------------------------------------------------------\n\nfunction matchesAny(text: string, patterns: readonly RegExp[]): boolean {\n for (const pattern of patterns) {\n if (pattern.test(text)) return true;\n }\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Check\n// ---------------------------------------------------------------------------\n\nexport function checkIntentConclusionMatch(input: ContentAnalysisInput): AnalysisResult {\n const { focusKeyphrase, content } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n return {\n id: 'intent-conclusion-match',\n title: 'Conclusion-intent alignment',\n description: 'No focus keyphrase set. Set one to evaluate conclusion-intent alignment.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const detected = detectIntent(focusKeyphrase);\n const intentLabel = detected.primary === 'commercial-investigation' ? 'commercial' : detected.primary;\n\n const plainText = stripHtml(content);\n const allWords = getWords(plainText);\n\n // Extract last 150 words\n const startIndex = Math.max(0, allWords.length - 150);\n const conclusionWords = allWords.slice(startIndex);\n\n if (conclusionWords.length === 0) {\n return {\n id: 'intent-conclusion-match',\n title: 'Conclusion-intent alignment',\n description: 'Content is empty. Add content to evaluate conclusion-intent alignment.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n\n const conclusionText = conclusionWords.join(' ');\n\n let strongPatterns: readonly RegExp[];\n let weakPatterns: readonly RegExp[];\n\n switch (detected.primary) {\n case 'informational':\n strongPatterns = INFORMATIONAL_STRONG;\n weakPatterns = INFORMATIONAL_WEAK;\n break;\n case 'transactional':\n strongPatterns = TRANSACTIONAL_STRONG;\n weakPatterns = TRANSACTIONAL_WEAK;\n break;\n case 'commercial-investigation':\n strongPatterns = COMMERCIAL_STRONG;\n weakPatterns = COMMERCIAL_WEAK;\n break;\n case 'navigational':\n strongPatterns = NAVIGATIONAL_STRONG;\n weakPatterns = NAVIGATIONAL_WEAK;\n break;\n default:\n strongPatterns = INFORMATIONAL_STRONG;\n weakPatterns = INFORMATIONAL_WEAK;\n }\n\n const hasStrongSignal = matchesAny(conclusionText, strongPatterns);\n const hasWeakSignal = matchesAny(conclusionText, weakPatterns);\n\n // good (5): conclusion properly resolves intent\n if (hasStrongSignal) {\n return {\n id: 'intent-conclusion-match',\n title: 'Conclusion-intent alignment',\n description: `The conclusion properly resolves the ${intentLabel} intent. This reinforces the page purpose and satisfies user expectations.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n // ok (3): partial resolution\n if (hasWeakSignal) {\n return {\n id: 'intent-conclusion-match',\n title: 'Conclusion-intent alignment',\n description: `The conclusion partially resolves ${intentLabel} intent. Strengthen the final 150 words with a clearer ${intentLabel} resolution.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n // poor (0): no resolution or drops intent\n return {\n id: 'intent-conclusion-match',\n title: 'Conclusion-intent alignment',\n description: `The conclusion does not resolve the ${intentLabel} intent. End the content with a clear ${intentLabel} resolution so readers leave with their intent fulfilled.`,\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Informational Content Completeness Check\n// ----------------------------------------------------------------------------\n// Checks whether informational content covers the elements readers expect:\n// definitions, examples, subtopics, takeaways, citations, visuals, and depth.\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\ninterface CompletenessElement {\n name: string;\n present: boolean;\n}\n\nexport function checkIntentInformationalCompleteness(\n input: ContentAnalysisInput,\n): AnalysisResult {\n const id = 'intent-informational-completeness';\n const title = 'Informational content completeness';\n\n // No keyphrase — cannot determine intent\n if (!input.focusKeyphrase || input.focusKeyphrase.trim().length === 0) {\n return { id, title, description: 'No focus keyphrase set.', status: 'na', score: 0, maxScore: 5 };\n }\n\n // Only applies to informational intent\n const intent = detectIntent(input.focusKeyphrase);\n if (intent.primary !== 'informational') {\n return {\n id,\n title,\n description: `Detected intent is \"${intent.primary}\" — this check only applies to informational content.`,\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const content = input.content;\n const contentLower = content.toLowerCase();\n const plainText = stripHtml(content);\n const plainTextLower = plainText.toLowerCase();\n const words = getWords(content);\n const wordCount = words.length;\n\n const elements: CompletenessElement[] = [];\n\n // 1. Definitions / explanations\n const hasDefinitions = /\\b(?:is a|refers to|means|defined as|in other words|simply put)\\b/i.test(plainText);\n elements.push({ name: 'Definitions/explanations', present: hasDefinitions });\n\n // 2. Examples\n const hasExamples = /\\b(?:for example|for instance|such as|e\\.g\\.|consider)\\b/i.test(plainText)\n || /\\blike\\b/i.test(plainTextLower);\n elements.push({ name: 'Examples', present: hasExamples });\n\n // 3. Subtopics coverage (>= 3 H2/H3 headings)\n const h2Matches = contentLower.split('<h2').length - 1;\n const h3Matches = contentLower.split('<h3').length - 1;\n const headingCount = h2Matches + h3Matches;\n elements.push({ name: 'Subtopics (3+ headings)', present: headingCount >= 3 });\n\n // 4. Actionable takeaways\n const hasTakeaways = /\\b(?:key takeaway|in summary|bottom line|action step|next step|to summarize|remember)\\b/i.test(plainText);\n elements.push({ name: 'Actionable takeaways', present: hasTakeaways });\n\n // 5. Source citations (external links >= 2)\n const externalLinkRegex = /<a\\s[^>]*href\\s*=\\s*[\"']https?:\\/\\//gi;\n const externalLinkMatches = content.match(externalLinkRegex);\n const externalLinkCount = externalLinkMatches ? externalLinkMatches.length : 0;\n elements.push({ name: 'Source citations (2+ external links)', present: externalLinkCount >= 2 });\n\n // 6. Visual aids (images >= 1)\n const imgCount = contentLower.split('<img').length - 1;\n elements.push({ name: 'Visual aids (images)', present: imgCount >= 1 });\n\n // 7. Depth (word count >= 1000)\n elements.push({ name: 'Depth (1000+ words)', present: wordCount >= 1000 });\n\n // Tally present elements\n const presentElements = elements.filter((e) => e.present);\n const presentCount = presentElements.length;\n const missingElements = elements.filter((e) => !e.present);\n\n // Score: 1 point per element, capped at 5\n const score = Math.min(presentCount, 5);\n\n // Build description\n const presentList = presentElements.map((e) => e.name).join(', ');\n const missingList = missingElements.map((e) => e.name).join(', ');\n\n let description: string;\n if (presentCount >= 5) {\n description = `Excellent informational completeness (${presentCount}/7 elements). Present: ${presentList}.`;\n if (missingElements.length > 0) {\n description += ` Consider also adding: ${missingList}.`;\n }\n } else if (presentCount >= 3) {\n description = `Acceptable informational completeness (${presentCount}/7 elements). Present: ${presentList}. Missing: ${missingList}.`;\n } else {\n description = `Informational content lacks completeness (${presentCount}/7 elements).${presentCount > 0 ? ` Present: ${presentList}.` : ''} Missing: ${missingList}.`;\n }\n\n let status: 'good' | 'ok' | 'poor';\n if (presentCount >= 5) {\n status = 'good';\n } else if (presentCount >= 3) {\n status = 'ok';\n } else {\n status = 'poor';\n }\n\n return { id, title, description, status, score, maxScore: 5 };\n}\n","// @power-seo/content-analysis — Transactional Content Elements Check\n// ----------------------------------------------------------------------------\n// Checks whether transactional content includes the elements buyers expect:\n// pricing, specs, availability, CTAs, trust signals, shipping, payments,\n// and reviews/ratings.\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\ninterface TransactionalElement {\n name: string;\n present: boolean;\n}\n\nexport function checkIntentTransactionalElements(\n input: ContentAnalysisInput,\n): AnalysisResult {\n const id = 'intent-transactional-elements';\n const title = 'Transactional content elements';\n\n // No keyphrase — cannot determine intent\n if (!input.focusKeyphrase || input.focusKeyphrase.trim().length === 0) {\n return { id, title, description: 'No focus keyphrase set.', status: 'na', score: 0, maxScore: 5 };\n }\n\n // Only applies to transactional intent\n const intent = detectIntent(input.focusKeyphrase);\n if (intent.primary !== 'transactional') {\n return {\n id,\n title,\n description: `Detected intent is \"${intent.primary}\" — this check only applies to transactional content.`,\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const plainText = stripHtml(input.content);\n const plainTextLower = plainText.toLowerCase();\n\n const elements: TransactionalElement[] = [];\n\n // 1. Price / cost mentions\n const hasPricing = /\\$\\d/.test(plainText)\n || /\\b(?:price|cost|pricing)\\b/i.test(plainText)\n || /(?:USD|EUR|GBP|CAD|AUD)\\s*\\d/i.test(plainText)\n || /\\d+\\.\\d{2}\\b/.test(plainText);\n elements.push({ name: 'Price/cost mentions', present: hasPricing });\n\n // 2. Product specs\n const hasSpecs = /\\b(?:specifications|features|dimensions|weight|material|compatibility)\\b/i.test(plainText);\n elements.push({ name: 'Product specifications', present: hasSpecs });\n\n // 3. Availability\n const hasAvailability = /\\b(?:in stock|available|ships|delivery|ready to ship)\\b/i.test(plainText);\n elements.push({ name: 'Availability info', present: hasAvailability });\n\n // 4. Purchase CTAs\n const hasCTAs = /\\b(?:buy now|add to cart|order|get started|try free|start trial)\\b/i.test(plainText);\n elements.push({ name: 'Purchase CTAs', present: hasCTAs });\n\n // 5. Trust signals\n const hasTrust = /\\b(?:guarantee|warranty|money-back|secure|verified|certified|free returns)\\b/i.test(plainText);\n elements.push({ name: 'Trust signals', present: hasTrust });\n\n // 6. Shipping info\n const hasShipping = /\\b(?:free shipping|delivery|ships within|express|standard shipping)\\b/i.test(plainText);\n elements.push({ name: 'Shipping information', present: hasShipping });\n\n // 7. Payment options\n const hasPayment = /\\b(?:pay with|credit card|paypal|payment plan|installment|financing)\\b/i.test(plainText);\n elements.push({ name: 'Payment options', present: hasPayment });\n\n // 8. Reviews / ratings\n const hasReviews = /\\b(?:review|rating|stars|customer|testimonial)\\b/i.test(plainTextLower);\n elements.push({ name: 'Reviews/ratings', present: hasReviews });\n\n // Tally present elements\n const presentElements = elements.filter((e) => e.present);\n const presentCount = presentElements.length;\n const missingElements = elements.filter((e) => !e.present);\n\n // Scoring\n let score: number;\n let status: 'good' | 'ok' | 'poor';\n\n if (presentCount >= 5) {\n score = 5;\n status = 'good';\n } else if (presentCount >= 3) {\n score = 3;\n status = 'ok';\n } else {\n score = 1;\n status = 'poor';\n }\n\n // Build description\n const presentList = presentElements.map((e) => e.name).join(', ');\n const missingList = missingElements.map((e) => e.name).join(', ');\n\n let description: string;\n if (presentCount >= 5) {\n description = `Strong transactional content (${presentCount}/8 elements). Present: ${presentList}.`;\n if (missingElements.length > 0) {\n description += ` Consider also adding: ${missingList}.`;\n }\n } else if (presentCount >= 3) {\n description = `Acceptable transactional content (${presentCount}/8 elements). Present: ${presentList}. Missing: ${missingList}.`;\n } else {\n description = `Transactional content lacks key elements (${presentCount}/8).${presentCount > 0 ? ` Present: ${presentList}.` : ''} Missing: ${missingList}.`;\n }\n\n return { id, title, description, status, score, maxScore: 5 };\n}\n","// @power-seo/content-analysis — Commercial Investigation Elements Check\n// ----------------------------------------------------------------------------\n// Checks whether commercial-investigation content includes the elements\n// comparison shoppers expect: comparison structure, pros/cons, ratings,\n// multiple options, recommendations, price comparison, and feature comparison.\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\ninterface CommercialElement {\n name: string;\n present: boolean;\n}\n\nexport function checkIntentCommercialElements(\n input: ContentAnalysisInput,\n): AnalysisResult {\n const id = 'intent-commercial-elements';\n const title = 'Commercial investigation elements';\n\n // No keyphrase — cannot determine intent\n if (!input.focusKeyphrase || input.focusKeyphrase.trim().length === 0) {\n return { id, title, description: 'No focus keyphrase set.', status: 'na', score: 0, maxScore: 5 };\n }\n\n // Only applies to commercial-investigation intent\n const intent = detectIntent(input.focusKeyphrase);\n if (intent.primary !== 'commercial-investigation') {\n return {\n id,\n title,\n description: `Detected intent is \"${intent.primary}\" — this check only applies to commercial investigation content.`,\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const content = input.content;\n const contentLower = content.toLowerCase();\n const plainText = stripHtml(content);\n\n const elements: CommercialElement[] = [];\n\n // 1. Comparison structure: <table> present OR comparison phrases\n const hasTable = contentLower.includes('<table');\n const hasComparisonPhrase = /\\b(?:compared to|side by side|head to head)\\b/i.test(plainText);\n elements.push({ name: 'Comparison structure', present: hasTable || hasComparisonPhrase });\n\n // 2. Pros and cons\n const hasProsCons = /\\b(?:pros|cons|advantages|disadvantages|benefits|drawbacks)\\b/i.test(plainText);\n elements.push({ name: 'Pros and cons', present: hasProsCons });\n\n // 3. Rating / scoring\n const hasRating = /\\b(?:rating|score|stars)\\b/i.test(plainText)\n || /\\/5\\b/.test(plainText)\n || /\\/10\\b/.test(plainText)\n || /\\bout of 10\\b/i.test(plainText)\n || /\\bgrade\\b/i.test(plainText);\n elements.push({ name: 'Rating/scoring', present: hasRating });\n\n // 4. Multiple options: 3+ capitalized multi-word phrases (brand-like patterns)\n // Heuristic: sequences of 2+ capitalized words that look like product/brand names\n const brandPattern = /\\b[A-Z][a-z]+(?:\\s+[A-Z][a-z]+)+\\b/g;\n const brandMatches = plainText.match(brandPattern);\n const uniqueBrands = brandMatches\n ? new Set(brandMatches.map((b) => b.toLowerCase())).size\n : 0;\n elements.push({ name: 'Multiple options (3+ products/brands)', present: uniqueBrands >= 3 });\n\n // 5. Recommendations\n const hasRecommendations = /\\b(?:we recommend|our pick|best for|editor'?s choice|top choice|best overall|winner)\\b/i.test(plainText);\n elements.push({ name: 'Recommendations', present: hasRecommendations });\n\n // 6. Price comparison: \"starting at\", \"from $\", or price patterns appearing 2+ times\n const hasStartingAt = /\\b(?:starting at|from \\$)\\b/i.test(plainText);\n const pricePatternMatches = plainText.match(/\\$\\d[\\d,.]*\\b/g);\n const priceCount = pricePatternMatches ? pricePatternMatches.length : 0;\n elements.push({ name: 'Price comparison', present: hasStartingAt || priceCount >= 2 });\n\n // 7. Feature comparison\n const hasFeatureComparison = /\\b(?:features|includes|offers|supports|lacks|missing)\\b/i.test(plainText);\n elements.push({ name: 'Feature comparison', present: hasFeatureComparison });\n\n // Tally present elements\n const presentElements = elements.filter((e) => e.present);\n const presentCount = presentElements.length;\n const missingElements = elements.filter((e) => !e.present);\n\n // Scoring\n let score: number;\n let status: 'good' | 'ok' | 'poor';\n\n if (presentCount >= 5) {\n score = 5;\n status = 'good';\n } else if (presentCount >= 3) {\n score = 3;\n status = 'ok';\n } else {\n score = 1;\n status = 'poor';\n }\n\n // Build description\n const presentList = presentElements.map((e) => e.name).join(', ');\n const missingList = missingElements.map((e) => e.name).join(', ');\n\n let description: string;\n if (presentCount >= 5) {\n description = `Strong commercial investigation content (${presentCount}/7 elements). Present: ${presentList}.`;\n if (missingElements.length > 0) {\n description += ` Consider also adding: ${missingList}.`;\n }\n } else if (presentCount >= 3) {\n description = `Acceptable commercial investigation content (${presentCount}/7 elements). Present: ${presentList}. Missing: ${missingList}.`;\n } else {\n description = `Commercial investigation content lacks key elements (${presentCount}/7).${presentCount > 0 ? ` Present: ${presentList}.` : ''} Missing: ${missingList}.`;\n }\n\n return { id, title, description, status, score, maxScore: 5 };\n}\n","// @power-seo/content-analysis — Navigational Content Clarity Check\n// ----------------------------------------------------------------------------\n// Checks whether navigational content is clear and direct: brand prominence,\n// direct links, contact info, conciseness, and navigation cues.\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\ninterface NavigationalElement {\n name: string;\n present: boolean;\n}\n\nexport function checkIntentNavigationalClarity(\n input: ContentAnalysisInput,\n): AnalysisResult {\n const id = 'intent-navigational-clarity';\n const title = 'Navigational content clarity';\n\n // No keyphrase — cannot determine intent\n if (!input.focusKeyphrase || input.focusKeyphrase.trim().length === 0) {\n return { id, title, description: 'No focus keyphrase set.', status: 'na', score: 0, maxScore: 5 };\n }\n\n // Only applies to navigational intent\n const intent = detectIntent(input.focusKeyphrase);\n if (intent.primary !== 'navigational') {\n return {\n id,\n title,\n description: `Detected intent is \"${intent.primary}\" — this check only applies to navigational content.`,\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const content = input.content;\n const plainText = stripHtml(content);\n const plainTextLower = plainText.toLowerCase();\n const words = getWords(content);\n const wordCount = words.length;\n\n // Determine target term: keyphrase itself and its first word\n const keyphrase = input.focusKeyphrase.trim().toLowerCase();\n const keyphraseWords = keyphrase.split(/\\s+/);\n const firstWord = keyphraseWords[0];\n\n const elements: NavigationalElement[] = [];\n\n // 1. Brand / target prominence: keyphrase (or first word) in title AND first 100 words\n const titleLower = (input.title ?? '').toLowerCase();\n const first100Words = words.slice(0, 100).join(' ').toLowerCase();\n\n const keyphraseInTitle = titleLower.includes(keyphrase)\n || (firstWord !== undefined && titleLower.includes(firstWord));\n const keyphraseInIntro = first100Words.includes(keyphrase)\n || (firstWord !== undefined && first100Words.includes(firstWord));\n\n elements.push({\n name: 'Brand/target prominence',\n present: keyphraseInTitle && keyphraseInIntro,\n });\n\n // 2. Direct links: at least 1 <a href link\n const linkMatches = content.match(/<a\\s[^>]*href\\s*=/gi);\n const linkCount = linkMatches ? linkMatches.length : 0;\n elements.push({ name: 'Direct links', present: linkCount >= 1 });\n\n // 3. Contact info\n const hasContact = /\\b(?:email|phone|address|contact)\\b/i.test(plainText)\n || /\\S+@\\S+\\.\\S+/.test(plainText);\n elements.push({ name: 'Contact information', present: hasContact });\n\n // 4. Conciseness: word count <= 800 (navigational pages should be direct)\n elements.push({ name: 'Conciseness (800 words or fewer)', present: wordCount <= 800 });\n\n // 5. Navigation cues\n const hasNavCues = /\\b(?:click here|visit|go to|access|log in|sign in)\\b/i.test(plainTextLower);\n elements.push({ name: 'Navigation cues', present: hasNavCues });\n\n // Tally present elements\n const presentElements = elements.filter((e) => e.present);\n const presentCount = presentElements.length;\n const missingElements = elements.filter((e) => !e.present);\n\n // Scoring\n let score: number;\n let status: 'good' | 'ok' | 'poor';\n\n if (presentCount >= 4) {\n score = 5;\n status = 'good';\n } else if (presentCount >= 2) {\n score = 3;\n status = 'ok';\n } else {\n score = 1;\n status = 'poor';\n }\n\n // Build description\n const presentList = presentElements.map((e) => e.name).join(', ');\n const missingList = missingElements.map((e) => e.name).join(', ');\n\n let description: string;\n if (presentCount >= 4) {\n description = `Clear navigational content (${presentCount}/5 elements). Present: ${presentList}.`;\n if (missingElements.length > 0) {\n description += ` Consider also adding: ${missingList}.`;\n }\n } else if (presentCount >= 2) {\n description = `Navigational content could be clearer (${presentCount}/5 elements). Present: ${presentList}. Missing: ${missingList}.`;\n } else {\n description = `Navigational content lacks clarity (${presentCount}/5).${presentCount > 0 ? ` Present: ${presentList}.` : ''} Missing: ${missingList}.`;\n }\n\n return { id, title, description, status, score, maxScore: 5 };\n}\n","// @power-seo/content-analysis — Content Format-Intent Match Check\n// ----------------------------------------------------------------------------\n// Checks whether the content's structural format matches the expectations for\n// the detected intent sub-type (e.g., tutorials should have steps, comparisons\n// should have tables, navigational pages should be concise with direct links).\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\ninterface FormatSignal {\n name: string;\n present: boolean;\n}\n\n/**\n * Check format elements for informational/tutorial content.\n * Expects ordered lists, step patterns, or numbered headings.\n */\nfunction checkTutorialFormat(content: string, plainText: string): FormatSignal[] {\n const contentLower = content.toLowerCase();\n const signals: FormatSignal[] = [];\n\n const hasOrderedList = contentLower.includes('<ol');\n signals.push({ name: 'Ordered list (<ol>)', present: hasOrderedList });\n\n const hasStepPatterns = /\\bstep\\s+\\d/i.test(plainText);\n signals.push({ name: 'Step patterns (\"Step 1\", \"Step 2\")', present: hasStepPatterns });\n\n const hasNumberedHeadings = /\\b\\d+\\.\\s+\\w/i.test(plainText);\n signals.push({ name: 'Numbered headings', present: hasNumberedHeadings });\n\n return signals;\n}\n\n/**\n * Check format elements for informational/definitional content.\n * Expects a concise definition early in the content (first 200 words).\n */\nfunction checkDefinitionalFormat(words: string[]): FormatSignal[] {\n const signals: FormatSignal[] = [];\n\n const first200 = words.slice(0, 200).join(' ').toLowerCase();\n const hasEarlyDefinition = /\\b(?:is a|refers to)\\b/.test(first200);\n signals.push({ name: 'Early definition (first 200 words)', present: hasEarlyDefinition });\n\n return signals;\n}\n\n/**\n * Check format elements for informational/listicle content.\n * Expects list items (>= 5) or numbered headings.\n */\nfunction checkListicleFormat(content: string, plainText: string): FormatSignal[] {\n const contentLower = content.toLowerCase();\n const signals: FormatSignal[] = [];\n\n const liCount = contentLower.split('<li').length - 1;\n signals.push({ name: 'List items (5+ <li>)', present: liCount >= 5 });\n\n const hasNumberedHeadings = /\\b\\d+\\.\\s+\\w/.test(plainText);\n signals.push({ name: 'Numbered headings', present: hasNumberedHeadings });\n\n return signals;\n}\n\n/**\n * Check format elements for commercial/comparison content.\n * Expects tables or structured comparison sections.\n */\nfunction checkComparisonFormat(content: string, plainText: string): FormatSignal[] {\n const contentLower = content.toLowerCase();\n const signals: FormatSignal[] = [];\n\n const hasTable = contentLower.includes('<table');\n signals.push({ name: 'Comparison table', present: hasTable });\n\n const hasComparisonPhrases = /\\b(?:compared to|side by side|head to head|vs\\.?)\\b/i.test(plainText);\n signals.push({ name: 'Comparison phrases', present: hasComparisonPhrases });\n\n return signals;\n}\n\n/**\n * Check format elements for commercial/review content.\n * Expects rating patterns and pros/cons sections.\n */\nfunction checkReviewFormat(plainText: string): FormatSignal[] {\n const signals: FormatSignal[] = [];\n\n const hasRating = /\\b(?:rating|score|stars)\\b/i.test(plainText)\n || /\\/5\\b/.test(plainText)\n || /\\/10\\b/.test(plainText)\n || /\\bout of 10\\b/i.test(plainText);\n signals.push({ name: 'Rating patterns', present: hasRating });\n\n const hasProsCons = /\\b(?:pros|cons|advantages|disadvantages|benefits|drawbacks)\\b/i.test(plainText);\n signals.push({ name: 'Pros/cons sections', present: hasProsCons });\n\n return signals;\n}\n\n/**\n * Check format elements for transactional content.\n * Expects product-like structure: specs + price + CTA.\n */\nfunction checkTransactionalFormat(plainText: string): FormatSignal[] {\n const signals: FormatSignal[] = [];\n\n const hasSpecs = /\\b(?:specifications|features|dimensions|weight|material)\\b/i.test(plainText);\n signals.push({ name: 'Product specifications', present: hasSpecs });\n\n const hasPrice = /\\$\\d/.test(plainText) || /\\b(?:price|cost|pricing)\\b/i.test(plainText);\n signals.push({ name: 'Price information', present: hasPrice });\n\n const hasCTA = /\\b(?:buy now|add to cart|order|get started|try free|start trial)\\b/i.test(plainText);\n signals.push({ name: 'Call-to-action', present: hasCTA });\n\n return signals;\n}\n\n/**\n * Check format elements for navigational content.\n * Expects minimal structure with direct links.\n */\nfunction checkNavigationalFormat(content: string, wordCount: number): FormatSignal[] {\n const signals: FormatSignal[] = [];\n\n signals.push({ name: 'Concise (800 words or fewer)', present: wordCount <= 800 });\n\n const linkMatches = content.match(/<a\\s[^>]*href\\s*=/gi);\n const linkCount = linkMatches ? linkMatches.length : 0;\n signals.push({ name: 'Direct links present', present: linkCount >= 1 });\n\n return signals;\n}\n\nexport function checkIntentFormatMatch(\n input: ContentAnalysisInput,\n): AnalysisResult {\n const id = 'intent-format-match';\n const title = 'Content format-intent match';\n\n // No keyphrase — cannot determine intent\n if (!input.focusKeyphrase || input.focusKeyphrase.trim().length === 0) {\n return { id, title, description: 'No focus keyphrase set.', status: 'na', score: 0, maxScore: 8 };\n }\n\n const intent = detectIntent(input.focusKeyphrase);\n const content = input.content;\n const plainText = stripHtml(content);\n const words = getWords(content);\n const wordCount = words.length;\n\n let signals: FormatSignal[] = [];\n let expectedFormat: string;\n\n // Route to the appropriate format check based on intent primary + sub-type\n const primary = intent.primary;\n const subType = intent.subType;\n\n if (primary === 'informational') {\n if (subType === 'tutorial' || subType === 'troubleshooting') {\n expectedFormat = 'tutorial/how-to';\n signals = checkTutorialFormat(content, plainText);\n } else if (subType === 'definitional') {\n expectedFormat = 'definitional';\n signals = checkDefinitionalFormat(words);\n } else if (subType === 'reference') {\n expectedFormat = 'listicle';\n signals = checkListicleFormat(content, plainText);\n } else {\n // General informational — check for a mix of tutorial + listicle\n expectedFormat = 'informational';\n const tutorialSignals = checkTutorialFormat(content, plainText);\n const listicleSignals = checkListicleFormat(content, plainText);\n const defSignals = checkDefinitionalFormat(words);\n signals = [...tutorialSignals, ...listicleSignals, ...defSignals];\n }\n } else if (primary === 'commercial-investigation') {\n if (subType === 'comparison') {\n expectedFormat = 'comparison';\n signals = checkComparisonFormat(content, plainText);\n } else if (subType === 'review-seeking') {\n expectedFormat = 'review';\n signals = checkReviewFormat(plainText);\n } else {\n // General commercial — check for both comparison + review signals\n expectedFormat = 'commercial investigation';\n const compSignals = checkComparisonFormat(content, plainText);\n const reviewSignals = checkReviewFormat(plainText);\n signals = [...compSignals, ...reviewSignals];\n }\n } else if (primary === 'transactional') {\n expectedFormat = 'transactional/product';\n signals = checkTransactionalFormat(plainText);\n } else if (primary === 'navigational') {\n expectedFormat = 'navigational';\n signals = checkNavigationalFormat(content, wordCount);\n } else {\n // Fallback — should not happen, but handle gracefully\n return {\n id,\n title,\n description: 'Unable to determine expected format for this intent type.',\n status: 'na',\n score: 0,\n maxScore: 8,\n };\n }\n\n // Evaluate: how many format signals are present?\n const totalSignals = signals.length;\n const presentSignals = signals.filter((s) => s.present);\n const presentCount = presentSignals.length;\n const missingSignals = signals.filter((s) => !s.present);\n\n // Determine match level\n let score: number;\n let status: 'good' | 'ok' | 'poor';\n\n if (totalSignals === 0) {\n // No signals to check — consider it a pass\n return {\n id,\n title,\n description: `No specific format requirements identified for ${expectedFormat} content.`,\n status: 'na',\n score: 0,\n maxScore: 8,\n };\n }\n\n const matchRatio = presentCount / totalSignals;\n\n if (matchRatio >= 0.5) {\n // At least half the signals match — good\n score = 5;\n status = 'good';\n } else if (presentCount >= 1) {\n // At least one signal matches — partial\n score = 3;\n status = 'ok';\n } else {\n // No signals match — mismatch\n score = 0;\n status = 'poor';\n }\n\n // Build description\n const subTypeLabel = subType ? ` (${subType})` : '';\n const presentList = presentSignals.map((s) => s.name).join(', ');\n const missingList = missingSignals.map((s) => s.name).join(', ');\n\n let description: string;\n if (status === 'good') {\n description = `Content format matches ${expectedFormat}${subTypeLabel} expectations (${presentCount}/${totalSignals} signals). Found: ${presentList}.`;\n if (missingSignals.length > 0) {\n description += ` Could also add: ${missingList}.`;\n }\n } else if (status === 'ok') {\n description = `Content partially matches ${expectedFormat}${subTypeLabel} format (${presentCount}/${totalSignals} signals). Found: ${presentList}. Missing: ${missingList}.`;\n } else {\n description = `Content format does not match ${expectedFormat}${subTypeLabel} expectations (0/${totalSignals} signals). Missing: ${missingList}. Restructure content to match the expected format.`;\n }\n\n return { id, title, description, status, score, maxScore: 8 };\n}\n","// @power-seo/content-analysis — Intent Signal Density Check\n// ----------------------------------------------------------------------------\n// Measures how frequently intent-matching signal phrases appear in the content\n// body relative to the total word count.\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\n// ---------------------------------------------------------------------------\n// Intent-specific signal patterns\n// ---------------------------------------------------------------------------\n\nconst SIGNAL_PATTERNS: Record<string, RegExp> = {\n informational:\n /\\b(how to|what is|guide|learn|understand|explained|definition|steps|tutorial|tips|example|for example|such as|in this article|we'll cover|you'll learn|let's explore|introduction|overview|basics|beginners|faq)\\b/gi,\n transactional:\n /\\b(buy|purchase|order|add to cart|shop|deal|discount|price|pricing|free shipping|checkout|subscribe|sign up|get started|try free|limited time|in stock|available now|book now|reserve)\\b/gi,\n 'commercial-investigation':\n /\\b(best|top|review|compared|comparison|vs|versus|pros and cons|advantages|disadvantages|rating|rated|recommend|our pick|editor's choice|winner|runner-up|alternative|benchmark)\\b/gi,\n navigational:\n /\\b(official|login|sign in|dashboard|my account|support|contact us|help center|visit|go to|homepage)\\b/gi,\n};\n\n/**\n * Count all matches for a given regex pattern within text.\n * Resets the regex lastIndex to ensure consistent results.\n */\nfunction countMatches(text: string, pattern: RegExp): number {\n pattern.lastIndex = 0;\n const matches = text.match(pattern);\n return matches ? matches.length : 0;\n}\n\n/**\n * Check the density of intent-matching signal phrases in the content body.\n *\n * Density is calculated as (matchCount / wordCount) * 500 — signals per 500 words.\n * - good (5): density >= 4\n * - ok (3): density >= 2\n * - poor (1): density < 2\n * - poor (0): density === 0 (no signals at all)\n */\nexport function checkIntentSignalDensity(\n input: ContentAnalysisInput,\n): AnalysisResult {\n const { focusKeyphrase, content } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n return {\n id: 'intent-signal-density',\n title: 'Intent signal density',\n description:\n 'No focus keyphrase set. Set one to analyze intent signal density.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const detected = detectIntent(focusKeyphrase.trim());\n const intentKey = detected.primary;\n const pattern = SIGNAL_PATTERNS[intentKey];\n\n // Safety: should always resolve, but guard for strict indexed access\n if (!pattern) {\n return {\n id: 'intent-signal-density',\n title: 'Intent signal density',\n description: `Unable to determine signal pattern for intent \"${intentKey}\".`,\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const plainText = stripHtml(content).toLowerCase();\n const words = getWords(content);\n const wordCount = words.length;\n\n if (wordCount === 0) {\n return {\n id: 'intent-signal-density',\n title: 'Intent signal density',\n description: 'Content has no words. Add content to analyze intent signal density.',\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n\n const matchCount = countMatches(plainText, pattern);\n const density = (matchCount / wordCount) * 500;\n const densityRounded = Math.round(density * 100) / 100;\n\n if (matchCount === 0) {\n return {\n id: 'intent-signal-density',\n title: 'Intent signal density',\n description:\n `No ${intentKey} intent signals found in ${wordCount} words. ` +\n `Add phrases that reinforce ${intentKey} intent (density: 0 per 500 words).`,\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n\n if (density < 2) {\n return {\n id: 'intent-signal-density',\n title: 'Intent signal density',\n description:\n `Found ${matchCount} ${intentKey} intent signal(s) in ${wordCount} words ` +\n `(${densityRounded} per 500 words). Aim for at least 4 per 500 words.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n }\n\n if (density < 4) {\n return {\n id: 'intent-signal-density',\n title: 'Intent signal density',\n description:\n `Found ${matchCount} ${intentKey} intent signal(s) in ${wordCount} words ` +\n `(${densityRounded} per 500 words). Good start — aim for 4+ per 500 words for optimal density.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'intent-signal-density',\n title: 'Intent signal density',\n description:\n `Found ${matchCount} ${intentKey} intent signal(s) in ${wordCount} words ` +\n `(${densityRounded} per 500 words). Intent signals are well-represented throughout the content.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Intent Signal Distribution Check\n// ----------------------------------------------------------------------------\n// Verifies that intent signals are spread across all sections of the content,\n// not clustered in one area.\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\n// ---------------------------------------------------------------------------\n// Intent-specific signal patterns\n// ---------------------------------------------------------------------------\n\nconst SIGNAL_PATTERNS: Record<string, RegExp> = {\n informational:\n /\\b(how to|what is|guide|learn|understand|explained|definition|steps|tutorial|tips|example|for example|such as|in this article|we'll cover|you'll learn|let's explore|introduction|overview|basics|beginners|faq)\\b/gi,\n transactional:\n /\\b(buy|purchase|order|add to cart|shop|deal|discount|price|pricing|free shipping|checkout|subscribe|sign up|get started|try free|limited time|in stock|available now|book now|reserve)\\b/gi,\n 'commercial-investigation':\n /\\b(best|top|review|compared|comparison|vs|versus|pros and cons|advantages|disadvantages|rating|rated|recommend|our pick|editor's choice|winner|runner-up|alternative|benchmark)\\b/gi,\n navigational:\n /\\b(official|login|sign in|dashboard|my account|support|contact us|help center|visit|go to|homepage)\\b/gi,\n};\n\nconst MIN_WORDS_FOR_DISTRIBUTION = 200;\nconst QUARTILE_COUNT = 4;\nconst QUARTILE_LABELS = ['Q1 (0-25%)', 'Q2 (25-50%)', 'Q3 (50-75%)', 'Q4 (75-100%)'];\n\n/**\n * Check whether a text segment contains at least one match for the pattern.\n */\nfunction hasSignals(text: string, pattern: RegExp): boolean {\n // Clone the pattern to reset lastIndex\n const re = new RegExp(pattern.source, pattern.flags);\n return re.test(text);\n}\n\n/**\n * Divide an array of words into N roughly equal quartiles and return joined strings.\n */\nfunction divideIntoQuartiles(words: string[], count: number): string[] {\n const quartiles: string[] = [];\n const size = Math.max(1, Math.ceil(words.length / count));\n\n for (let i = 0; i < count; i++) {\n const start = i * size;\n const end = Math.min(start + size, words.length);\n if (start < words.length) {\n quartiles.push(words.slice(start, end).join(' '));\n } else {\n quartiles.push('');\n }\n }\n\n return quartiles;\n}\n\n/**\n * Check whether intent signals are evenly distributed across content quartiles.\n *\n * Divides the plaintext content into 4 equal quartiles by word count and checks\n * each for the presence of intent-matching signal phrases.\n *\n * - good (5): 4/4 quartiles have signals\n * - ok (3): 2-3/4 quartiles have signals\n * - poor (1): 1/4 quartile (signals clustered)\n * - poor (0): 0/4 quartiles have signals\n *\n * Returns 'na' if total word count < 200 (too short to assess distribution).\n */\nexport function checkIntentSignalDistribution(\n input: ContentAnalysisInput,\n): AnalysisResult {\n const { focusKeyphrase, content } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n return {\n id: 'intent-signal-distribution',\n title: 'Intent signal distribution',\n description:\n 'No focus keyphrase set. Set one to analyze intent signal distribution.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const detected = detectIntent(focusKeyphrase.trim());\n const intentKey = detected.primary;\n const pattern = SIGNAL_PATTERNS[intentKey];\n\n if (!pattern) {\n return {\n id: 'intent-signal-distribution',\n title: 'Intent signal distribution',\n description: `Unable to determine signal pattern for intent \"${intentKey}\".`,\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const plainText = stripHtml(content).toLowerCase();\n const words = getWords(content);\n const wordCount = words.length;\n\n if (wordCount < MIN_WORDS_FOR_DISTRIBUTION) {\n return {\n id: 'intent-signal-distribution',\n title: 'Intent signal distribution',\n description:\n `Content is only ${wordCount} words. At least ${MIN_WORDS_FOR_DISTRIBUTION} words are needed ` +\n 'to meaningfully assess intent signal distribution.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n // Split plaintext words into quartiles\n const plainWords = plainText.split(/\\s+/).filter((w) => w.length > 0);\n const quartiles = divideIntoQuartiles(plainWords, QUARTILE_COUNT);\n\n const quartilesWithSignals: string[] = [];\n const intentDeserts: string[] = [];\n\n for (let i = 0; i < QUARTILE_COUNT; i++) {\n const quartileText = quartiles[i];\n const label = QUARTILE_LABELS[i];\n\n // Guard for strict indexed access\n if (quartileText === undefined || label === undefined) {\n continue;\n }\n\n if (hasSignals(quartileText, pattern)) {\n quartilesWithSignals.push(label);\n } else {\n intentDeserts.push(label);\n }\n }\n\n const signalCount = quartilesWithSignals.length;\n\n if (signalCount === 0) {\n return {\n id: 'intent-signal-distribution',\n title: 'Intent signal distribution',\n description:\n `No ${intentKey} intent signals found in any of the 4 content quartiles. ` +\n `All sections are intent deserts: ${intentDeserts.join(', ')}.`,\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n\n if (signalCount === 1) {\n return {\n id: 'intent-signal-distribution',\n title: 'Intent signal distribution',\n description:\n `${intentKey[0]?.toUpperCase()}${intentKey.slice(1)} intent signals found in only 1 of 4 quartiles ` +\n `(${quartilesWithSignals.join(', ')}). ` +\n `Signals are clustered. Intent deserts: ${intentDeserts.join(', ')}. ` +\n 'Spread intent signals throughout the content.',\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n }\n\n if (signalCount <= 3) {\n return {\n id: 'intent-signal-distribution',\n title: 'Intent signal distribution',\n description:\n `${intentKey[0]?.toUpperCase()}${intentKey.slice(1)} intent signals found in ${signalCount} of 4 quartiles ` +\n `(${quartilesWithSignals.join(', ')}). ` +\n (intentDeserts.length > 0\n ? `Intent deserts: ${intentDeserts.join(', ')}. Add signals to these sections.`\n : ''),\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'intent-signal-distribution',\n title: 'Intent signal distribution',\n description:\n `${intentKey[0]?.toUpperCase()}${intentKey.slice(1)} intent signals are present in all 4 content quartiles ` +\n `(${quartilesWithSignals.join(', ')}). Intent is consistently reinforced throughout.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Content Depth-Intent Match Check\n// ----------------------------------------------------------------------------\n// Verifies that the content length is appropriate for the detected search\n// intent type. Different intents have different ideal word count ranges.\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { getWords } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\n// ---------------------------------------------------------------------------\n// Ideal word count ranges per intent type\n// ---------------------------------------------------------------------------\n\ninterface DepthRange {\n idealMin: number;\n idealMax: number;\n label: string;\n}\n\nconst DEPTH_RANGES: Record<string, DepthRange> = {\n informational: { idealMin: 1000, idealMax: 5000, label: '1,000–5,000' },\n transactional: { idealMin: 300, idealMax: 1500, label: '300–1,500' },\n 'commercial-investigation': {\n idealMin: 1500,\n idealMax: 5000,\n label: '1,500–5,000',\n },\n navigational: { idealMin: 100, idealMax: 800, label: '100–800' },\n};\n\n/**\n * Evaluate informational intent depth.\n * - < 500 = poor\n * - 500-999 = ok\n * - 1000+ = good\n */\nfunction evaluateInformational(wordCount: number): { status: 'good' | 'ok' | 'poor'; score: number; note: string } {\n if (wordCount < 500) {\n return {\n status: 'poor',\n score: 1,\n note: `${wordCount} words is well under the ideal range. Informational content needs depth — expand to at least 1,000 words.`,\n };\n }\n if (wordCount < 1000) {\n return {\n status: 'ok',\n score: 3,\n note: `${wordCount} words is slightly below the ideal range. Consider expanding to 1,000+ words for comprehensive coverage.`,\n };\n }\n return {\n status: 'good',\n score: 5,\n note: `${wordCount} words is within the ideal range for informational content. Good depth for thorough topic coverage.`,\n };\n}\n\n/**\n * Evaluate transactional intent depth.\n * - < 200 = poor\n * - 200-299 = ok\n * - 300-1500 = good\n * - > 2000 = ok (over-length for transactional)\n */\nfunction evaluateTransactional(wordCount: number): { status: 'good' | 'ok' | 'poor'; score: number; note: string } {\n if (wordCount < 200) {\n return {\n status: 'poor',\n score: 1,\n note: `${wordCount} words is too short for transactional content. Add product details, benefits, and trust signals.`,\n };\n }\n if (wordCount < 300) {\n return {\n status: 'ok',\n score: 3,\n note: `${wordCount} words is slightly under the ideal range. Consider adding more product details to reach 300+ words.`,\n };\n }\n if (wordCount <= 1500) {\n return {\n status: 'good',\n score: 5,\n note: `${wordCount} words is within the ideal range for transactional content. Concise enough for action-oriented users.`,\n };\n }\n if (wordCount > 2000) {\n return {\n status: 'ok',\n score: 3,\n note: `${wordCount} words may be over-length for transactional content. Buyers want quick decisions — consider trimming to under 1,500 words.`,\n };\n }\n // 1501-2000: borderline, still acceptable\n return {\n status: 'good',\n score: 5,\n note: `${wordCount} words is near the upper end of the ideal range for transactional content.`,\n };\n}\n\n/**\n * Evaluate commercial investigation intent depth.\n * - < 800 = poor\n * - 800-1499 = ok\n * - 1500+ = good\n */\nfunction evaluateCommercial(wordCount: number): { status: 'good' | 'ok' | 'poor'; score: number; note: string } {\n if (wordCount < 800) {\n return {\n status: 'poor',\n score: 1,\n note: `${wordCount} words is well under the ideal range. Comparison and review content needs depth — expand to 1,500+ words.`,\n };\n }\n if (wordCount < 1500) {\n return {\n status: 'ok',\n score: 3,\n note: `${wordCount} words is slightly below the ideal range. Add more detail to comparisons and evaluations to reach 1,500+ words.`,\n };\n }\n return {\n status: 'good',\n score: 5,\n note: `${wordCount} words is within the ideal range for commercial investigation content. Provides thorough comparison depth.`,\n };\n}\n\n/**\n * Evaluate navigational intent depth.\n * - < 50 = poor\n * - > 1000 = ok (too verbose)\n * - 100-800 = good\n * - 50-99 = ok (slightly short)\n * - 801-1000 = ok (slightly long)\n */\nfunction evaluateNavigational(wordCount: number): { status: 'good' | 'ok' | 'poor'; score: number; note: string } {\n if (wordCount < 50) {\n return {\n status: 'poor',\n score: 1,\n note: `${wordCount} words is too short. Add at least basic navigation cues and directions.`,\n };\n }\n if (wordCount < 100) {\n return {\n status: 'ok',\n score: 3,\n note: `${wordCount} words is slightly under the ideal range. Consider adding brief context to help users navigate.`,\n };\n }\n if (wordCount <= 800) {\n return {\n status: 'good',\n score: 5,\n note: `${wordCount} words is within the ideal range for navigational content. Concise and focused on directing users.`,\n };\n }\n if (wordCount > 1000) {\n return {\n status: 'ok',\n score: 3,\n note: `${wordCount} words is too verbose for navigational content. Users want to get somewhere quickly — consider trimming to under 800 words.`,\n };\n }\n // 801-1000: borderline\n return {\n status: 'ok',\n score: 3,\n note: `${wordCount} words is slightly over the ideal range. Navigational pages should be concise.`,\n };\n}\n\n/**\n * Check whether the content length (word count) is appropriate for the\n * detected search intent of the focus keyphrase.\n *\n * Each intent type has a different ideal word count range:\n * - Informational: 1,000–5,000 words\n * - Transactional: 300–1,500 words\n * - Commercial: 1,500–5,000 words\n * - Navigational: 100–800 words\n */\nexport function checkIntentDepthMatch(\n input: ContentAnalysisInput,\n): AnalysisResult {\n const { focusKeyphrase, content } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n return {\n id: 'intent-depth-match',\n title: 'Content depth-intent match',\n description:\n 'No focus keyphrase set. Set one to analyze content depth relative to intent.',\n status: 'na',\n score: 0,\n maxScore: 8,\n };\n }\n\n const detected = detectIntent(focusKeyphrase.trim());\n const intentKey = detected.primary;\n const range = DEPTH_RANGES[intentKey];\n\n if (!range) {\n return {\n id: 'intent-depth-match',\n title: 'Content depth-intent match',\n description: `Unable to determine depth range for intent \"${intentKey}\".`,\n status: 'na',\n score: 0,\n maxScore: 8,\n };\n }\n\n const words = getWords(content);\n const wordCount = words.length;\n\n let evaluation: { status: 'good' | 'ok' | 'poor'; score: number; note: string };\n\n switch (intentKey) {\n case 'informational':\n evaluation = evaluateInformational(wordCount);\n break;\n case 'transactional':\n evaluation = evaluateTransactional(wordCount);\n break;\n case 'commercial-investigation':\n evaluation = evaluateCommercial(wordCount);\n break;\n case 'navigational':\n evaluation = evaluateNavigational(wordCount);\n break;\n default:\n evaluation = {\n status: 'ok',\n score: 3,\n note: `${wordCount} words. Unable to determine ideal range for this intent type.`,\n };\n }\n\n return {\n id: 'intent-depth-match',\n title: 'Content depth-intent match',\n description:\n `${evaluation.note} Expected range for ${intentKey} intent: ${range.label} words.`,\n status: evaluation.status,\n score: evaluation.score,\n maxScore: 8,\n };\n}\n","// @power-seo/content-analysis — Mixed Intent Warning Check\n// ----------------------------------------------------------------------------\n// Detects when content contains conflicting intent signals that may confuse\n// search engines about the page's purpose.\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\n// ---------------------------------------------------------------------------\n// Intent signal patterns for all 4 categories\n// ---------------------------------------------------------------------------\n\ninterface IntentCategory {\n key: string;\n label: string;\n pattern: RegExp;\n}\n\nconst INTENT_CATEGORIES: IntentCategory[] = [\n {\n key: 'informational',\n label: 'Informational',\n pattern:\n /\\b(how to|what is|guide|learn|understand|explained|definition|steps|tutorial|tips|example|for example|such as|in this article|we'll cover|you'll learn|let's explore|introduction|overview|basics|beginners|faq)\\b/gi,\n },\n {\n key: 'transactional',\n label: 'Transactional',\n pattern:\n /\\b(buy|purchase|order|add to cart|shop|deal|discount|price|pricing|free shipping|checkout|subscribe|sign up|get started|try free|limited time|in stock|available now|book now|reserve)\\b/gi,\n },\n {\n key: 'commercial-investigation',\n label: 'Commercial',\n pattern:\n /\\b(best|top|review|compared|comparison|vs|versus|pros and cons|advantages|disadvantages|rating|rated|recommend|our pick|editor's choice|winner|runner-up|alternative|benchmark)\\b/gi,\n },\n {\n key: 'navigational',\n label: 'Navigational',\n pattern:\n /\\b(official|login|sign in|dashboard|my account|support|contact us|help center|visit|go to|homepage)\\b/gi,\n },\n];\n\n/** Conflict threshold: secondary intent > 30% of primary intent signals. */\nconst CONFLICT_THRESHOLD = 0.3;\n\n/**\n * Count all matches for a given regex pattern within text.\n */\nfunction countMatches(text: string, pattern: RegExp): number {\n const re = new RegExp(pattern.source, pattern.flags);\n const matches = text.match(re);\n return matches ? matches.length : 0;\n}\n\n/**\n * Check whether the content mixes signals from conflicting intent categories.\n *\n * Scans content for signals from all 4 intent types, determines the dominant\n * content intent, and checks whether it aligns with the keyphrase intent.\n *\n * - good (5): no conflicting signals, content matches keyphrase intent\n * - ok (3): minor mixing (secondary signals present but < 30% of primary)\n * - poor (1): heavy mixing or dominant content intent contradicts keyphrase intent\n */\nexport function checkIntentMixedWarning(\n input: ContentAnalysisInput,\n): AnalysisResult {\n const { focusKeyphrase, content } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n return {\n id: 'intent-mixed-warning',\n title: 'Mixed intent warning',\n description:\n 'No focus keyphrase set. Set one to check for mixed intent signals.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const detected = detectIntent(focusKeyphrase.trim());\n const keyphraseIntent = detected.primary;\n\n const plainText = stripHtml(content).toLowerCase();\n\n // Count signals per category\n const categoryCounts: Array<{ key: string; label: string; count: number }> = [];\n for (const category of INTENT_CATEGORIES) {\n const count = countMatches(plainText, category.pattern);\n categoryCounts.push({ key: category.key, label: category.label, count });\n }\n\n // Sort by count descending to find dominant content intent\n const sorted = [...categoryCounts].sort((a, b) => b.count - a.count);\n const dominant = sorted[0];\n\n // Guard for strict indexed access\n if (!dominant) {\n return {\n id: 'intent-mixed-warning',\n title: 'Mixed intent warning',\n description: 'Unable to analyze intent signals in the content.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n // No signals at all\n if (dominant.count === 0) {\n return {\n id: 'intent-mixed-warning',\n title: 'Mixed intent warning',\n description:\n 'No intent signals found in the content. Add intent-appropriate language to strengthen your content focus.',\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n // Identify secondary categories with signals\n const secondaryCategories = sorted.filter(\n (c) => c.key !== keyphraseIntent && c.count > 0,\n );\n\n // Find the keyphrase intent's signal count in content\n const keyphraseIntentCount =\n categoryCounts.find((c) => c.key === keyphraseIntent)?.count ?? 0;\n\n // Check for conflicts: secondary intent signals > 30% of primary keyphrase intent signals\n const conflicting = secondaryCategories.filter((c) => {\n if (keyphraseIntentCount === 0) return c.count > 0;\n return c.count / keyphraseIntentCount > CONFLICT_THRESHOLD;\n });\n\n // Check if dominant content intent contradicts keyphrase intent\n const dominantContradictsKeyphrase =\n dominant.key !== keyphraseIntent && dominant.count > keyphraseIntentCount;\n\n // Build description parts\n const keyphraseLabel =\n INTENT_CATEGORIES.find((c) => c.key === keyphraseIntent)?.label ?? keyphraseIntent;\n const signalSummary = categoryCounts\n .filter((c) => c.count > 0)\n .map((c) => `${c.label}: ${c.count}`)\n .join(', ');\n\n if (dominantContradictsKeyphrase) {\n return {\n id: 'intent-mixed-warning',\n title: 'Mixed intent warning',\n description:\n `Content's dominant intent is ${dominant.label} (${dominant.count} signals), ` +\n `but the keyphrase targets ${keyphraseLabel} intent (${keyphraseIntentCount} signals). ` +\n `Signal breakdown: ${signalSummary}. ` +\n 'Realign content to match the keyphrase intent or choose a different keyphrase.',\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n }\n\n if (conflicting.length > 0) {\n const conflictNames = conflicting\n .map((c) => `${c.label} (${c.count} signals)`)\n .join(', ');\n\n // Heavy mixing: any secondary > 30% but dominant still matches\n const hasHeavyMixing = conflicting.some((c) => {\n if (keyphraseIntentCount === 0) return true;\n return c.count / keyphraseIntentCount > 0.5;\n });\n\n if (hasHeavyMixing) {\n return {\n id: 'intent-mixed-warning',\n title: 'Mixed intent warning',\n description:\n `Heavy intent mixing detected. Keyphrase targets ${keyphraseLabel} intent ` +\n `(${keyphraseIntentCount} signals), but conflicting signals found: ${conflictNames}. ` +\n `Signal breakdown: ${signalSummary}. ` +\n 'Reduce conflicting intent language to strengthen content focus.',\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n }\n\n return {\n id: 'intent-mixed-warning',\n title: 'Mixed intent warning',\n description:\n `Minor intent mixing detected. Keyphrase targets ${keyphraseLabel} intent ` +\n `(${keyphraseIntentCount} signals) with some secondary signals: ${conflictNames}. ` +\n `Signal breakdown: ${signalSummary}. ` +\n 'Consider reducing secondary intent language for clearer focus.',\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n // Check for minor presence of secondary signals (under threshold)\n const minorSecondary = secondaryCategories.filter((c) => c.count > 0);\n if (minorSecondary.length > 0) {\n return {\n id: 'intent-mixed-warning',\n title: 'Mixed intent warning',\n description:\n `Content aligns well with ${keyphraseLabel} intent (${keyphraseIntentCount} signals). ` +\n `Minor secondary signals present but within acceptable range. Signal breakdown: ${signalSummary}.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n return {\n id: 'intent-mixed-warning',\n title: 'Mixed intent warning',\n description:\n `Content cleanly targets ${keyphraseLabel} intent with ${keyphraseIntentCount} signals ` +\n `and no conflicting intent language. Signal breakdown: ${signalSummary}.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — CTA-Intent Alignment Check\n// ----------------------------------------------------------------------------\n// Checks whether calls-to-action (CTAs) in the content match the detected\n// search intent of the focus keyphrase.\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\n// ---------------------------------------------------------------------------\n// CTA patterns per intent category\n// ---------------------------------------------------------------------------\n\ninterface CtaCategory {\n key: string;\n label: string;\n phrases: readonly string[];\n}\n\nconst CTA_CATEGORIES: CtaCategory[] = [\n {\n key: 'informational',\n label: 'Informational',\n phrases: [\n 'read more',\n 'learn more',\n 'discover',\n 'find out',\n 'explore',\n 'see also',\n 'related',\n 'continue reading',\n 'download guide',\n 'subscribe for updates',\n ],\n },\n {\n key: 'transactional',\n label: 'Transactional',\n phrases: [\n 'buy now',\n 'add to cart',\n 'order now',\n 'shop now',\n 'get started',\n 'start free trial',\n 'sign up',\n 'book now',\n 'reserve',\n 'claim offer',\n ],\n },\n {\n key: 'commercial-investigation',\n label: 'Commercial',\n phrases: [\n 'compare plans',\n 'see pricing',\n 'read review',\n 'view comparison',\n 'check availability',\n 'get quote',\n ],\n },\n {\n key: 'navigational',\n label: 'Navigational',\n phrases: [\n 'visit site',\n 'go to',\n 'access',\n 'log in',\n 'open',\n 'launch',\n ],\n },\n];\n\n/**\n * Find all CTA phrases from a category that appear in the text.\n */\nfunction findCtaMatches(text: string, phrases: readonly string[]): string[] {\n const found: string[] = [];\n for (const phrase of phrases) {\n const escaped = phrase.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const re = new RegExp(`\\\\b${escaped}\\\\b`, 'i');\n if (re.test(text)) {\n found.push(phrase);\n }\n }\n return found;\n}\n\n/**\n * Check whether the CTAs found in the content align with the detected intent\n * of the focus keyphrase.\n *\n * - good (5): CTAs align with intent, no conflicting CTAs\n * - ok (3): some CTAs align, some don't, or no CTAs found\n * - poor (1): CTAs contradict intent (e.g., \"buy now\" in informational content)\n */\nexport function checkIntentCtaAlignment(\n input: ContentAnalysisInput,\n): AnalysisResult {\n const { focusKeyphrase, content } = input;\n\n if (!focusKeyphrase || focusKeyphrase.trim().length === 0) {\n return {\n id: 'intent-cta-alignment',\n title: 'CTA-intent alignment',\n description:\n 'No focus keyphrase set. Set one to analyze CTA-intent alignment.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const detected = detectIntent(focusKeyphrase.trim());\n const keyphraseIntent = detected.primary;\n\n const plainText = stripHtml(content).toLowerCase();\n\n // Find CTAs per category\n const ctaResults: Array<{\n key: string;\n label: string;\n matches: string[];\n }> = [];\n\n for (const category of CTA_CATEGORIES) {\n const matches = findCtaMatches(plainText, category.phrases);\n ctaResults.push({\n key: category.key,\n label: category.label,\n matches,\n });\n }\n\n // Separate aligned vs conflicting CTAs\n const alignedCategory = ctaResults.find((c) => c.key === keyphraseIntent);\n const alignedCtas = alignedCategory?.matches ?? [];\n\n const conflictingCategories = ctaResults.filter(\n (c) => c.key !== keyphraseIntent && c.matches.length > 0,\n );\n\n const allConflictingCtas = conflictingCategories.flatMap((c) => c.matches);\n const totalCtasFound = alignedCtas.length + allConflictingCtas.length;\n\n // Get the keyphrase intent label\n const intentLabel =\n CTA_CATEGORIES.find((c) => c.key === keyphraseIntent)?.label ??\n keyphraseIntent;\n\n // No CTAs found at all\n if (totalCtasFound === 0) {\n return {\n id: 'intent-cta-alignment',\n title: 'CTA-intent alignment',\n description:\n `No CTA phrases found in the content. For ${intentLabel.toLowerCase()} intent, ` +\n `consider adding relevant CTAs such as: ${alignedCategory?.matches.length === 0 ? CTA_CATEGORIES.find((c) => c.key === keyphraseIntent)?.phrases.slice(0, 3).join(', ') ?? 'appropriate calls to action' : alignedCtas.join(', ')}.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n // Only conflicting CTAs, no aligned ones\n if (alignedCtas.length === 0 && allConflictingCtas.length > 0) {\n const conflictDetail = conflictingCategories\n .filter((c) => c.matches.length > 0)\n .map((c) => `${c.label}: \"${c.matches.join('\", \"')}\"`)\n .join('; ');\n\n return {\n id: 'intent-cta-alignment',\n title: 'CTA-intent alignment',\n description:\n `CTAs contradict the ${intentLabel.toLowerCase()} intent of the keyphrase. ` +\n `Found conflicting CTAs — ${conflictDetail}. ` +\n `Replace with ${intentLabel.toLowerCase()}-appropriate CTAs.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n }\n\n // Both aligned and conflicting CTAs present\n if (alignedCtas.length > 0 && allConflictingCtas.length > 0) {\n const conflictDetail = conflictingCategories\n .filter((c) => c.matches.length > 0)\n .map((c) => `${c.label}: \"${c.matches.join('\", \"')}\"`)\n .join('; ');\n\n return {\n id: 'intent-cta-alignment',\n title: 'CTA-intent alignment',\n description:\n `Some CTAs align with ${intentLabel.toLowerCase()} intent (\"${alignedCtas.join('\", \"')}\"), ` +\n `but conflicting CTAs were also found — ${conflictDetail}. ` +\n 'Consider removing CTAs that contradict the primary intent.',\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n // All CTAs align with intent\n return {\n id: 'intent-cta-alignment',\n title: 'CTA-intent alignment',\n description:\n `CTAs align well with ${intentLabel.toLowerCase()} intent. ` +\n `Found matching CTAs: \"${alignedCtas.join('\", \"')}\". ` +\n 'No conflicting CTAs detected.',\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Featured Snippet Readiness Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords, extractTagContents } from '@power-seo/core';\n\n// ---------------------------------------------------------------------------\n// Snippet pattern detectors\n// ---------------------------------------------------------------------------\n\ninterface SnippetPattern {\n name: string;\n found: boolean;\n}\n\n/**\n * Check for a definition paragraph within the first 300 words.\n * Google favours concise 40-60 word answers for position zero.\n */\nfunction hasDefinitionParagraph(html: string): boolean {\n const paragraphs = extractTagContents(html, 'p');\n const plainText = stripHtml(html);\n const allWords = getWords(plainText);\n\n // We only care about paragraphs whose text falls within the first 300 words.\n let cumulativeWords = 0;\n\n for (const para of paragraphs) {\n const paraPlain = stripHtml(para);\n const paraWords = getWords(paraPlain);\n\n if (cumulativeWords >= 300) break;\n cumulativeWords += paraWords.length;\n\n // Check length: 40-60 words is Google's sweet spot\n if (paraWords.length < 40 || paraWords.length > 60) continue;\n\n // Check for definitional phrases\n const lower = paraPlain.toLowerCase();\n if (\n /\\bis\\s+a\\b/.test(lower) ||\n /\\brefers\\s+to\\b/.test(lower) ||\n /\\bis\\s+defined\\s+as\\b/.test(lower) ||\n /\\bmeans\\b/.test(lower)\n ) {\n return true;\n }\n }\n\n // Also handle content that doesn't use <p> tags but still has early definition text\n if (paragraphs.length === 0 && allWords.length >= 40) {\n const first300 = allWords.slice(0, 300).join(' ').toLowerCase();\n // Try to find a 40-60 word segment with a definitional phrase\n if (\n /\\bis\\s+a\\b/.test(first300) ||\n /\\brefers\\s+to\\b/.test(first300) ||\n /\\bis\\s+defined\\s+as\\b/.test(first300) ||\n /\\bmeans\\b/.test(first300)\n ) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Check for numbered/ordered list: <ol> with 3+ <li>, or step-pattern headings.\n */\nfunction hasOrderedList(html: string): boolean {\n // Check for <ol> with 3+ items\n const olBlocks = extractTagContents(html, 'ol');\n for (const ol of olBlocks) {\n const items = extractTagContents(ol, 'li');\n if (items.length >= 3) return true;\n }\n\n // Check for step-pattern headings (\"Step 1\", \"Step 2\", etc.)\n const h2s = extractTagContents(html, 'h2');\n const h3s = extractTagContents(html, 'h3');\n const allHeadings = [...h2s, ...h3s];\n\n let stepCount = 0;\n for (const heading of allHeadings) {\n const headingText = stripHtml(heading).toLowerCase();\n if (/step\\s+\\d+/i.test(headingText)) {\n stepCount++;\n }\n }\n\n return stepCount >= 3;\n}\n\n/**\n * Check for bullet/unordered list: <ul> with 3+ <li> items.\n */\nfunction hasBulletList(html: string): boolean {\n const ulBlocks = extractTagContents(html, 'ul');\n for (const ul of ulBlocks) {\n const items = extractTagContents(ul, 'li');\n if (items.length >= 3) return true;\n }\n return false;\n}\n\n/**\n * Check for a table with at least 2 rows.\n */\nfunction hasTable(html: string): boolean {\n const tables = extractTagContents(html, 'table');\n for (const table of tables) {\n const rows = extractTagContents(table, 'tr');\n if (rows.length >= 2) return true;\n }\n return false;\n}\n\n/**\n * Check for question-answer pattern: an H2/H3 that contains a question word,\n * followed by a paragraph of 30-80 words.\n */\nfunction hasQuestionAnswerPattern(html: string): boolean {\n const questionWords = /\\b(?:what|how|why|when|where|who|can|does|is)\\b/i;\n\n // We need to find headings followed by paragraphs in the HTML structure.\n // Strategy: look for h2/h3 openings, check if they contain a question word,\n // then look for the next <p> and check its word count.\n // Find all h2 and h3 positions with their content\n const headingRegex = /<h[23][^>]*>([\\s\\S]*?)<\\/h[23]>/gi;\n let match: RegExpExecArray | null;\n\n while ((match = headingRegex.exec(html)) !== null) {\n const headingContent = match[1];\n if (headingContent === undefined) continue;\n\n const headingText = stripHtml(headingContent);\n\n if (!questionWords.test(headingText)) continue;\n\n // Look for the next <p> tag after this heading\n const afterHeading = html.slice(match.index + match[0].length);\n const nextParagraphs = extractTagContents(afterHeading, 'p');\n const firstParagraph = nextParagraphs[0];\n\n if (firstParagraph !== undefined) {\n const paraText = stripHtml(firstParagraph);\n const paraWordCount = getWords(paraText).length;\n if (paraWordCount >= 30 && paraWordCount <= 80) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Check\n// ---------------------------------------------------------------------------\n\nexport function checkIntentSnippetReadiness(input: ContentAnalysisInput): AnalysisResult {\n const { content, focusKeyphrase } = input;\n\n const patterns: SnippetPattern[] = [\n { name: 'definition paragraph (40-60 words)', found: hasDefinitionParagraph(content) },\n { name: 'numbered/ordered list (3+ items)', found: hasOrderedList(content) },\n { name: 'bullet list (3+ items)', found: hasBulletList(content) },\n { name: 'data table (2+ rows)', found: hasTable(content) },\n { name: 'question-answer pattern', found: hasQuestionAnswerPattern(content) },\n ];\n\n const found = patterns.filter((p) => p.found);\n const missing = patterns.filter((p) => !p.found);\n const count = found.length;\n\n const keyphraseNote =\n !focusKeyphrase || focusKeyphrase.trim().length === 0\n ? ' No focus keyphrase set — snippet patterns still matter but targeting improves with one.'\n : '';\n\n // good (5): 3+ snippet patterns\n if (count >= 3) {\n const foundNames = found.map((p) => p.name).join(', ');\n return {\n id: 'intent-snippet-readiness',\n title: 'Featured snippet readiness',\n description: `Content has ${count} snippet-ready patterns: ${foundNames}. Well-structured for position zero.${keyphraseNote}`,\n status: 'good',\n score: 5,\n maxScore: 6,\n };\n }\n\n // ok (3): 1-2 snippet patterns\n if (count >= 1) {\n const foundNames = found.map((p) => p.name).join(', ');\n const missingNames = missing.map((p) => p.name).join(', ');\n return {\n id: 'intent-snippet-readiness',\n title: 'Featured snippet readiness',\n description: `Found ${count} snippet pattern${count === 1 ? '' : 's'}: ${foundNames}. Consider adding: ${missingNames}.${keyphraseNote}`,\n status: 'ok',\n score: 3,\n maxScore: 6,\n };\n }\n\n // poor (0): no snippet patterns\n const missingNames = missing.map((p) => p.name).join(', ');\n return {\n id: 'intent-snippet-readiness',\n title: 'Featured snippet readiness',\n description: `No snippet-ready patterns found. Add at least one of: ${missingNames}. These structures help win Google's featured snippet (position zero).${keyphraseNote}`,\n status: 'poor',\n score: 0,\n maxScore: 6,\n };\n}\n","// @power-seo/content-analysis — Rich Result Schema Readiness Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords, extractTagContents } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\n// ---------------------------------------------------------------------------\n// Schema type detectors\n// ---------------------------------------------------------------------------\n\ninterface SchemaCandidate {\n type: string;\n applicable: boolean;\n reason: string;\n implementation: string;\n}\n\n/**\n * FAQPage: 2+ headings that are questions, each followed by answer paragraphs.\n */\nfunction checkFAQPage(html: string): SchemaCandidate {\n const questionWords = /\\b(?:who|what|when|where|why|how|can|does|is)\\b/i;\n\n let questionHeadingCount = 0;\n\n // Use regex to find headings followed by paragraph content\n const headingRegex = /<h[23][^>]*>([\\s\\S]*?)<\\/h[23]>/gi;\n let match: RegExpExecArray | null;\n\n while ((match = headingRegex.exec(html)) !== null) {\n const headingContent = match[1];\n if (headingContent === undefined) continue;\n\n const headingText = stripHtml(headingContent);\n if (!questionWords.test(headingText) && !headingText.includes('?')) continue;\n\n // Check that a paragraph follows\n const afterHeading = html.slice(match.index + match[0].length);\n const nextParagraphs = extractTagContents(afterHeading, 'p');\n const firstPara = nextParagraphs[0];\n\n if (firstPara !== undefined) {\n const paraText = stripHtml(firstPara);\n if (getWords(paraText).length >= 5) {\n questionHeadingCount++;\n }\n }\n }\n\n return {\n type: 'FAQPage',\n applicable: questionHeadingCount >= 2,\n reason: questionHeadingCount >= 2\n ? `${questionHeadingCount} question-answer pairs detected in headings`\n : 'Needs 2+ headings phrased as questions with answer paragraphs',\n implementation: 'Add FAQPage schema with @type Question/Answer for each pair',\n };\n}\n\n/**\n * HowTo: Step-by-step structure — ordered list or \"Step N:\" patterns, 3+ steps.\n */\nfunction checkHowTo(html: string): SchemaCandidate {\n let stepCount = 0;\n\n // Check for <ol> with 3+ <li>\n const olBlocks = extractTagContents(html, 'ol');\n for (const ol of olBlocks) {\n const items = extractTagContents(ol, 'li');\n if (items.length >= 3) {\n stepCount = Math.max(stepCount, items.length);\n }\n }\n\n // Check for step-pattern headings\n const h2s = extractTagContents(html, 'h2');\n const h3s = extractTagContents(html, 'h3');\n const allHeadings = [...h2s, ...h3s];\n\n let stepHeadingCount = 0;\n for (const heading of allHeadings) {\n const headingText = stripHtml(heading);\n if (/step\\s+\\d+/i.test(headingText)) {\n stepHeadingCount++;\n }\n }\n stepCount = Math.max(stepCount, stepHeadingCount);\n\n return {\n type: 'HowTo',\n applicable: stepCount >= 3,\n reason: stepCount >= 3\n ? `${stepCount}-step structure detected`\n : 'Needs ordered list or \"Step N:\" headings with 3+ steps',\n implementation: 'Add HowTo schema with @type HowToStep for each step',\n };\n}\n\n/**\n * Product: Transactional content with price mentions, product name in title,\n * specs/features sections.\n */\nfunction checkProduct(html: string, input: ContentAnalysisInput): SchemaCandidate {\n const plainText = stripHtml(html);\n const lower = plainText.toLowerCase();\n const detected = input.focusKeyphrase\n ? detectIntent(input.focusKeyphrase)\n : null;\n\n let signals = 0;\n const details: string[] = [];\n\n // Price mentions: $X.XX or \"price:\"\n if (/\\$\\d+(?:\\.\\d{2})?/.test(plainText) || /\\bprice\\s*:/i.test(plainText)) {\n signals++;\n details.push('price info');\n }\n\n // Transactional intent\n if (detected && (detected.primary === 'transactional' || detected.primary === 'commercial-investigation')) {\n signals++;\n details.push('transactional/commercial intent');\n }\n\n // Product name in title\n if (input.title && input.focusKeyphrase) {\n const titleLower = input.title.toLowerCase();\n const keyphraseLower = input.focusKeyphrase.toLowerCase();\n if (titleLower.includes(keyphraseLower)) {\n signals++;\n details.push('keyphrase in title');\n }\n }\n\n // Specs/features sections\n if (\n /\\b(?:specifications|specs|features|dimensions|weight|compatibility)\\b/i.test(lower)\n ) {\n signals++;\n details.push('specs/features section');\n }\n\n const applicable = signals >= 2;\n return {\n type: 'Product',\n applicable,\n reason: applicable\n ? `Product signals: ${details.join(', ')}`\n : 'Needs price info, product name in title, and specs/features sections',\n implementation: 'Add Product schema with name, description, offers, and brand',\n };\n}\n\n/**\n * Review/AggregateRating: Rating patterns, pros/cons, verdict sections.\n */\nfunction checkReview(html: string): SchemaCandidate {\n const plainText = stripHtml(html);\n const lower = plainText.toLowerCase();\n\n let signals = 0;\n const details: string[] = [];\n\n // Rating patterns: \"/5\", \"/10\", \"stars\", \"score:\"\n if (/\\/\\s*5\\b/.test(plainText) || /\\/\\s*10\\b/.test(plainText)) {\n signals++;\n details.push('rating scale');\n }\n if (/\\bstars?\\b/i.test(plainText)) {\n signals++;\n details.push('star rating');\n }\n if (/\\bscore\\s*:/i.test(plainText)) {\n signals++;\n details.push('score mention');\n }\n\n // Pros/cons sections\n if (/\\b(?:pros|advantages)\\b/i.test(lower) && /\\b(?:cons|disadvantages)\\b/i.test(lower)) {\n signals++;\n details.push('pros/cons');\n }\n\n // Verdict/conclusion\n if (/\\b(?:verdict|final\\s+(?:thoughts|verdict)|conclusion|bottom\\s+line)\\b/i.test(lower)) {\n signals++;\n details.push('verdict/conclusion');\n }\n\n const applicable = signals >= 2;\n return {\n type: 'Review',\n applicable,\n reason: applicable\n ? `Review signals: ${details.join(', ')}`\n : 'Needs rating patterns (/5, stars), pros/cons, and verdict sections',\n implementation: 'Add Review schema with reviewRating, author, and itemReviewed',\n };\n}\n\n/**\n * Article: Has author info, publish date, and content > 300 words.\n */\nfunction checkArticle(input: ContentAnalysisInput): SchemaCandidate {\n const plainText = stripHtml(input.content);\n const wordCount = getWords(plainText).length;\n\n let signals = 0;\n const details: string[] = [];\n\n if (input.author?.name) {\n signals++;\n details.push('author name');\n }\n\n if (input.publishDate) {\n signals++;\n details.push('publish date');\n }\n\n if (wordCount > 300) {\n signals++;\n details.push(`${wordCount} words`);\n }\n\n const applicable = signals >= 2;\n return {\n type: 'Article',\n applicable,\n reason: applicable\n ? `Article signals: ${details.join(', ')}`\n : 'Needs author name, publish date, and 300+ words',\n implementation: 'Add Article schema with headline, author, datePublished, and publisher',\n };\n}\n\n// ---------------------------------------------------------------------------\n// Check\n// ---------------------------------------------------------------------------\n\nexport function checkIntentSchemaReadiness(input: ContentAnalysisInput): AnalysisResult {\n const { content } = input;\n const plainText = stripHtml(content);\n const wordCount = getWords(plainText).length;\n\n // Too short — can't meaningfully assess schema readiness\n if (wordCount < 100) {\n return {\n id: 'intent-schema-readiness',\n title: 'Rich result schema readiness',\n description: `Content is only ${wordCount} words. At least 100 words are needed to assess rich result schema opportunities.`,\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const candidates: SchemaCandidate[] = [\n checkFAQPage(content),\n checkHowTo(content),\n checkProduct(content, input),\n checkReview(content),\n checkArticle(input),\n ];\n\n const applicable = candidates.filter((c) => c.applicable);\n const notApplicable = candidates.filter((c) => !c.applicable);\n const count = applicable.length;\n\n // good (5): 2+ applicable schemas\n if (count >= 2) {\n const schemaList = applicable\n .map((c) => `${c.type} (${c.reason})`)\n .join('; ');\n const implList = applicable\n .map((c) => `${c.type}: ${c.implementation}`)\n .join('. ');\n return {\n id: 'intent-schema-readiness',\n title: 'Rich result schema readiness',\n description: `${count} rich result schemas applicable: ${schemaList}. Implementation: ${implList}.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n // ok (3): 1 schema applicable\n if (count === 1) {\n const schema = applicable[0];\n if (schema === undefined) {\n // Safety guard — should never happen since count === 1\n return {\n id: 'intent-schema-readiness',\n title: 'Rich result schema readiness',\n description: 'Unable to determine applicable schemas.',\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n }\n\n const closestMiss = notApplicable[0];\n const suggestion = closestMiss !== undefined\n ? ` Consider restructuring for ${closestMiss.type}: ${closestMiss.reason}.`\n : '';\n\n return {\n id: 'intent-schema-readiness',\n title: 'Rich result schema readiness',\n description: `1 rich result schema applicable: ${schema.type} (${schema.reason}). ${schema.implementation}.${suggestion}`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n // poor (1): no schemas applicable\n const suggestions = notApplicable\n .slice(0, 3)\n .map((c) => `${c.type}: ${c.reason}`)\n .join('; ');\n return {\n id: 'intent-schema-readiness',\n title: 'Rich result schema readiness',\n description: `Content structure does not support any rich result schemas. To qualify, address: ${suggestions}.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — People Also Ask Coverage Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, extractTagContents } from '@power-seo/core';\n\n// ---------------------------------------------------------------------------\n// Question detection\n// ---------------------------------------------------------------------------\n\nconst QUESTION_STARTERS = /\\b(?:what|how|why|when|where|who|can|does|do|is|are|should|will|which)\\b/i;\n\n/**\n * Determine whether a heading text is a question pattern.\n * Matches headings that start with or contain PAA-style question words,\n * or headings that end with a question mark.\n */\nfunction isQuestionHeading(headingText: string): boolean {\n const trimmed = headingText.trim();\n if (trimmed.length === 0) return false;\n\n // Explicit question mark\n if (trimmed.includes('?')) return true;\n\n // Contains a question word\n if (QUESTION_STARTERS.test(trimmed)) return true;\n\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Check\n// ---------------------------------------------------------------------------\n\nexport function checkIntentPaaCoverage(input: ContentAnalysisInput): AnalysisResult {\n const { content } = input;\n\n // Extract all H2 and H3 headings\n const h2s = extractTagContents(content, 'h2');\n const h3s = extractTagContents(content, 'h3');\n const allHeadingHtmls = [...h2s, ...h3s];\n\n // Convert to plain text\n const allHeadings: string[] = [];\n for (const h of allHeadingHtmls) {\n const text = stripHtml(h).trim();\n if (text.length > 0) {\n allHeadings.push(text);\n }\n }\n\n // No headings at all\n if (allHeadings.length === 0) {\n return {\n id: 'intent-paa-coverage',\n title: 'People Also Ask coverage',\n description: 'No H2 or H3 headings found in the content. Add headings — especially question-phrased headings — to target \"People Also Ask\" boxes in Google.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n // Find question headings\n const questionHeadings: string[] = [];\n for (const heading of allHeadings) {\n if (isQuestionHeading(heading)) {\n questionHeadings.push(heading);\n }\n }\n\n const count = questionHeadings.length;\n\n // Build example list (up to 3 examples)\n const exampleLimit = Math.min(count, 3);\n const examples: string[] = [];\n for (let i = 0; i < exampleLimit; i++) {\n const example = questionHeadings[i];\n if (example !== undefined) {\n examples.push(`\"${example}\"`);\n }\n }\n const exampleText = examples.length > 0 ? ` Examples: ${examples.join(', ')}.` : '';\n\n // good (5): >= 4 question headings\n if (count >= 4) {\n return {\n id: 'intent-paa-coverage',\n title: 'People Also Ask coverage',\n description: `${count} question-phrased headings found out of ${allHeadings.length} total H2/H3 headings.${exampleText} Well-optimized for PAA visibility.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n // ok (3): 2-3 question headings\n if (count >= 2) {\n const needed = 4 - count;\n return {\n id: 'intent-paa-coverage',\n title: 'People Also Ask coverage',\n description: `${count} question-phrased heading${count === 1 ? '' : 's'} found out of ${allHeadings.length} total.${exampleText} Add ${needed} more question headings (What, How, Why, etc.) to improve PAA coverage.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n // poor (1): 1 question heading\n if (count === 1) {\n return {\n id: 'intent-paa-coverage',\n title: 'People Also Ask coverage',\n description: `Only 1 question-phrased heading found out of ${allHeadings.length} total.${exampleText} Add at least 3 more question headings starting with What, How, Why, When, Where, Who, Can, Does, Is, Are, Should, Will, or Which.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n }\n\n // poor (0): no question headings\n return {\n id: 'intent-paa-coverage',\n title: 'People Also Ask coverage',\n description: `None of the ${allHeadings.length} H2/H3 headings use question phrasing. Rephrase headings as questions (e.g. \"What is X?\", \"How does Y work?\") to target Google's \"People Also Ask\" feature.`,\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Search Satisfaction Score Check\n// ----------------------------------------------------------------------------\n// Composite check estimating if content fully resolves the searcher's query\n// by evaluating 6 satisfaction signals specific to the detected intent type.\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\n// ---------------------------------------------------------------------------\n// Signal checkers per intent type\n// ---------------------------------------------------------------------------\n\ninterface SignalResult {\n name: string;\n present: boolean;\n}\n\nfunction checkInformationalSignals(\n plainText: string,\n contentLower: string,\n): SignalResult[] {\n const textLower = plainText.toLowerCase();\n const words = getWords(plainText);\n const wordCount = words.length;\n\n // Count H2/H3 subheadings\n const h2Count = contentLower.split('<h2').length - 1;\n const h3Count = contentLower.split('<h3').length - 1;\n const headingCount = h2Count + h3Count;\n\n return [\n {\n name: 'Answer clarity',\n present: /\\b(?:is a|means|refers to)\\b/i.test(plainText),\n },\n {\n name: 'Examples',\n present: /\\b(?:for example|for instance|such as|e\\.g\\.)\\b/i.test(plainText),\n },\n {\n name: 'Summary/takeaway',\n present: /\\b(?:in summary|key takeaway|conclusion|to summarize|bottom line)\\b/i.test(plainText),\n },\n {\n name: 'Depth (800+ words)',\n present: wordCount >= 800,\n },\n {\n name: 'Structure (3+ subheadings)',\n present: headingCount >= 3,\n },\n {\n name: 'Next steps',\n present: /\\b(?:next step|learn more|read also|related|see also)\\b/i.test(textLower),\n },\n ];\n}\n\nfunction checkTransactionalSignals(\n plainText: string,\n _contentLower: string,\n): SignalResult[] {\n const textLower = plainText.toLowerCase();\n\n return [\n {\n name: 'Product info',\n present: /\\b(?:spec|specs|specifications?|features?|details?)\\b/i.test(textLower),\n },\n {\n name: 'Pricing',\n present: /\\b(?:price|cost|pricing)\\b/i.test(textLower) || textLower.includes('$'),\n },\n {\n name: 'CTA',\n present: /\\b(?:buy|order|get started)\\b/i.test(textLower),\n },\n {\n name: 'Trust signals',\n present: /\\b(?:guarantee|warranty|secure|money.back)\\b/i.test(textLower),\n },\n {\n name: 'Logistics',\n present: /\\b(?:shipping|delivery|availability|in stock)\\b/i.test(textLower),\n },\n {\n name: 'Social proof',\n present: /\\b(?:reviews?|testimonials?|ratings?|customers? say)\\b/i.test(textLower),\n },\n ];\n}\n\nfunction checkCommercialSignals(\n plainText: string,\n contentLower: string,\n): SignalResult[] {\n const textLower = plainText.toLowerCase();\n\n // Check for multiple product/service mentions (simple heuristic: 2+ capitalized\n // multi-word proper nouns or brand-like words near \"vs\" / list context)\n const productMentions = plainText.match(/\\b[A-Z][a-zA-Z]+(?:\\s[A-Z][a-zA-Z]+)*\\b/g);\n const uniqueProducts = productMentions ? new Set(productMentions).size : 0;\n\n return [\n {\n name: 'Multiple options',\n present: uniqueProducts >= 2,\n },\n {\n name: 'Comparison',\n present: /\\b(?:vs|versus|compared|comparison)\\b/i.test(textLower)\n || contentLower.includes('<table'),\n },\n {\n name: 'Verdict',\n present: /\\b(?:recommendation|winner|our pick|best overall|top pick|verdict)\\b/i.test(textLower),\n },\n {\n name: 'Criteria',\n present: /\\b(?:criteria|factors?|what to look for|how to choose|we evaluated|we tested)\\b/i.test(textLower),\n },\n {\n name: 'Pricing comparison',\n present: /\\b(?:price|cost|pricing|starts at|per month|free plan)\\b/i.test(textLower),\n },\n {\n name: 'Pros/cons',\n present: /\\b(?:pros|cons|advantages?|disadvantages?|strengths?|weaknesses?)\\b/i.test(textLower),\n },\n ];\n}\n\nfunction checkNavigationalSignals(\n plainText: string,\n contentLower: string,\n): SignalResult[] {\n const textLower = plainText.toLowerCase();\n const words = getWords(plainText);\n const wordCount = words.length;\n\n // Check for external links\n const hasExternalLink = /<a\\s[^>]*href\\s*=\\s*[\"']https?:\\/\\//i.test(contentLower);\n\n return [\n {\n name: 'Target found',\n present: /\\b(?:official|homepage|website|portal)\\b/i.test(textLower),\n },\n {\n name: 'Direct link',\n present: hasExternalLink,\n },\n {\n name: 'Concise',\n present: wordCount <= 500,\n },\n {\n name: 'Contact info',\n present: /\\b(?:contact|email|phone|address|call us|reach us)\\b/i.test(textLower),\n },\n {\n name: 'Clear path',\n present: /\\b(?:click here|go to|visit|navigate|find it at|head to)\\b/i.test(textLower),\n },\n {\n name: 'Freshness',\n present: /\\b(?:updated|as of|current|latest|new|20\\d{2})\\b/i.test(textLower),\n },\n ];\n}\n\n// ---------------------------------------------------------------------------\n// Check\n// ---------------------------------------------------------------------------\n\nexport function checkIntentSatisfactionScore(\n input: ContentAnalysisInput,\n): AnalysisResult {\n const id = 'intent-satisfaction-score';\n const title = 'Search satisfaction score';\n\n if (!input.focusKeyphrase || input.focusKeyphrase.trim().length === 0) {\n return {\n id,\n title,\n description: 'No focus keyphrase set. Set one to evaluate search satisfaction.',\n status: 'na',\n score: 0,\n maxScore: 10,\n };\n }\n\n const detected = detectIntent(input.focusKeyphrase);\n const intentLabel =\n detected.primary === 'commercial-investigation'\n ? 'commercial'\n : detected.primary;\n\n const plainText = stripHtml(input.content);\n const contentLower = input.content.toLowerCase();\n\n let signals: SignalResult[];\n switch (detected.primary) {\n case 'informational':\n signals = checkInformationalSignals(plainText, contentLower);\n break;\n case 'transactional':\n signals = checkTransactionalSignals(plainText, contentLower);\n break;\n case 'commercial-investigation':\n signals = checkCommercialSignals(plainText, contentLower);\n break;\n case 'navigational':\n signals = checkNavigationalSignals(plainText, contentLower);\n break;\n default:\n signals = checkInformationalSignals(plainText, contentLower);\n }\n\n const presentSignals = signals.filter((s) => s.present);\n const missingSignals = signals.filter((s) => !s.present);\n const presentCount = presentSignals.length;\n\n const presentList = presentSignals.map((s) => s.name).join(', ');\n const missingList = missingSignals.map((s) => s.name).join(', ');\n\n // good (5): 5-6 signals\n if (presentCount >= 5) {\n return {\n id,\n title,\n description:\n `Excellent search satisfaction for ${intentLabel} intent (${presentCount}/6 signals). ` +\n `Present: ${presentList}.` +\n (missingSignals.length > 0 ? ` Consider adding: ${missingList}.` : ''),\n status: 'good',\n score: 5,\n maxScore: 10,\n };\n }\n\n // ok (3): 3-4 signals\n if (presentCount >= 3) {\n return {\n id,\n title,\n description:\n `Acceptable search satisfaction for ${intentLabel} intent (${presentCount}/6 signals). ` +\n `Present: ${presentList}. Missing: ${missingList}.`,\n status: 'ok',\n score: 3,\n maxScore: 10,\n };\n }\n\n // poor (1): 1-2 signals\n if (presentCount >= 1) {\n return {\n id,\n title,\n description:\n `Low search satisfaction for ${intentLabel} intent (${presentCount}/6 signals). ` +\n `Present: ${presentList}. Missing: ${missingList}. ` +\n `Content may not fully resolve the searcher's query.`,\n status: 'poor',\n score: 1,\n maxScore: 10,\n };\n }\n\n // poor (0): 0 signals\n return {\n id,\n title,\n description:\n `No satisfaction signals found for ${intentLabel} intent (0/6 signals). ` +\n `Missing: ${missingList}. Content is unlikely to resolve the searcher's query.`,\n status: 'poor',\n score: 0,\n maxScore: 10,\n };\n}\n","// @power-seo/content-analysis — User Journey Funnel Position Check\n// ----------------------------------------------------------------------------\n// Maps detected intent to a buyer journey stage and checks whether internal\n// links guide users to the NEXT funnel stage.\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\n// ---------------------------------------------------------------------------\n// Funnel stage mapping\n// ---------------------------------------------------------------------------\n\ninterface FunnelStage {\n name: string;\n label: string;\n nextStage: string;\n nextStageAnchors: readonly string[];\n}\n\nconst FUNNEL_STAGES: Record<string, FunnelStage> = {\n informational: {\n name: 'Awareness',\n label: 'awareness',\n nextStage: 'Consideration',\n nextStageAnchors: ['compare', 'review', 'best', 'see options', 'which one'],\n },\n 'commercial-investigation': {\n name: 'Consideration',\n label: 'consideration',\n nextStage: 'Decision',\n nextStageAnchors: ['buy', 'pricing', 'get started', 'order', 'try'],\n },\n transactional: {\n name: 'Decision',\n label: 'decision',\n nextStage: 'Retention',\n nextStageAnchors: ['support', 'help', 'guide', 'getting started', 'dashboard'],\n },\n navigational: {\n name: 'Retention/Loyalty',\n label: 'retention/loyalty',\n nextStage: 'none',\n nextStageAnchors: [],\n },\n};\n\n// ---------------------------------------------------------------------------\n// Internal link extraction\n// ---------------------------------------------------------------------------\n\ninterface ExtractedLink {\n href: string;\n anchorText: string;\n}\n\nfunction extractInternalLinks(\n content: string,\n siteUrl: string | undefined,\n): ExtractedLink[] {\n const links: ExtractedLink[] = [];\n // Match <a> tags with href and capture anchor text\n const linkRegex = /<a\\s[^>]*href\\s*=\\s*[\"']([^\"']*)[\"'][^>]*>([\\s\\S]*?)<\\/a>/gi;\n\n let match: RegExpExecArray | null;\n while ((match = linkRegex.exec(content)) !== null) {\n const href = match[1];\n const anchorRaw = match[2];\n if (href === undefined || anchorRaw === undefined) continue;\n\n const isExternal = /^https?:\\/\\//i.test(href);\n const matchesSiteUrl =\n siteUrl !== undefined &&\n siteUrl.length > 0 &&\n href.toLowerCase().startsWith(siteUrl.toLowerCase());\n\n // Internal link: either relative (no http) or matches siteUrl\n if (!isExternal || matchesSiteUrl) {\n // Strip HTML from anchor text\n const anchorText = anchorRaw.replace(/<[^>]*>/g, '').trim();\n links.push({ href, anchorText });\n }\n }\n\n return links;\n}\n\n// ---------------------------------------------------------------------------\n// Check for next-stage anchor text\n// ---------------------------------------------------------------------------\n\nfunction hasNextStageLinks(\n internalLinks: ExtractedLink[],\n nextStageAnchors: readonly string[],\n): boolean {\n if (nextStageAnchors.length === 0) return false;\n\n for (const link of internalLinks) {\n const anchorLower = link.anchorText.toLowerCase();\n for (const anchor of nextStageAnchors) {\n if (anchorLower.includes(anchor)) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Check\n// ---------------------------------------------------------------------------\n\nexport function checkIntentFunnelPosition(\n input: ContentAnalysisInput,\n): AnalysisResult {\n const id = 'intent-funnel-position';\n const title = 'User journey funnel position';\n\n if (!input.focusKeyphrase || input.focusKeyphrase.trim().length === 0) {\n return {\n id,\n title,\n description: 'No focus keyphrase set. Set one to evaluate funnel position.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const detected = detectIntent(input.focusKeyphrase);\n const stage = FUNNEL_STAGES[detected.primary];\n\n // Cannot determine funnel position\n if (!stage) {\n return {\n id,\n title,\n description:\n `Cannot determine funnel position for intent \"${detected.primary}\". ` +\n `Ensure the keyphrase clearly signals a search intent type.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n }\n\n const internalLinks = extractInternalLinks(input.content, input.siteUrl);\n\n // Navigational (retention) is the final stage — no \"next stage\" to link to\n if (detected.primary === 'navigational') {\n return {\n id,\n title,\n description:\n `Content maps to the ${stage.name} stage (final funnel stage). ` +\n `This is the end of the buyer journey — focus on user satisfaction and re-engagement.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n const foundNextStageLinks = hasNextStageLinks(\n internalLinks,\n stage.nextStageAnchors,\n );\n\n // good (5): funnel position identified AND next-stage links present\n if (foundNextStageLinks) {\n return {\n id,\n title,\n description:\n `Content maps to the ${stage.name} stage and includes links guiding users to the ${stage.nextStage} stage. ` +\n `This supports a smooth buyer journey progression.`,\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n // ok (3): funnel position identified but no next-stage links (dead-end content)\n return {\n id,\n title,\n description:\n `Content maps to the ${stage.name} stage but lacks internal links to ${stage.nextStage} content. ` +\n `This creates a dead-end in the buyer journey. Add links with anchor text like ` +\n `\"${stage.nextStageAnchors.join('\", \"')}\" to guide users to the next stage.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Related Intent Coverage Check\n// ----------------------------------------------------------------------------\n// Checks if content addresses secondary/related intents that searchers\n// commonly have alongside the primary query, reducing the need for follow-up\n// searches.\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\n// ---------------------------------------------------------------------------\n// Related intent definitions per primary sub-intent pattern\n// ---------------------------------------------------------------------------\n\ninterface RelatedIntent {\n name: string;\n /** Pattern to detect if this related intent is addressed in content */\n pattern: RegExp;\n}\n\ninterface SubIntentMapping {\n /** Pattern to detect if the keyphrase matches this sub-intent */\n keyphrasePattern: RegExp;\n label: string;\n relatedIntents: RelatedIntent[];\n}\n\nconst SUB_INTENT_MAPPINGS: readonly SubIntentMapping[] = [\n {\n keyphrasePattern: /\\bhow to\\b/i,\n label: '\"how to\" article',\n relatedIntents: [\n {\n name: '\"what is\" (definitional)',\n pattern: /\\b(?:what is|what are|definition|refers to|is a type of)\\b/i,\n },\n {\n name: '\"why\" (motivation)',\n pattern: /\\b(?:why you should|why it matters|the reason|benefits of|importance of)\\b/i,\n },\n {\n name: 'common mistakes',\n pattern: /\\b(?:mistakes?|avoid|common errors?|pitfalls?|don't)\\b/i,\n },\n {\n name: 'tools/resources',\n pattern: /\\b(?:tools?|resources?|software|apps?|platforms?|you'll need)\\b/i,\n },\n ],\n },\n {\n keyphrasePattern: /\\bbest\\b/i,\n label: '\"best X\" query',\n relatedIntents: [\n {\n name: '\"how to choose\"',\n pattern: /\\b(?:how to choose|how to pick|what to look for|factors to consider|buying guide)\\b/i,\n },\n {\n name: '\"what to look for\"',\n pattern: /\\b(?:features?|criteria|specifications?|requirements?|must.have)\\b/i,\n },\n {\n name: 'budget options',\n pattern: /\\b(?:budget|affordable|cheap|free|value for money|bang for buck)\\b/i,\n },\n {\n name: 'use-case recommendations',\n pattern: /\\b(?:for beginners?|for professionals?|for small business|for enterprise|use case)\\b/i,\n },\n ],\n },\n {\n keyphrasePattern: /\\bbuy\\b/i,\n label: '\"buy X\" query',\n relatedIntents: [\n {\n name: '\"X review\"',\n pattern: /\\b(?:reviews?|ratings?|rated|tested|hands.on|our verdict)\\b/i,\n },\n {\n name: '\"X alternatives\"',\n pattern: /\\b(?:alternatives?|similar to|instead of|competitors?|other options?)\\b/i,\n },\n {\n name: 'warranty/support',\n pattern: /\\b(?:warranty|guarantee|support|return policy|customer service)\\b/i,\n },\n {\n name: 'setup/getting started',\n pattern: /\\b(?:setup|set up|getting started|installation|unboxing)\\b/i,\n },\n ],\n },\n {\n keyphrasePattern: /\\b(?:vs|versus)\\b/i,\n label: '\"X vs Y\" comparison',\n relatedIntents: [\n {\n name: '\"which is better\"',\n pattern: /\\b(?:which is better|winner|our pick|verdict|recommendation)\\b/i,\n },\n {\n name: '\"when to use X vs Y\"',\n pattern: /\\b(?:when to use|best for|ideal for|suited for|use case|scenario)\\b/i,\n },\n {\n name: 'key differences',\n pattern: /\\b(?:key differences?|main differences?|differs? from|unlike|whereas)\\b/i,\n },\n {\n name: 'pricing comparison',\n pattern: /\\b(?:pricing|price|cost|plans?|subscription|free tier)\\b/i,\n },\n ],\n },\n {\n keyphrasePattern: /\\b(?:what is|what are)\\b/i,\n label: '\"what is X\" query',\n relatedIntents: [\n {\n name: '\"how to use X\"',\n pattern: /\\b(?:how to use|how to implement|how to apply|getting started|step.by.step)\\b/i,\n },\n {\n name: '\"X examples\"',\n pattern: /\\b(?:examples?|for instance|for example|such as|use cases?|real.world)\\b/i,\n },\n {\n name: 'types/categories',\n pattern: /\\b(?:types? of|categories|kinds? of|varieties|classification)\\b/i,\n },\n {\n name: 'history/background',\n pattern: /\\b(?:history|background|origin|evolution|development|invented|created)\\b/i,\n },\n ],\n },\n] as const;\n\n// ---------------------------------------------------------------------------\n// Check\n// ---------------------------------------------------------------------------\n\nexport function checkIntentRelatedCoverage(\n input: ContentAnalysisInput,\n): AnalysisResult {\n const id = 'intent-related-coverage';\n const title = 'Related intent coverage';\n\n if (!input.focusKeyphrase || input.focusKeyphrase.trim().length === 0) {\n return {\n id,\n title,\n description: 'No focus keyphrase set. Set one to evaluate related intent coverage.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const keyphrase = input.focusKeyphrase.trim();\n const plainText = stripHtml(input.content);\n\n // Find the matching sub-intent mapping\n let matchedMapping: SubIntentMapping | undefined;\n for (const mapping of SUB_INTENT_MAPPINGS) {\n if (mapping.keyphrasePattern.test(keyphrase)) {\n matchedMapping = mapping;\n break;\n }\n }\n\n // If no sub-intent pattern matches, we cannot evaluate\n if (!matchedMapping) {\n // Fallback: use detected intent to give a generic assessment\n const detected = detectIntent(keyphrase);\n const intentLabel =\n detected.primary === 'commercial-investigation'\n ? 'commercial'\n : detected.primary;\n return {\n id,\n title,\n description:\n `Could not determine a specific sub-intent pattern for this ${intentLabel} keyphrase. ` +\n `Consider adding related topics that users commonly search for alongside \"${keyphrase}\".`,\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n }\n\n // Check which related intents are addressed\n const covered: string[] = [];\n const missing: string[] = [];\n\n for (const related of matchedMapping.relatedIntents) {\n if (related.pattern.test(plainText)) {\n covered.push(related.name);\n } else {\n missing.push(related.name);\n }\n }\n\n const coveredCount = covered.length;\n const coveredList = covered.join(', ');\n const missingList = missing.join(', ');\n\n // good (5): 3+ related intents addressed\n if (coveredCount >= 3) {\n return {\n id,\n title,\n description:\n `Excellent related intent coverage for a ${matchedMapping.label} (${coveredCount}/${matchedMapping.relatedIntents.length} related intents). ` +\n `Covered: ${coveredList}.` +\n (missing.length > 0 ? ` Consider also addressing: ${missingList}.` : ''),\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n // ok (3): 1-2 related intents\n if (coveredCount >= 1) {\n return {\n id,\n title,\n description:\n `Partial related intent coverage for a ${matchedMapping.label} (${coveredCount}/${matchedMapping.relatedIntents.length} related intents). ` +\n `Covered: ${coveredList}. Missing: ${missingList}. ` +\n `Address missing intents to reduce follow-up searches.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n // poor (0): no related intents addressed\n return {\n id,\n title,\n description:\n `No related intents addressed for a ${matchedMapping.label}. ` +\n `Missing: ${missingList}. ` +\n `Content may cause users to search again for these related topics.`,\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — Engagement Signal Optimization Check\n// ----------------------------------------------------------------------------\n// Checks for elements that reduce pogo-sticking (user bouncing back to search\n// results) by evaluating 7 engagement signals in the content.\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\nimport { detectIntent } from './intent-utils.js';\n\n// ---------------------------------------------------------------------------\n// Signal checkers\n// ---------------------------------------------------------------------------\n\ninterface EngagementSignal {\n name: string;\n present: boolean;\n}\n\nfunction checkTableOfContents(content: string): boolean {\n const contentLower = content.toLowerCase();\n\n // Check for explicit TOC text\n const hasTocText = /\\b(?:table of contents|in this article|jump to)\\b/i.test(\n contentLower,\n );\n if (hasTocText) return true;\n\n // Check for \"contents\" as a heading\n if (/<h[1-6][^>]*>\\s*contents\\s*<\\/h[1-6]>/i.test(content)) return true;\n\n // Check for an early list of anchor links (#section style)\n // Look for 3+ anchor links with # hrefs in the first 20% of content\n const contentLength = content.length;\n const earlySection = content.slice(0, Math.floor(contentLength * 0.2));\n const anchorLinkMatches = earlySection.match(/href\\s*=\\s*[\"']#[^\"']+[\"']/gi);\n if (anchorLinkMatches && anchorLinkMatches.length >= 3) return true;\n\n return false;\n}\n\nfunction checkSubheadings(content: string): boolean {\n const contentLower = content.toLowerCase();\n const h2Count = contentLower.split('<h2').length - 1;\n const h3Count = contentLower.split('<h3').length - 1;\n return h2Count + h3Count >= 3;\n}\n\nfunction checkShortParagraphs(content: string): boolean {\n // Split by </p> tags or double newlines to get paragraphs\n let paragraphs: string[];\n\n if (content.includes('</p>')) {\n paragraphs = content\n .split(/<\\/p>/i)\n .map((p) => stripHtml(p).trim())\n .filter((p) => p.length > 0);\n } else {\n paragraphs = content\n .split(/\\n\\s*\\n/)\n .map((p) => stripHtml(p).trim())\n .filter((p) => p.length > 0);\n }\n\n if (paragraphs.length === 0) return true;\n\n let totalWords = 0;\n for (const para of paragraphs) {\n const words = getWords(para);\n totalWords += words.length;\n }\n\n const avgLength = totalWords / paragraphs.length;\n return avgLength <= 150;\n}\n\nfunction checkLists(content: string): boolean {\n const contentLower = content.toLowerCase();\n return contentLower.includes('<ul') || contentLower.includes('<ol');\n}\n\nfunction checkBoldEmphasis(content: string): boolean {\n const contentLower = content.toLowerCase();\n return (\n contentLower.includes('<strong') ||\n contentLower.includes('<b>') ||\n contentLower.includes('<b ') ||\n contentLower.includes('<em')\n );\n}\n\nfunction checkMedia(content: string): boolean {\n const contentLower = content.toLowerCase();\n return (\n contentLower.includes('<img') ||\n contentLower.includes('<video') ||\n contentLower.includes('<iframe')\n );\n}\n\nfunction checkAnswerImmediacy(\n content: string,\n focusKeyphrase: string,\n isInformational: boolean,\n): boolean {\n if (!isInformational) return false;\n\n const plainText = stripHtml(content);\n const words = getWords(plainText);\n const first100 = words.slice(0, 100).join(' ').toLowerCase();\n\n // Check if any keyphrase words appear in the first 100 words\n const keyphraseWords = getWords(focusKeyphrase.toLowerCase());\n if (keyphraseWords.length === 0) return false;\n\n let foundCount = 0;\n for (const kw of keyphraseWords) {\n if (first100.includes(kw)) {\n foundCount++;\n }\n }\n\n // At least half the keyphrase words should appear early\n return foundCount >= Math.ceil(keyphraseWords.length / 2);\n}\n\n// ---------------------------------------------------------------------------\n// Check\n// ---------------------------------------------------------------------------\n\nexport function checkIntentEngagementSignals(\n input: ContentAnalysisInput,\n): AnalysisResult {\n const id = 'intent-engagement-signals';\n const title = 'Engagement signal optimization';\n\n if (!input.focusKeyphrase || input.focusKeyphrase.trim().length === 0) {\n return {\n id,\n title,\n description:\n 'No focus keyphrase set. Set one to evaluate engagement signals.',\n status: 'na',\n score: 0,\n maxScore: 5,\n };\n }\n\n const detected = detectIntent(input.focusKeyphrase);\n const isInformational = detected.primary === 'informational';\n\n const signals: EngagementSignal[] = [\n {\n name: 'Table of contents',\n present: checkTableOfContents(input.content),\n },\n {\n name: 'Scannable subheadings (3+)',\n present: checkSubheadings(input.content),\n },\n {\n name: 'Short paragraphs (avg <= 150 words)',\n present: checkShortParagraphs(input.content),\n },\n {\n name: 'Lists (ul/ol)',\n present: checkLists(input.content),\n },\n {\n name: 'Bold/emphasis highlights',\n present: checkBoldEmphasis(input.content),\n },\n {\n name: 'Media (images/video)',\n present: checkMedia(input.content),\n },\n {\n name: 'Answer immediacy',\n present: checkAnswerImmediacy(\n input.content,\n input.focusKeyphrase,\n isInformational,\n ),\n },\n ];\n\n const presentSignals = signals.filter((s) => s.present);\n const missingSignals = signals.filter((s) => !s.present);\n const presentCount = presentSignals.length;\n\n const presentList = presentSignals.map((s) => s.name).join(', ');\n const missingList = missingSignals.map((s) => s.name).join(', ');\n\n // good (5): 5+ elements\n if (presentCount >= 5) {\n return {\n id,\n title,\n description:\n `Excellent engagement optimization (${presentCount}/7 signals). ` +\n `Present: ${presentList}.` +\n (missingSignals.length > 0\n ? ` Consider also adding: ${missingList}.`\n : ''),\n status: 'good',\n score: 5,\n maxScore: 5,\n };\n }\n\n // ok (3): 3-4 elements\n if (presentCount >= 3) {\n return {\n id,\n title,\n description:\n `Acceptable engagement optimization (${presentCount}/7 signals). ` +\n `Present: ${presentList}. Missing: ${missingList}. ` +\n `Add more engagement elements to reduce pogo-sticking.`,\n status: 'ok',\n score: 3,\n maxScore: 5,\n };\n }\n\n // poor (1): 1-2 elements\n if (presentCount >= 1) {\n return {\n id,\n title,\n description:\n `Low engagement optimization (${presentCount}/7 signals). ` +\n `Present: ${presentList}. Missing: ${missingList}. ` +\n `Users are likely to bounce back to search results.`,\n status: 'poor',\n score: 1,\n maxScore: 5,\n };\n }\n\n // poor (0): 0 elements — high pogo-stick risk\n return {\n id,\n title,\n description:\n `No engagement signals found (0/7). Missing: ${missingList}. ` +\n `High pogo-stick risk — users will likely return to search results immediately.`,\n status: 'poor',\n score: 0,\n maxScore: 5,\n };\n}\n","// @power-seo/content-analysis — AEO: Direct Answer Opening Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords, extractTagContents } from '@power-seo/core';\n\n/**\n * Check whether the article opens with a direct, answer-first paragraph.\n * AI engines (ChatGPT, Perplexity, Google AIO) prefer definition-first openings.\n * Research: definition-first openings generate 34 daily AI citations vs <5 for narrative openings.\n */\nfunction findDirectAnswerOpening(html: string, keyphrase: string): {\n hasDirectAnswer: boolean;\n hasKeyphrase: boolean;\n hasDefinitionPattern: boolean;\n} {\n const paragraphs = extractTagContents(html, 'p');\n const plainText = stripHtml(html);\n const allWords = getWords(plainText);\n\n const kp = keyphrase.toLowerCase().trim();\n\n // Check first 3 paragraphs only (within ~150 words)\n let cumulativeWords = 0;\n for (let i = 0; i < Math.min(paragraphs.length, 3); i++) {\n const para = paragraphs[i];\n if (para === undefined) continue;\n const paraPlain = stripHtml(para);\n const paraWords = getWords(paraPlain);\n if (cumulativeWords >= 150) break;\n cumulativeWords += paraWords.length;\n\n // Must be meaningful length: 30-120 words\n if (paraWords.length < 30 || paraWords.length > 120) continue;\n\n const lower = paraPlain.toLowerCase();\n const hasDefinitionPattern =\n /\\bis\\s+a\\b/.test(lower) ||\n /\\brefers\\s+to\\b/.test(lower) ||\n /\\bis\\s+defined\\s+as\\b/.test(lower) ||\n /\\bmeans\\b/.test(lower) ||\n /\\bis\\s+the\\s+process\\b/.test(lower) ||\n /\\binvolves\\b/.test(lower);\n\n const hasKeyphrase = kp.length > 0 && lower.includes(kp);\n\n if (hasDefinitionPattern) {\n return { hasDirectAnswer: true, hasKeyphrase, hasDefinitionPattern: true };\n }\n }\n\n // Fallback: check first 150 words of raw text for definition patterns\n if (allWords.length >= 30) {\n const first150 = allWords.slice(0, 150).join(' ').toLowerCase();\n const hasDefinitionPattern =\n /\\bis\\s+a\\b/.test(first150) ||\n /\\brefers\\s+to\\b/.test(first150) ||\n /\\bis\\s+defined\\s+as\\b/.test(first150) ||\n /\\bmeans\\b/.test(first150);\n const hasKeyphrase = kp.length > 0 && first150.includes(kp);\n\n if (hasDefinitionPattern) {\n return { hasDirectAnswer: true, hasKeyphrase, hasDefinitionPattern: true };\n }\n\n // Partial: short paragraph exists but no definition pattern\n const firstPara = paragraphs[0];\n if (firstPara !== undefined) {\n const firstParaWords = getWords(stripHtml(firstPara));\n if (firstParaWords.length >= 30 && firstParaWords.length <= 120) {\n return { hasDirectAnswer: false, hasKeyphrase, hasDefinitionPattern: false };\n }\n }\n }\n\n return { hasDirectAnswer: false, hasKeyphrase: false, hasDefinitionPattern: false };\n}\n\nexport function checkAeoDirectAnswer(input: ContentAnalysisInput): AnalysisResult {\n const { content, focusKeyphrase } = input;\n const plain = stripHtml(content);\n const wordCount = getWords(plain).length;\n\n if (wordCount < 50) {\n return {\n id: 'aeo-direct-answer',\n title: 'Direct answer opening (AEO)',\n description: 'Add more content to evaluate the direct answer opening.',\n status: 'na',\n score: 0,\n maxScore: 10,\n };\n }\n\n const kp = (focusKeyphrase ?? '').trim();\n const { hasDirectAnswer, hasKeyphrase, hasDefinitionPattern } = findDirectAnswerOpening(content, kp);\n\n if (hasDefinitionPattern && (hasKeyphrase || kp.length === 0)) {\n return {\n id: 'aeo-direct-answer',\n title: 'Direct answer opening (AEO)',\n description: 'Great — the article opens with a definition-style direct answer. AI engines (ChatGPT, Perplexity, Google AI Overviews) strongly favour this pattern, generating up to 34× more AI citations.',\n status: 'good',\n score: 10,\n maxScore: 10,\n };\n }\n\n if (hasDefinitionPattern || hasDirectAnswer) {\n const kpNote = kp.length > 0 && !hasKeyphrase\n ? ` Include the focus keyphrase \"${kp}\" in the opening paragraph for full AEO benefit.`\n : '';\n return {\n id: 'aeo-direct-answer',\n title: 'Direct answer opening (AEO)',\n description: `The opening has some direct-answer structure, but could be clearer.${kpNote} Start with \"[Topic] is/refers to/means…\" for maximum AI engine citability.`,\n status: 'ok',\n score: 5,\n maxScore: 10,\n };\n }\n\n const kpNote = kp.length > 0\n ? ` Open with a sentence like \"${kp} is…\" or \"${kp} refers to…\" to maximise AI citation probability.`\n : ' Open with a definition-style sentence (e.g. \"[Topic] is…\") to maximise AI citation probability.';\n\n return {\n id: 'aeo-direct-answer',\n title: 'Direct answer opening (AEO)',\n description: `No direct-answer opening detected. AI engines favour content that answers the query in the first 40–60 words.${kpNote}`,\n status: 'poor',\n score: 0,\n maxScore: 10,\n };\n}\n","// @power-seo/content-analysis — AEO: FAQ Section Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords, extractTagContents } from '@power-seo/core';\n\n/**\n * Count Q&A pairs: question-phrased H2/H3 headings followed by an answer paragraph (30–200 words).\n * FAQPage schema + FAQ section = 2.7–3.2× higher AI Overview citation rate (Relixir, 50-site study).\n */\nfunction countQaPairs(html: string): number {\n const questionWordPattern = /\\b(?:what|how|why|when|where|who|which|can|does|is|are|will|should)\\b/i;\n const headingRegex = /<h[23][^>]*>([\\s\\S]*?)<\\/h[23]>/gi;\n\n let pairCount = 0;\n let match: RegExpExecArray | null;\n\n while ((match = headingRegex.exec(html)) !== null) {\n const headingContent = match[1];\n if (headingContent === undefined) continue;\n\n const headingText = stripHtml(headingContent);\n const isQuestion =\n questionWordPattern.test(headingText) ||\n headingText.trim().endsWith('?');\n\n if (!isQuestion) continue;\n\n // Check the immediately following content for a valid answer paragraph\n const afterHeading = html.slice(match.index + match[0].length);\n const nextParagraphs = extractTagContents(afterHeading, 'p');\n const firstPara = nextParagraphs[0];\n\n if (firstPara !== undefined) {\n const paraWordCount = getWords(stripHtml(firstPara)).length;\n if (paraWordCount >= 30 && paraWordCount <= 200) {\n pairCount++;\n }\n }\n }\n\n return pairCount;\n}\n\nexport function checkAeoFaqSection(input: ContentAnalysisInput): AnalysisResult {\n const { content } = input;\n const plain = stripHtml(content);\n const wordCount = getWords(plain).length;\n\n if (wordCount < 200) {\n return {\n id: 'aeo-faq-section',\n title: 'FAQ section (AEO)',\n description: 'Add more content to evaluate FAQ structure.',\n status: 'na',\n score: 0,\n maxScore: 10,\n };\n }\n\n const pairCount = countQaPairs(content);\n\n if (pairCount >= 3) {\n return {\n id: 'aeo-faq-section',\n title: 'FAQ section (AEO)',\n description: `${pairCount} FAQ-style Q&A pairs detected. Excellent — add FAQPage schema (JSON-LD) to these sections for a 2.7–3.2× AI Overview citation boost. AI engines cite FAQ content in 41% of answers vs 15% for pages without FAQ structure.`,\n status: 'good',\n score: 10,\n maxScore: 10,\n };\n }\n\n if (pairCount >= 1) {\n return {\n id: 'aeo-faq-section',\n title: 'FAQ section (AEO)',\n description: `${pairCount} Q&A pair${pairCount === 1 ? '' : 's'} detected. Aim for 5–8 FAQ pairs. Write each H2/H3 as a question (ending with \"?\"), followed by a 40–80 word direct answer paragraph.`,\n status: 'ok',\n score: 5,\n maxScore: 10,\n };\n }\n\n return {\n id: 'aeo-faq-section',\n title: 'FAQ section (AEO)',\n description: 'No FAQ-style Q&A structure found. Add a \"Frequently Asked Questions\" section with 5–8 question headings (H2/H3 ending in \"?\") each answered in 40–80 words. This is the single highest-impact AEO signal for citation in AI answers.',\n status: 'poor',\n score: 0,\n maxScore: 10,\n };\n}\n","// @power-seo/content-analysis — AEO: Fact Density Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\n\n/**\n * Count verifiable fact signals in plain text.\n * AI engines prefer content with measurable claims.\n * Target: 1 fact signal per 150–200 words (8–12 citations per 1,500 words).\n * Princeton GEO study: adding statistics = +40% AI visibility.\n */\nfunction countFactSignals(text: string): number {\n let count = 0;\n\n // Numeric percentages: 42%, 3.5%, 99.9%\n const percentages = text.match(/\\d+(?:\\.\\d+)?%/g);\n count += percentages?.length ?? 0;\n\n // Dollar/currency amounts: $1.2B, $42, €100, £50\n const currencies = text.match(/[$€£¥]\\s*\\d+(?:[.,]\\d+)?(?:\\s*[BMKbmk](?:illion|illion)?)?/g);\n count += currencies?.length ?? 0;\n\n // Year references: in 2024, since 2019, by 2026\n const years = text.match(/\\b(?:in|since|by|from|until|through)\\s+20\\d{2}\\b/gi);\n count += years?.length ?? 0;\n\n // Standalone years in parentheses (citations): (2024), (2023)\n const citedYears = text.match(/\\(20\\d{2}\\)/g);\n count += citedYears?.length ?? 0;\n\n // Multipliers: 3.5x, 2×, 4.8x\n const multipliers = text.match(/\\d+(?:\\.\\d+)?[x×]\\b/g);\n count += multipliers?.length ?? 0;\n\n // \"According to\" and attribution phrases\n const attributions = text.match(/\\baccording\\s+to\\b|\\bstudy\\s+(?:found|shows|revealed)\\b|\\bresearch\\s+(?:found|shows|suggests)\\b/gi);\n count += attributions?.length ?? 0;\n\n // Numeric measurements with units: 42ms, 3.2GB, 150km, 42dB\n const measurements = text.match(/\\d+(?:\\.\\d+)?\\s*(?:ms|gb|mb|kb|km|cm|mm|kg|lbs?|db|fps|mph|rpm)\\b/gi);\n count += measurements?.length ?? 0;\n\n return count;\n}\n\nexport function checkAeoFactDensity(input: ContentAnalysisInput): AnalysisResult {\n const { content } = input;\n const plain = stripHtml(content);\n const words = getWords(plain);\n const wordCount = words.length;\n\n if (wordCount < 100) {\n return {\n id: 'aeo-fact-density',\n title: 'Fact density (AEO)',\n description: 'Add more content to measure fact density.',\n status: 'na',\n score: 0,\n maxScore: 8,\n };\n }\n\n const factCount = countFactSignals(plain);\n const factsPerHundredWords = (factCount / wordCount) * 100;\n\n if (factsPerHundredWords >= 2) {\n return {\n id: 'aeo-fact-density',\n title: 'Fact density (AEO)',\n description: `${factCount} fact signals detected across ${wordCount} words (${factsPerHundredWords.toFixed(1)} per 100 words). Strong fact density — AI engines like Perplexity and ChatGPT strongly favour content with verifiable data points.`,\n status: 'good',\n score: 8,\n maxScore: 8,\n };\n }\n\n if (factsPerHundredWords >= 0.8) {\n return {\n id: 'aeo-fact-density',\n title: 'Fact density (AEO)',\n description: `${factCount} fact signals in ${wordCount} words (${factsPerHundredWords.toFixed(1)} per 100 words). Aim for at least 1 data point every 150 words — add more statistics, percentages, dates, or study citations. Princeton GEO study: adding statistics increases AI visibility by 40%.`,\n status: 'ok',\n score: 4,\n maxScore: 8,\n };\n }\n\n return {\n id: 'aeo-fact-density',\n title: 'Fact density (AEO)',\n description: `Only ${factCount} fact signal${factCount === 1 ? '' : 's'} in ${wordCount} words (${factsPerHundredWords.toFixed(1)} per 100 words). AI engines prioritise content with measurable claims. Add statistics (e.g. \"42% of users…\"), study citations (\"according to…\"), dates, and measurement data. Target: 8–12 cited facts per 1,500 words.`,\n status: 'poor',\n score: 0,\n maxScore: 8,\n };\n}\n","// @power-seo/content-analysis — AEO: TL;DR / Summary Section Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords, extractTagContents } from '@power-seo/core';\n\n/**\n * Detects a TL;DR or summary block — a structured overview that AI engines\n * can extract as a standalone answer. Content with a summary block receives\n * 2.1× more AI citations (Moz AI Content Study, 2025).\n */\nfunction detectSummaryBlock(html: string): { found: boolean; hasBullets: boolean } {\n const headings = extractTagContents(html, 'h2').concat(extractTagContents(html, 'h3'));\n const tldrPattern = /\\b(?:tl;?dr|summary|key\\s+takeaways?|in\\s+brief|quick\\s+answer|the\\s+short\\s+version|overview)\\b/i;\n\n let found = false;\n for (const h of headings) {\n if (tldrPattern.test(stripHtml(h))) {\n found = true;\n break;\n }\n }\n\n // Also check for a <strong>TL;DR</strong> or bold summary inline\n const boldTldr = /<(?:strong|b)[^>]*>[^<]*(?:tl;?dr|summary|key\\s+takeaway)[^<]*<\\/(?:strong|b)>/i.test(html);\n if (boldTldr) found = true;\n\n // Check if a bullet list follows a summary/tldr heading\n const hasBullets = found && (/<ul[\\s>]/.test(html) || /<ol[\\s>]/.test(html));\n\n return { found, hasBullets };\n}\n\nexport function checkAeoTldrSummary(input: ContentAnalysisInput): AnalysisResult {\n const { content } = input;\n const plain = stripHtml(content);\n const wordCount = getWords(plain).length;\n\n if (wordCount < 300) {\n return {\n id: 'aeo-tldr-summary',\n title: 'TL;DR / summary section (AEO)',\n description: 'Content is too short to require a summary section.',\n status: 'na',\n score: 0,\n maxScore: 7,\n };\n }\n\n const { found, hasBullets } = detectSummaryBlock(content);\n\n if (found && hasBullets) {\n return {\n id: 'aeo-tldr-summary',\n title: 'TL;DR / summary section (AEO)',\n description: 'TL;DR / summary section with bullet points detected. Excellent — AI engines extract structured summaries 2.1× more often than narrative-only content.',\n status: 'good',\n score: 7,\n maxScore: 7,\n };\n }\n\n if (found) {\n return {\n id: 'aeo-tldr-summary',\n title: 'TL;DR / summary section (AEO)',\n description: 'Summary section detected. Add 3–5 bullet points summarising key insights — bullet lists in summaries increase AI snippet extraction rate by 40%.',\n status: 'ok',\n score: 4,\n maxScore: 7,\n };\n }\n\n return {\n id: 'aeo-tldr-summary',\n title: 'TL;DR / summary section (AEO)',\n description: 'No TL;DR or summary section found. Add a \"Key Takeaways\" or \"TL;DR\" H2 section near the top with 3–5 bullet points covering the main answers. This pattern is cited 2.1× more by AI engines.',\n status: 'poor',\n score: 0,\n maxScore: 7,\n };\n}\n","// @power-seo/content-analysis — AEO: Concise Answers Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords, extractTagContents } from '@power-seo/core';\n\n/**\n * Checks whether question-phrased headings are followed by concise 40–120 word\n * answer paragraphs. Perplexity AI study (2025): 40–60 word answer paragraphs\n * following question headings generate 220% more citations than longer answers.\n */\nfunction countConciseAnswers(html: string): { concise: number; total: number } {\n const questionPattern = /\\b(?:what|how|why|when|where|who|which|can|does|is|are|will|should)\\b/i;\n const headingRegex = /<h[23][^>]*>([\\s\\S]*?)<\\/h[23]>/gi;\n\n let concise = 0;\n let total = 0;\n let match: RegExpExecArray | null;\n\n while ((match = headingRegex.exec(html)) !== null) {\n const headingText = stripHtml(match[1] ?? '');\n const isQuestion = questionPattern.test(headingText) || headingText.trim().endsWith('?');\n if (!isQuestion) continue;\n total++;\n\n const afterHeading = html.slice(match.index + match[0].length);\n const nextParas = extractTagContents(afterHeading, 'p');\n const firstPara = nextParas[0];\n\n if (firstPara !== undefined) {\n const wordCount = getWords(stripHtml(firstPara)).length;\n if (wordCount >= 40 && wordCount <= 120) {\n concise++;\n }\n }\n }\n\n return { concise, total };\n}\n\nexport function checkAeoConciseAnswers(input: ContentAnalysisInput): AnalysisResult {\n const { content } = input;\n const plain = stripHtml(content);\n const wordCount = getWords(plain).length;\n\n if (wordCount < 200) {\n return {\n id: 'aeo-concise-answers',\n title: 'Concise answer paragraphs (AEO)',\n description: 'Add more content to evaluate answer conciseness.',\n status: 'na',\n score: 0,\n maxScore: 7,\n };\n }\n\n const { concise, total } = countConciseAnswers(content);\n\n if (total === 0) {\n return {\n id: 'aeo-concise-answers',\n title: 'Concise answer paragraphs (AEO)',\n description: 'No question-style headings (H2/H3) found. Add questions as headings and answer each with a 40–120 word paragraph. Perplexity AI study: 40–60 word answer paragraphs generate 220% more AI citations.',\n status: 'poor',\n score: 0,\n maxScore: 7,\n };\n }\n\n const ratio = concise / total;\n\n if (ratio >= 0.7) {\n return {\n id: 'aeo-concise-answers',\n title: 'Concise answer paragraphs (AEO)',\n description: `${concise} of ${total} question headings have concise 40–120 word answers. Excellent — this pattern generates 220% more Perplexity and ChatGPT citations than long-form answers.`,\n status: 'good',\n score: 7,\n maxScore: 7,\n };\n }\n\n if (ratio >= 0.4 || concise >= 1) {\n return {\n id: 'aeo-concise-answers',\n title: 'Concise answer paragraphs (AEO)',\n description: `${concise} of ${total} question headings have concise answers (40–120 words). Aim for all question headings to be followed by a tight 40–60 word direct answer. Longer answers reduce AI citation probability by 60%.`,\n status: 'ok',\n score: 4,\n maxScore: 7,\n };\n }\n\n return {\n id: 'aeo-concise-answers',\n title: 'Concise answer paragraphs (AEO)',\n description: `${concise} of ${total} question headings have concise answers. Most answers are too long or absent. Keep the first answer paragraph to 40–120 words — then add detail in subsequent paragraphs. AI engines extract the first paragraph under each heading as the cited answer.`,\n status: 'poor',\n score: 1,\n maxScore: 7,\n };\n}\n","// @power-seo/content-analysis — AEO: Structured Data Hints Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\n\n/**\n * Detects structured content patterns: tables, numbered processes, feature lists,\n * how-to steps, and comparison structures. AI engines extract these 3.8× more\n * often than unstructured prose (SurferSEO AI content analysis, Q4 2025).\n */\nfunction detectStructuredPatterns(html: string, plain: string): {\n hasTables: boolean;\n hasNumberedProcess: boolean;\n hasComparisonList: boolean;\n hasHowTo: boolean;\n patternCount: number;\n} {\n const hasTables = /<table[\\s>]/i.test(html);\n\n // Numbered step patterns: \"Step 1:\", \"1. Do this\", \"First, ... Second, ...\"\n const numberedProcessPatterns = [\n /\\bstep\\s+\\d+\\b/gi,\n /\\b(?:first|second|third|fourth|fifth),\\s/gi,\n /^\\s*\\d+\\.\\s+[A-Z]/m,\n ];\n const hasNumberedProcess = numberedProcessPatterns.some((p) => p.test(plain));\n\n // Comparison / feature list: \"vs\", \"versus\", \"pros and cons\", \"advantages\", \"compared to\"\n const comparisonPattern = /\\b(?:vs\\.?|versus|pros?\\s+and\\s+cons?|advantages?\\s+and\\s+disadvantages?|compared\\s+to|comparison)\\b/i;\n const hasComparisonList = comparisonPattern.test(plain);\n\n // How-to patterns: \"how to\", \"instructions\", numbered lists in HTML\n const hasHowTo = /\\bhow\\s+to\\b/i.test(plain) && (/<ol[\\s>]/i.test(html) || /<li[\\s>]/i.test(html));\n\n const patternCount = [hasTables, hasNumberedProcess, hasComparisonList, hasHowTo].filter(Boolean).length;\n\n return { hasTables, hasNumberedProcess, hasComparisonList, hasHowTo, patternCount };\n}\n\nexport function checkAeoStructuredDataHints(input: ContentAnalysisInput): AnalysisResult {\n const { content } = input;\n const plain = stripHtml(content);\n const wordCount = getWords(plain).length;\n\n if (wordCount < 150) {\n return {\n id: 'aeo-structured-data-hints',\n title: 'Structured content patterns (AEO)',\n description: 'Add more content to evaluate structured formatting.',\n status: 'na',\n score: 0,\n maxScore: 7,\n };\n }\n\n const { hasTables, hasNumberedProcess, hasComparisonList, hasHowTo, patternCount } = detectStructuredPatterns(content, plain);\n\n if (patternCount >= 2) {\n const patterns = [\n hasTables && 'table',\n hasNumberedProcess && 'numbered steps',\n hasComparisonList && 'comparison',\n hasHowTo && 'how-to list',\n ].filter(Boolean).join(', ');\n\n return {\n id: 'aeo-structured-data-hints',\n title: 'Structured content patterns (AEO)',\n description: `Structured patterns detected: ${patterns}. Great — AI engines extract structured content 3.8× more often than unstructured prose. Add HowTo or Table schema (JSON-LD) to maximise eligibility.`,\n status: 'good',\n score: 7,\n maxScore: 7,\n };\n }\n\n if (patternCount === 1) {\n return {\n id: 'aeo-structured-data-hints',\n title: 'Structured content patterns (AEO)',\n description: 'One structured pattern found. Add more: numbered step-by-step processes, comparison tables, feature lists, or how-to ordered lists. Each additional structure type increases AI engine extraction probability.',\n status: 'ok',\n score: 4,\n maxScore: 7,\n };\n }\n\n return {\n id: 'aeo-structured-data-hints',\n title: 'Structured content patterns (AEO)',\n description: 'No structured content patterns detected. Add tables, numbered step-by-step processes, comparison sections (\"X vs Y\"), or how-to ordered lists. AI engines extract structured content 3.8× more often — and these patterns unlock Rich Results (HowTo, Table schema) in Google.',\n status: 'poor',\n score: 0,\n maxScore: 7,\n };\n}\n","// @power-seo/content-analysis — AEO: Citation Readiness Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\n\n/**\n * Checks signals that make content citable by AI engines: external source links,\n * attribution phrases, footnotes, and a sources section.\n * BrightEdge 2025: cited pages have 3.1× more external references than non-cited pages.\n */\nfunction measureCitationSignals(html: string, plain: string): {\n externalLinks: number;\n hasSourcesSection: boolean;\n attributionPhrases: number;\n hasFootnotes: boolean;\n totalSignals: number;\n} {\n // Count external links (href starting with http/https)\n const externalLinkMatches = html.match(/href=[\"']https?:\\/\\/[^\"']+[\"']/gi);\n const externalLinks = externalLinkMatches?.length ?? 0;\n\n // Sources/references section heading\n const hasSourcesSection = /\\b(?:sources?|references?|bibliography|further\\s+reading|citations?)\\b/i.test(plain);\n\n // Attribution phrases\n const attributionPattern = /\\baccording\\s+to\\b|\\bcited\\s+by\\b|\\bsource[d]?\\s*:\\b|\\bvia\\b|\\bper\\b\\s+[A-Z]|\\bas\\s+reported\\s+by\\b/gi;\n const attributionMatches = plain.match(attributionPattern);\n const attributionPhrases = attributionMatches?.length ?? 0;\n\n // Footnotes: [1], [2], or superscript numbers\n const footnotePattern = /\\[\\d+\\]|<sup>\\d+<\\/sup>/g;\n const hasFootnotes = footnotePattern.test(html);\n\n const totalSignals = externalLinks + (hasSourcesSection ? 3 : 0) + attributionPhrases + (hasFootnotes ? 2 : 0);\n\n return { externalLinks, hasSourcesSection, attributionPhrases, hasFootnotes, totalSignals };\n}\n\nexport function checkAeoCitationReadiness(input: ContentAnalysisInput): AnalysisResult {\n const { content } = input;\n const plain = stripHtml(content);\n const wordCount = getWords(plain).length;\n\n if (wordCount < 200) {\n return {\n id: 'aeo-citation-readiness',\n title: 'Citation readiness (AEO)',\n description: 'Add more content to evaluate citation readiness.',\n status: 'na',\n score: 0,\n maxScore: 8,\n };\n }\n\n const { externalLinks, hasSourcesSection, attributionPhrases, hasFootnotes, totalSignals } = measureCitationSignals(content, plain);\n\n if (totalSignals >= 5 && (hasSourcesSection || externalLinks >= 3)) {\n return {\n id: 'aeo-citation-readiness',\n title: 'Citation readiness (AEO)',\n description: `Strong citation signals: ${externalLinks} external links${hasSourcesSection ? ', sources section' : ''}${attributionPhrases > 0 ? `, ${attributionPhrases} attribution phrase${attributionPhrases > 1 ? 's' : ''}` : ''}${hasFootnotes ? ', footnotes' : ''}. BrightEdge 2025: pages with this level of attribution are cited 3.1× more by AI engines.`,\n status: 'good',\n score: 8,\n maxScore: 8,\n };\n }\n\n if (totalSignals >= 2 || externalLinks >= 1) {\n return {\n id: 'aeo-citation-readiness',\n title: 'Citation readiness (AEO)',\n description: `Some citation signals present (${externalLinks} external links, ${attributionPhrases} attribution phrases). Strengthen citation readiness: add a \"Sources\" or \"References\" section, use \"According to [Source]…\" phrases, and link out to authoritative studies. Target: 3+ external links + a sources section.`,\n status: 'ok',\n score: 4,\n maxScore: 8,\n };\n }\n\n return {\n id: 'aeo-citation-readiness',\n title: 'Citation readiness (AEO)',\n description: 'No citation signals detected. AI engines (Perplexity, ChatGPT, Gemini) strongly prefer citing content that itself cites authoritative sources. Add: (1) 3–5 external links to authoritative sources, (2) \"According to [source]…\" attribution phrases, (3) a \"Sources\" section at the bottom. BrightEdge 2025: cited pages have 3.1× more external references.',\n status: 'poor',\n score: 0,\n maxScore: 8,\n };\n}\n","// @power-seo/content-analysis — AEO: Entity Coverage Check\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, AnalysisResult } from '@power-seo/core';\nimport { stripHtml, getWords } from '@power-seo/core';\n\n/**\n * Estimates named entity density — proper nouns, brand names, technologies,\n * places, people, and numbers used as entity identifiers.\n * Kalicube AEO study (2025): 15+ entities per 1,000 words = 4.8× higher AI\n * selection rate vs content with <5 entities per 1,000 words.\n * Target: 15–25 named entities per 1,000 words.\n */\nfunction estimateEntityDensity(plain: string, wordCount: number): {\n entityCount: number;\n entitiesPerThousand: number;\n} {\n // Named entities heuristics (capitalised sequences not at sentence start)\n // 1. Title-cased multi-word phrases: \"Google Analytics\", \"Next.js\", \"United States\"\n const titleCaseEntities = plain.match(/\\b[A-Z][a-z]+(?:\\s+[A-Z][a-z]+)+\\b/g);\n const titleCount = titleCaseEntities?.length ?? 0;\n\n // 2. Single proper nouns (not at sentence start — simplistic but effective)\n const singlePropers = plain.match(/(?:^|\\s)([A-Z][a-z]{2,})\\b/g);\n // Filter out common sentence-starting words\n const commonSentenceStarters = new Set([\n 'The', 'This', 'That', 'These', 'Those', 'It', 'He', 'She', 'They', 'We',\n 'In', 'On', 'At', 'By', 'For', 'With', 'And', 'But', 'Or', 'If', 'As',\n 'An', 'A', 'Is', 'Are', 'Was', 'Were', 'Have', 'Has', 'Had', 'Will',\n 'When', 'Where', 'What', 'How', 'Why', 'Who', 'Which',\n ]);\n const filteredSingles = (singlePropers ?? []).filter((w) => {\n const word = w.trim();\n return !commonSentenceStarters.has(word);\n });\n const singleCount = Math.min(filteredSingles.length, titleCount * 2); // cap to avoid false positives\n\n // 3. Technology / product names with mixed case or dots: JavaScript, Next.js, ChatGPT\n const techNames = plain.match(/\\b(?:[A-Z][a-zA-Z]*[A-Z][a-zA-Z]*|[A-Za-z]+\\.[a-z]{2,4}(?:\\s|$))\\b/g);\n const techCount = techNames?.length ?? 0;\n\n // 4. Version numbers used as entity signals: v1.0, 2024, GPT-4\n const versionNumbers = plain.match(/\\b(?:v\\d+(?:\\.\\d+)*|GPT-\\d|gpt-\\d|\\d{4})\\b/g);\n const versionCount = versionNumbers?.length ?? 0;\n\n // Sum with weighting to avoid over-counting\n const rawCount = titleCount + Math.floor(singleCount * 0.3) + Math.floor(techCount * 0.5) + Math.floor(versionCount * 0.5);\n const entityCount = Math.max(rawCount, 0);\n const entitiesPerThousand = wordCount > 0 ? (entityCount / wordCount) * 1000 : 0;\n\n return { entityCount, entitiesPerThousand };\n}\n\nexport function checkAeoEntityCoverage(input: ContentAnalysisInput): AnalysisResult {\n const { content } = input;\n const plain = stripHtml(content);\n const words = getWords(plain);\n const wordCount = words.length;\n\n if (wordCount < 200) {\n return {\n id: 'aeo-entity-coverage',\n title: 'Named entity coverage (AEO)',\n description: 'Add more content to evaluate entity density.',\n status: 'na',\n score: 0,\n maxScore: 9,\n };\n }\n\n const { entityCount, entitiesPerThousand } = estimateEntityDensity(plain, wordCount);\n\n if (entitiesPerThousand >= 15) {\n return {\n id: 'aeo-entity-coverage',\n title: 'Named entity coverage (AEO)',\n description: `Estimated ${entityCount} named entities across ${wordCount} words (${entitiesPerThousand.toFixed(1)}/1,000 words). Strong entity coverage — Kalicube AEO study: 15+ entities per 1,000 words yields 4.8× higher AI engine selection rate.`,\n status: 'good',\n score: 9,\n maxScore: 9,\n };\n }\n\n if (entitiesPerThousand >= 7) {\n return {\n id: 'aeo-entity-coverage',\n title: 'Named entity coverage (AEO)',\n description: `Estimated ${entityCount} named entities (${entitiesPerThousand.toFixed(1)}/1,000 words). Target 15–25 entities per 1,000 words. Mention specific tools, brands, people, organisations, standards, and technologies by name to build entity richness and improve AI engine citability.`,\n status: 'ok',\n score: 5,\n maxScore: 9,\n };\n }\n\n return {\n id: 'aeo-entity-coverage',\n title: 'Named entity coverage (AEO)',\n description: `Low entity coverage: ~${entityCount} named entities in ${wordCount} words (${entitiesPerThousand.toFixed(1)}/1,000 words). Kalicube AEO study: content with <5 entities per 1,000 words is 4.8× less likely to be cited by AI engines. Name specific tools, people, organisations, technologies, and standards throughout your content.`,\n status: 'poor',\n score: 1,\n maxScore: 9,\n };\n}\n","// @power-seo/content-analysis — Content Analyzer Orchestrator\n// ----------------------------------------------------------------------------\n\nimport type { ContentAnalysisInput, ContentAnalysisOutput, AnalysisResult } from '@power-seo/core';\nimport type { AnalysisConfig, CheckId } from './types.js';\nimport { checkTitle } from './checks/title.js';\nimport { checkMetaDescription } from './checks/meta-description.js';\nimport { checkKeyphraseUsage } from './checks/keyphrase-usage.js';\nimport { checkHeadings } from './checks/headings.js';\nimport { checkWordCount } from './checks/word-count.js';\nimport { checkImages } from './checks/images.js';\nimport { checkLinks } from './checks/links.js';\nimport { checkParagraphLength } from './checks/paragraph-length.js';\nimport { checkSentenceLength } from './checks/sentence-length.js';\nimport { checkSubheadingDistribution } from './checks/subheading-distribution.js';\nimport { checkTransitionWords } from './checks/transition-words.js';\nimport { checkCanonicalUrl } from './checks/canonical-url.js';\nimport { checkKeyphraseIntroduction } from './checks/keyphrase-introduction.js';\nimport { checkKeyphraseSlug } from './checks/keyphrase-slug.js';\nimport { checkKeyphraseLength } from './checks/keyphrase-length.js';\nimport { checkTitleReadability } from './checks/title-readability.js';\nimport { checkKeyphraseTitlePosition } from './checks/keyphrase-title-position.js';\nimport { checkUrlLength } from './checks/url-length.js';\nimport { checkTextPresence } from './checks/text-presence.js';\nimport { checkMediaCount } from './checks/media-count.js';\nimport { checkTableOfContents } from './checks/table-of-contents.js';\nimport { checkNofollowLinks } from './checks/nofollow-links.js';\nimport { checkSecondaryKeyphrases } from './checks/secondary-keyphrases.js';\n\n// E-E-A-T: Experience\nimport { checkExperienceDepth } from './checks/eeat-experience-depth.js';\nimport { checkOriginalResearch } from './checks/eeat-original-research.js';\nimport { checkSpecificityDepth } from './checks/eeat-specificity-depth.js';\nimport { checkMultimediaEvidence } from './checks/eeat-multimedia-evidence.js';\nimport { checkCaseStudyPatterns } from './checks/eeat-case-study-patterns.js';\n\n// E-E-A-T: Expertise\nimport { checkAuthorSchema } from './checks/eeat-author-schema.js';\nimport { checkTopicalAuthority } from './checks/eeat-topical-authority.js';\nimport { checkTechnicalVocabulary } from './checks/eeat-technical-vocabulary.js';\nimport { checkExpertHedging } from './checks/eeat-expert-hedging.js';\nimport { checkMethodologyTransparency } from './checks/eeat-methodology-transparency.js';\n\n// E-E-A-T: Authoritativeness\nimport { checkAuthorSocial } from './checks/eeat-author-social.js';\nimport { checkOrganization } from './checks/eeat-organization.js';\nimport { checkPublishedWorks } from './checks/eeat-published-works.js';\nimport { checkExpertSourcing } from './checks/eeat-expert-sourcing.js';\nimport { checkEditorialReview } from './checks/eeat-editorial-review.js';\n\n// E-E-A-T: Trustworthiness\nimport { checkSourceQuality } from './checks/eeat-source-quality.js';\nimport { checkYmylCompliance } from './checks/eeat-ymyl-compliance.js';\nimport { checkConflictDisclosure } from './checks/eeat-conflict-disclosure.js';\nimport { checkContentAccuracy } from './checks/eeat-content-accuracy.js';\nimport { checkCorrectionPolicy } from './checks/eeat-correction-policy.js';\nimport { checkPrivacySafety } from './checks/eeat-privacy-safety.js';\n\n// E-E-A-T: Meta\nimport { checkEeatOverallScore } from './checks/eeat-overall-score.js';\nimport { checkYmylMultiplier } from './checks/eeat-ymyl-multiplier.js';\n\n// Non-E-E-A-T\nimport { checkPreviouslyUsedKeyphrase } from './checks/previously-used-keyphrase.js';\nimport { checkKeyphraseEvenDistribution } from './checks/keyphrase-even-distribution.js';\nimport { checkSingleH1 } from './checks/single-h1.js';\nimport { checkWordComplexity } from './checks/word-complexity.js';\nimport { checkInclusiveLanguage } from './checks/inclusive-language.js';\nimport { checkCompetingLinks } from './checks/competing-links.js';\nimport { checkContentFreshness } from './checks/content-freshness.js';\nimport { checkKeyphraseMarkup } from './checks/keyphrase-markup.js';\nimport { checkHeadlineAnalyzer } from './checks/headline-analyzer.js';\nimport { checkInboundInternalLinks } from './checks/inbound-internal-links.js';\n\n// Intent: Detection\nimport { checkIntentKeywordClassification } from './checks/intent-keyword-classification.js';\nimport { checkIntentSubType } from './checks/intent-sub-type.js';\nimport { checkIntentModifierAnalysis } from './checks/intent-modifier-analysis.js';\nimport { checkIntentMultiDetection } from './checks/intent-multi-detection.js';\n\n// Intent: Content Alignment\nimport { checkIntentContentAlignment } from './checks/intent-content-alignment.js';\nimport { checkIntentTitleMatch } from './checks/intent-title-match.js';\nimport { checkIntentMetaMatch } from './checks/intent-meta-match.js';\nimport { checkIntentHeadingMatch } from './checks/intent-heading-match.js';\nimport { checkIntentOpeningMatch } from './checks/intent-opening-match.js';\nimport { checkIntentConclusionMatch } from './checks/intent-conclusion-match.js';\n\n// Intent: Specific Requirements\nimport { checkIntentInformationalCompleteness } from './checks/intent-informational-completeness.js';\nimport { checkIntentTransactionalElements } from './checks/intent-transactional-elements.js';\nimport { checkIntentCommercialElements } from './checks/intent-commercial-elements.js';\nimport { checkIntentNavigationalClarity } from './checks/intent-navigational-clarity.js';\nimport { checkIntentFormatMatch } from './checks/intent-format-match.js';\n\n// Intent: Signal Quality\nimport { checkIntentSignalDensity } from './checks/intent-signal-density.js';\nimport { checkIntentSignalDistribution } from './checks/intent-signal-distribution.js';\nimport { checkIntentDepthMatch } from './checks/intent-depth-match.js';\nimport { checkIntentMixedWarning } from './checks/intent-mixed-warning.js';\nimport { checkIntentCtaAlignment } from './checks/intent-cta-alignment.js';\n\n// Intent: SERP Features\nimport { checkIntentSnippetReadiness } from './checks/intent-snippet-readiness.js';\nimport { checkIntentSchemaReadiness } from './checks/intent-schema-readiness.js';\nimport { checkIntentPaaCoverage } from './checks/intent-paa-coverage.js';\n\n// Intent: User Journey\nimport { checkIntentSatisfactionScore } from './checks/intent-satisfaction-score.js';\nimport { checkIntentFunnelPosition } from './checks/intent-funnel-position.js';\nimport { checkIntentRelatedCoverage } from './checks/intent-related-coverage.js';\nimport { checkIntentEngagementSignals } from './checks/intent-engagement-signals.js';\n\n// AEO: Answer Engine Optimization\nimport { checkAeoDirectAnswer } from './checks/aeo-direct-answer.js';\nimport { checkAeoFaqSection } from './checks/aeo-faq-section.js';\nimport { checkAeoFactDensity } from './checks/aeo-fact-density.js';\nimport { checkAeoTldrSummary } from './checks/aeo-tldr-summary.js';\nimport { checkAeoConciseAnswers } from './checks/aeo-concise-answers.js';\nimport { checkAeoStructuredDataHints } from './checks/aeo-structured-data-hints.js';\nimport { checkAeoCitationReadiness } from './checks/aeo-citation-readiness.js';\nimport { checkAeoEntityCoverage } from './checks/aeo-entity-coverage.js';\n\n/**\n * Run all SEO content analysis checks and return aggregated results.\n *\n * @example\n * ```ts\n * const output = analyzeContent({\n * title: 'My Blog Post',\n * metaDescription: 'A description of my blog post about SEO.',\n * content: '<h1>My Blog Post</h1><p>Content goes here...</p>',\n * focusKeyphrase: 'blog post',\n * });\n * console.log(output.score, output.maxScore, output.recommendations);\n * ```\n */\nexport function analyzeContent(\n input: ContentAnalysisInput,\n config?: AnalysisConfig,\n): ContentAnalysisOutput {\n const disabled = new Set<CheckId>(config?.disabledChecks ?? []);\n\n const allResults: AnalysisResult[] = [];\n\n // Run each check group and collect results\n const titleResults = checkTitle(input);\n const metaResults = checkMetaDescription(input);\n const keyphraseResults = checkKeyphraseUsage(input);\n const headingResults = checkHeadings(input);\n const wordCountResult = checkWordCount(input);\n const imageResults = checkImages(input);\n const linkResults = checkLinks(input);\n const paragraphResult = checkParagraphLength(input);\n const sentenceResult = checkSentenceLength(input);\n const subheadingResult = checkSubheadingDistribution(input);\n const transitionResult = checkTransitionWords(input);\n const canonicalResult = checkCanonicalUrl(input);\n const keyphraseIntroductionResult = checkKeyphraseIntroduction(input);\n const keyphraseSlugResult = checkKeyphraseSlug(input);\n const keyphraseLengthResult = checkKeyphraseLength(input);\n const titleReadabilityResults = checkTitleReadability(input);\n const keyphraseTitlePositionResult = checkKeyphraseTitlePosition(input);\n const urlLengthResult = checkUrlLength(input);\n const textPresenceResult = checkTextPresence(input);\n const mediaCountResult = checkMediaCount(input);\n const tableOfContentsResult = checkTableOfContents(input);\n const nofollowLinksResult = checkNofollowLinks(input);\n const secondaryKeyphrasesResults = checkSecondaryKeyphrases(input);\n\n // E-E-A-T: Experience\n const experienceDepthResult = checkExperienceDepth(input);\n const originalResearchResult = checkOriginalResearch(input);\n const specificityDepthResult = checkSpecificityDepth(input);\n const multimediaEvidenceResult = checkMultimediaEvidence(input);\n const caseStudyResult = checkCaseStudyPatterns(input);\n\n // E-E-A-T: Expertise\n const authorSchemaResult = checkAuthorSchema(input);\n const topicalAuthorityResult = checkTopicalAuthority(input);\n const technicalVocabularyResult = checkTechnicalVocabulary(input);\n const expertHedgingResult = checkExpertHedging(input);\n const methodologyResult = checkMethodologyTransparency(input);\n\n // E-E-A-T: Authoritativeness\n const authorSocialResult = checkAuthorSocial(input);\n const organizationResult = checkOrganization(input);\n const publishedWorksResult = checkPublishedWorks(input);\n const expertSourcingResult = checkExpertSourcing(input);\n const editorialReviewResult = checkEditorialReview(input);\n\n // E-E-A-T: Trustworthiness\n const sourceQualityResult = checkSourceQuality(input);\n const ymylComplianceResult = checkYmylCompliance(input);\n const conflictDisclosureResult = checkConflictDisclosure(input);\n const contentAccuracyResult = checkContentAccuracy(input);\n const correctionPolicyResult = checkCorrectionPolicy(input);\n const privacySafetyResult = checkPrivacySafety(input);\n\n // E-E-A-T: Meta\n const eeatOverallResult = checkEeatOverallScore(input);\n const ymylMultiplierResult = checkYmylMultiplier(input);\n\n // Non-E-E-A-T\n const previouslyUsedKeyphraseResult = checkPreviouslyUsedKeyphrase(input);\n const keyphraseEvenDistributionResult = checkKeyphraseEvenDistribution(input);\n const singleH1Result = checkSingleH1(input);\n const wordComplexityResult = checkWordComplexity(input);\n const inclusiveLanguageResult = checkInclusiveLanguage(input);\n const competingLinksResult = checkCompetingLinks(input);\n const contentFreshnessResult = checkContentFreshness(input);\n const keyphraseMarkupResult = checkKeyphraseMarkup(input);\n const headlineAnalyzerResult = checkHeadlineAnalyzer(input);\n const inboundInternalLinksResult = checkInboundInternalLinks(input);\n\n // Intent: Detection\n const intentKeywordClassificationResult = checkIntentKeywordClassification(input);\n const intentSubTypeResult = checkIntentSubType(input);\n const intentModifierAnalysisResult = checkIntentModifierAnalysis(input);\n const intentMultiDetectionResult = checkIntentMultiDetection(input);\n\n // Intent: Content Alignment\n const intentContentAlignmentResult = checkIntentContentAlignment(input);\n const intentTitleMatchResult = checkIntentTitleMatch(input);\n const intentMetaMatchResult = checkIntentMetaMatch(input);\n const intentHeadingMatchResult = checkIntentHeadingMatch(input);\n const intentOpeningMatchResult = checkIntentOpeningMatch(input);\n const intentConclusionMatchResult = checkIntentConclusionMatch(input);\n\n // Intent: Specific Requirements\n const intentInformationalResult = checkIntentInformationalCompleteness(input);\n const intentTransactionalResult = checkIntentTransactionalElements(input);\n const intentCommercialResult = checkIntentCommercialElements(input);\n const intentNavigationalResult = checkIntentNavigationalClarity(input);\n const intentFormatMatchResult = checkIntentFormatMatch(input);\n\n // Intent: Signal Quality\n const intentSignalDensityResult = checkIntentSignalDensity(input);\n const intentSignalDistributionResult = checkIntentSignalDistribution(input);\n const intentDepthMatchResult = checkIntentDepthMatch(input);\n const intentMixedWarningResult = checkIntentMixedWarning(input);\n const intentCtaAlignmentResult = checkIntentCtaAlignment(input);\n\n // Intent: SERP Features\n const intentSnippetReadinessResult = checkIntentSnippetReadiness(input);\n const intentSchemaReadinessResult = checkIntentSchemaReadiness(input);\n const intentPaaCoverageResult = checkIntentPaaCoverage(input);\n\n // Intent: User Journey\n const intentSatisfactionResult = checkIntentSatisfactionScore(input);\n const intentFunnelPositionResult = checkIntentFunnelPosition(input);\n const intentRelatedCoverageResult = checkIntentRelatedCoverage(input);\n const intentEngagementSignalsResult = checkIntentEngagementSignals(input);\n\n // AEO: Answer Engine Optimization\n const aeoDirectAnswerResult = checkAeoDirectAnswer(input);\n const aeoFaqSectionResult = checkAeoFaqSection(input);\n const aeoFactDensityResult = checkAeoFactDensity(input);\n const aeoTldrSummaryResult = checkAeoTldrSummary(input);\n const aeoConciseAnswersResult = checkAeoConciseAnswers(input);\n const aeoStructuredDataResult = checkAeoStructuredDataHints(input);\n const aeoCitationResult = checkAeoCitationReadiness(input);\n const aeoEntityResult = checkAeoEntityCoverage(input);\n\n // Flatten all results\n const candidateResults = [\n ...titleResults,\n ...metaResults,\n ...keyphraseResults,\n ...headingResults,\n wordCountResult,\n ...imageResults,\n ...linkResults,\n paragraphResult,\n sentenceResult,\n subheadingResult,\n transitionResult,\n canonicalResult,\n keyphraseIntroductionResult,\n keyphraseSlugResult,\n keyphraseLengthResult,\n ...titleReadabilityResults,\n keyphraseTitlePositionResult,\n urlLengthResult,\n textPresenceResult,\n mediaCountResult,\n tableOfContentsResult,\n nofollowLinksResult,\n ...secondaryKeyphrasesResults,\n // E-E-A-T: Experience\n experienceDepthResult,\n originalResearchResult,\n specificityDepthResult,\n multimediaEvidenceResult,\n caseStudyResult,\n // E-E-A-T: Expertise\n authorSchemaResult,\n topicalAuthorityResult,\n technicalVocabularyResult,\n expertHedgingResult,\n methodologyResult,\n // E-E-A-T: Authoritativeness\n authorSocialResult,\n organizationResult,\n publishedWorksResult,\n expertSourcingResult,\n editorialReviewResult,\n // E-E-A-T: Trustworthiness\n sourceQualityResult,\n ymylComplianceResult,\n conflictDisclosureResult,\n contentAccuracyResult,\n correctionPolicyResult,\n privacySafetyResult,\n // E-E-A-T: Meta\n eeatOverallResult,\n ymylMultiplierResult,\n // Non-E-E-A-T\n previouslyUsedKeyphraseResult,\n keyphraseEvenDistributionResult,\n singleH1Result,\n wordComplexityResult,\n inclusiveLanguageResult,\n competingLinksResult,\n contentFreshnessResult,\n keyphraseMarkupResult,\n headlineAnalyzerResult,\n inboundInternalLinksResult,\n // Intent: Detection\n intentKeywordClassificationResult,\n intentSubTypeResult,\n intentModifierAnalysisResult,\n intentMultiDetectionResult,\n // Intent: Content Alignment\n intentContentAlignmentResult,\n intentTitleMatchResult,\n intentMetaMatchResult,\n intentHeadingMatchResult,\n intentOpeningMatchResult,\n intentConclusionMatchResult,\n // Intent: Specific Requirements\n intentInformationalResult,\n intentTransactionalResult,\n intentCommercialResult,\n intentNavigationalResult,\n intentFormatMatchResult,\n // Intent: Signal Quality\n intentSignalDensityResult,\n intentSignalDistributionResult,\n intentDepthMatchResult,\n intentMixedWarningResult,\n intentCtaAlignmentResult,\n // Intent: SERP Features\n intentSnippetReadinessResult,\n intentSchemaReadinessResult,\n intentPaaCoverageResult,\n // Intent: User Journey\n intentSatisfactionResult,\n intentFunnelPositionResult,\n intentRelatedCoverageResult,\n intentEngagementSignalsResult,\n // AEO: Answer Engine Optimization\n aeoDirectAnswerResult,\n aeoFaqSectionResult,\n aeoFactDensityResult,\n aeoTldrSummaryResult,\n aeoConciseAnswersResult,\n aeoStructuredDataResult,\n aeoCitationResult,\n aeoEntityResult,\n ];\n\n // Filter out disabled checks\n for (const result of candidateResults) {\n if (!disabled.has(result.id as CheckId)) {\n allResults.push(result);\n }\n }\n\n // Sum scores — exclude 'na' (not applicable) checks from both score and maxScore\n const applicableResults = allResults.filter((r) => r.status !== 'na');\n const score = applicableResults.reduce((sum, r) => sum + r.score, 0);\n const maxScore = applicableResults.reduce((sum, r) => sum + r.maxScore, 0);\n\n // Generate recommendations from poor/ok results (exclude 'na')\n const recommendations = applicableResults\n .filter((r) => r.status === 'poor' || r.status === 'ok')\n .map((r) => r.description);\n\n return {\n score,\n maxScore,\n results: allResults,\n recommendations,\n };\n}\n"],"mappings":"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","names":["import_core","import_core","import_core","import_core","import_core","import_core","countWords","import_core","countWords","import_core","splitSentences","stripHtml","import_core","import_core","import_core","import_core","import_core","import_core","suggestions","import_core","import_core","import_core","import_core","import_core","import_core","YMYL_CATEGORIES","import_core","import_core","examples","import_core","import_core","import_core","weakPillars","import_core","YMYL_CATEGORIES","DISCLAIMER_PATTERNS","import_core","missing","import_core","parseHeadings","import_core","COMPLEX_SYNONYMS","import_core","import_core","import_core","import_core","POWER_WORDS","INTENT_LABELS","primaryLabel","secondaryLabel","import_core","import_core","import_core","import_core","import_core","INFORMATIONAL_STRONG","INFORMATIONAL_WEAK","TRANSACTIONAL_STRONG","TRANSACTIONAL_WEAK","COMMERCIAL_STRONG","COMMERCIAL_WEAK","NAVIGATIONAL_STRONG","NAVIGATIONAL_WEAK","matchesAny","import_core","import_core","import_core","hasTable","import_core","import_core","hasOrderedList","hasTable","import_core","import_core","SIGNAL_PATTERNS","import_core","import_core","countMatches","import_core","import_core","missingNames","import_core","import_core","import_core","import_core","import_core","checkTableOfContents","import_core","kpNote","import_core","import_core","import_core","import_core","import_core","import_core","import_core"]}
|