aeorank 3.0.0 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.d.ts +6 -0
- package/dist/browser.js +80 -4
- package/dist/browser.js.map +1 -1
- package/dist/cli.js +149 -4
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +128 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +128 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -197,6 +197,12 @@ interface RawDataSummary {
|
|
|
197
197
|
crawl_discovered: number;
|
|
198
198
|
crawl_fetched: number;
|
|
199
199
|
crawl_skipped: number;
|
|
200
|
+
citation_ready_sentences: number;
|
|
201
|
+
answer_first_ratio: number;
|
|
202
|
+
evidence_citations_avg: number;
|
|
203
|
+
entity_disambiguation_ratio: number;
|
|
204
|
+
extraction_friction_avg: number;
|
|
205
|
+
image_figure_ratio: number;
|
|
200
206
|
}
|
|
201
207
|
/**
|
|
202
208
|
* Fetches all site data in parallel with HTTPS/HTTP fallback.
|
package/dist/index.d.ts
CHANGED
|
@@ -197,6 +197,12 @@ interface RawDataSummary {
|
|
|
197
197
|
crawl_discovered: number;
|
|
198
198
|
crawl_fetched: number;
|
|
199
199
|
crawl_skipped: number;
|
|
200
|
+
citation_ready_sentences: number;
|
|
201
|
+
answer_first_ratio: number;
|
|
202
|
+
evidence_citations_avg: number;
|
|
203
|
+
entity_disambiguation_ratio: number;
|
|
204
|
+
extraction_friction_avg: number;
|
|
205
|
+
image_figure_ratio: number;
|
|
200
206
|
}
|
|
201
207
|
/**
|
|
202
208
|
* Fetches all site data in parallel with HTTPS/HTTP fallback.
|
package/dist/index.js
CHANGED
|
@@ -1824,7 +1824,83 @@ function extractRawDataSummary(data) {
|
|
|
1824
1824
|
// Full-crawl stats
|
|
1825
1825
|
crawl_discovered: data.crawlStats?.discovered ?? 0,
|
|
1826
1826
|
crawl_fetched: data.crawlStats?.fetched ?? 0,
|
|
1827
|
-
crawl_skipped: data.crawlStats?.skipped ?? 0
|
|
1827
|
+
crawl_skipped: data.crawlStats?.skipped ?? 0,
|
|
1828
|
+
// V2 criteria fields
|
|
1829
|
+
citation_ready_sentences: (() => {
|
|
1830
|
+
const combinedText = text + " " + (data.blogSample?.map((p) => p.text.replace(/<[^>]*>/g, " ")).join(" ") || "");
|
|
1831
|
+
return (combinedText.match(/\b\w+\s+(is\s+(?:a|an)\s|refers\s+to|defined\s+as)\b/gi) || []).length;
|
|
1832
|
+
})(),
|
|
1833
|
+
answer_first_ratio: (() => {
|
|
1834
|
+
const pages = [html, ...data.blogSample?.map((p) => p.text) || []];
|
|
1835
|
+
let answerFirst = 0;
|
|
1836
|
+
for (const pageHtml of pages) {
|
|
1837
|
+
const bodyMatch = pageHtml.match(/<body[^>]*>([\s\S]*)/i);
|
|
1838
|
+
const bodyHtml = bodyMatch ? bodyMatch[1] : pageHtml;
|
|
1839
|
+
const earlyParas = bodyHtml.match(/<p[^>]*>([\s\S]*?)<\/p>/gi)?.slice(0, 5) || [];
|
|
1840
|
+
for (const p of earlyParas) {
|
|
1841
|
+
const pText = p.replace(/<[^>]*>/g, "").trim();
|
|
1842
|
+
const wc = pText.split(/\s+/).length;
|
|
1843
|
+
if (wc >= 40 && wc <= 80) {
|
|
1844
|
+
answerFirst++;
|
|
1845
|
+
break;
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
return pages.length > 0 ? Math.round(answerFirst / pages.length * 100) : 0;
|
|
1850
|
+
})(),
|
|
1851
|
+
evidence_citations_avg: (() => {
|
|
1852
|
+
const allHtml = html + "\n" + (data.blogSample?.map((p) => p.text).join("\n") || "");
|
|
1853
|
+
const paragraphs = allHtml.match(/<p[^>]*>[\s\S]*?<\/p>/gi) || [];
|
|
1854
|
+
let citations = 0;
|
|
1855
|
+
const domainLower = data.domain.replace(/^www\./, "").toLowerCase();
|
|
1856
|
+
for (const p of paragraphs) {
|
|
1857
|
+
const links = p.match(/<a[^>]*href=["'](https?:\/\/[^"']+)["'][^>]*>/gi) || [];
|
|
1858
|
+
for (const link of links) {
|
|
1859
|
+
const href = link.match(/href=["'](https?:\/\/[^"']+)["']/i);
|
|
1860
|
+
if (href) {
|
|
1861
|
+
try {
|
|
1862
|
+
const ld = new URL(href[1]).hostname.replace(/^www\./, "").toLowerCase();
|
|
1863
|
+
if (ld !== domainLower) citations++;
|
|
1864
|
+
} catch {
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
const pageCount = Math.max(1, 1 + (data.blogSample?.length ?? 0));
|
|
1870
|
+
return Math.round(citations / pageCount * 10) / 10;
|
|
1871
|
+
})(),
|
|
1872
|
+
entity_disambiguation_ratio: (() => {
|
|
1873
|
+
const pages = [html, ...data.blogSample?.map((p) => p.text) || []];
|
|
1874
|
+
let defined = 0;
|
|
1875
|
+
for (const pageHtml of pages) {
|
|
1876
|
+
const h1Match = pageHtml.match(/<h1[^>]*>([\s\S]*?)<\/h1>/i);
|
|
1877
|
+
if (!h1Match) continue;
|
|
1878
|
+
const h1Text = h1Match[1].replace(/<[^>]*>/g, "").trim();
|
|
1879
|
+
const h1Words = h1Text.split(/\s+/).filter((w) => w.length > 3);
|
|
1880
|
+
const primaryNoun = h1Words.sort((a, b) => b.length - a.length)[0] || "";
|
|
1881
|
+
if (!primaryNoun) continue;
|
|
1882
|
+
const pageText = pageHtml.replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").slice(0, 500);
|
|
1883
|
+
if (new RegExp(`\\b${primaryNoun.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b[^.]*\\b(is|refers|defined|means)\\b`, "i").test(pageText)) {
|
|
1884
|
+
defined++;
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
return pages.length > 0 ? Math.round(defined / pages.length * 100) : 0;
|
|
1888
|
+
})(),
|
|
1889
|
+
extraction_friction_avg: (() => {
|
|
1890
|
+
const combinedText = text + " " + (data.blogSample?.map((p) => p.text.replace(/<[^>]*>/g, " ")).join(" ") || "");
|
|
1891
|
+
const sentences = combinedText.split(/[.!?]+/).filter((s) => s.trim().length > 5);
|
|
1892
|
+
if (sentences.length === 0) return 0;
|
|
1893
|
+
const totalWords = sentences.reduce((sum, s) => sum + s.trim().split(/\s+/).length, 0);
|
|
1894
|
+
return Math.round(totalWords / sentences.length * 10) / 10;
|
|
1895
|
+
})(),
|
|
1896
|
+
image_figure_ratio: (() => {
|
|
1897
|
+
const combinedHtml = html + "\n" + (data.blogSample?.map((p) => p.text).join("\n") || "");
|
|
1898
|
+
const allImages = combinedHtml.match(/<img\s[^>]*>/gi) || [];
|
|
1899
|
+
if (allImages.length === 0) return 0;
|
|
1900
|
+
const figureBlocks = combinedHtml.match(/<figure[\s\S]*?<\/figure>/gi) || [];
|
|
1901
|
+
const figuresWithCaption = figureBlocks.filter((f) => /<figcaption/i.test(f));
|
|
1902
|
+
return Math.round(figuresWithCaption.length / allImages.length * 100);
|
|
1903
|
+
})()
|
|
1828
1904
|
};
|
|
1829
1905
|
}
|
|
1830
1906
|
function getPageTopicText(html) {
|
|
@@ -4555,8 +4631,8 @@ function extractLinksWithAnchors(html, sourceUrl, domain) {
|
|
|
4555
4631
|
if (href.startsWith("//")) {
|
|
4556
4632
|
fullUrl = `https:${href}`;
|
|
4557
4633
|
} else if (href.startsWith("/")) {
|
|
4558
|
-
if (href
|
|
4559
|
-
fullUrl = `https://${domain}${href}`;
|
|
4634
|
+
if (href.startsWith("/#")) continue;
|
|
4635
|
+
fullUrl = href === "/" ? `https://${domain}` : `https://${domain}${href}`;
|
|
4560
4636
|
} else if (href.startsWith("http")) {
|
|
4561
4637
|
fullUrl = href;
|
|
4562
4638
|
} else if (href.startsWith("#") || href.startsWith("?") || href.startsWith("mailto:") || href.startsWith("tel:") || href.startsWith("javascript:")) {
|
|
@@ -4570,7 +4646,7 @@ function extractLinksWithAnchors(html, sourceUrl, domain) {
|
|
|
4570
4646
|
if (linkDomain !== cleanDomain) continue;
|
|
4571
4647
|
parsed.hash = "";
|
|
4572
4648
|
const path = parsed.pathname;
|
|
4573
|
-
if (path === "
|
|
4649
|
+
if (path === "") continue;
|
|
4574
4650
|
if (RESOURCE_EXTENSIONS.test(path)) continue;
|
|
4575
4651
|
if (SKIP_PATH_PATTERNS.test(path)) continue;
|
|
4576
4652
|
const normalized = normalizeUrl(fullUrl);
|
|
@@ -6090,6 +6166,22 @@ var CSS = `
|
|
|
6090
6166
|
.criterion-score { font-size: 14px; font-weight: 700; min-width: 32px; text-align: center; }
|
|
6091
6167
|
.criterion-name { font-size: 13px; flex: 1; }
|
|
6092
6168
|
.criterion-status { font-size: 11px; color: #666; background: #f0f0f0; padding: 2px 8px; border-radius: 10px; white-space: nowrap; }
|
|
6169
|
+
.criterion-pillar { display: block; font-size: 10px; color: #999; font-weight: 400; margin-top: 2px; }
|
|
6170
|
+
.pillar-grid { background: #fff; border: 1px solid #e0e0e0; border-radius: 8px; padding: 16px 20px; margin-bottom: 32px; }
|
|
6171
|
+
.pillar-row { display: flex; align-items: center; gap: 12px; padding: 8px 0; }
|
|
6172
|
+
.pillar-row + .pillar-row { border-top: 1px solid #f0f0f0; }
|
|
6173
|
+
.pillar-name { font-size: 14px; font-weight: 500; min-width: 180px; }
|
|
6174
|
+
.pillar-weight { font-size: 11px; color: #999; font-weight: 400; }
|
|
6175
|
+
.pillar-bar { flex: 1; height: 10px; background: #e0e0e0; border-radius: 5px; overflow: hidden; }
|
|
6176
|
+
.pillar-bar-fill { height: 100%; border-radius: 5px; transition: width 0.3s; }
|
|
6177
|
+
.pillar-score { font-size: 16px; font-weight: 700; min-width: 36px; text-align: right; }
|
|
6178
|
+
.top-fixes { background: #fff; border: 1px solid #e0e0e0; border-radius: 8px; padding: 16px 20px; margin-bottom: 32px; }
|
|
6179
|
+
.fix-item { display: flex; align-items: center; gap: 12px; padding: 10px 0; }
|
|
6180
|
+
.fix-item + .fix-item { border-top: 1px solid #f0f0f0; }
|
|
6181
|
+
.fix-num { font-size: 16px; font-weight: 700; color: #FF5722; min-width: 24px; }
|
|
6182
|
+
.fix-name { flex: 1; font-size: 14px; font-weight: 500; }
|
|
6183
|
+
.fix-impact { font-size: 13px; font-weight: 600; color: #4CAF50; }
|
|
6184
|
+
.fix-effort { font-size: 12px; color: #999; }
|
|
6093
6185
|
table { width: 100%; border-collapse: collapse; background: #fff; border: 1px solid #e0e0e0; border-radius: 8px; overflow: hidden; margin-bottom: 32px; }
|
|
6094
6186
|
th { background: #f5f5f5; text-align: left; padding: 10px 14px; font-size: 13px; font-weight: 600; color: #555; border-bottom: 1px solid #e0e0e0; }
|
|
6095
6187
|
td { padding: 10px 14px; font-size: 13px; border-bottom: 1px solid #f0f0f0; }
|
|
@@ -6135,10 +6227,11 @@ function generateHtmlReport(result) {
|
|
|
6135
6227
|
const scorecardCards = result.scorecard.map((item) => {
|
|
6136
6228
|
const color = criterionColor(item.score);
|
|
6137
6229
|
const width = item.score * 10;
|
|
6230
|
+
const pillarTag = item.pillar ? `<span class="criterion-pillar">${escapeHtml(item.pillar)}</span>` : "";
|
|
6138
6231
|
return `<div class="criterion-card">
|
|
6139
6232
|
<div class="criterion-bar"><div class="criterion-bar-fill" style="width:${width}%;background:${color}"></div></div>
|
|
6140
6233
|
<span class="criterion-score" style="color:${color}">${item.score}/10</span>
|
|
6141
|
-
<span class="criterion-name">${escapeHtml(item.criterion)}</span>
|
|
6234
|
+
<span class="criterion-name">${escapeHtml(item.clientName || item.criterion)}${pillarTag}</span>
|
|
6142
6235
|
<span class="criterion-status">${escapeHtml(item.status)}</span>
|
|
6143
6236
|
</div>`;
|
|
6144
6237
|
}).join("\n");
|
|
@@ -6190,11 +6283,40 @@ function generateHtmlReport(result) {
|
|
|
6190
6283
|
|
|
6191
6284
|
<div class="verdict">${escapeHtml(result.verdict)}</div>
|
|
6192
6285
|
|
|
6193
|
-
<h2 class="section-title">Scorecard (
|
|
6286
|
+
<h2 class="section-title">Scorecard (34 Criteria)</h2>
|
|
6194
6287
|
<div class="scorecard-grid">
|
|
6195
6288
|
${scorecardCards}
|
|
6196
6289
|
</div>
|
|
6197
6290
|
|
|
6291
|
+
${result.pillarScores ? `
|
|
6292
|
+
<h2 class="section-title">Pillar Scores</h2>
|
|
6293
|
+
<div class="pillar-grid">
|
|
6294
|
+
${[
|
|
6295
|
+
{ name: "Answer Readiness", score: result.pillarScores.answerReadiness, weight: "~40%" },
|
|
6296
|
+
{ name: "Content Structure", score: result.pillarScores.contentStructure, weight: "~25%" },
|
|
6297
|
+
{ name: "Trust & Authority", score: result.pillarScores.trustAuthority, weight: "~15%" },
|
|
6298
|
+
{ name: "Technical Foundation", score: result.pillarScores.technicalFoundation, weight: "~10%" },
|
|
6299
|
+
{ name: "AI Discovery", score: result.pillarScores.aiDiscovery, weight: "~10%" }
|
|
6300
|
+
].map((p) => `<div class="pillar-row">
|
|
6301
|
+
<span class="pillar-name">${p.name} <span class="pillar-weight">${p.weight}</span></span>
|
|
6302
|
+
<div class="pillar-bar"><div class="pillar-bar-fill" style="width:${p.score}%;background:${scoreColor(p.score)}"></div></div>
|
|
6303
|
+
<span class="pillar-score" style="color:${scoreColor(p.score)}">${p.score}</span>
|
|
6304
|
+
</div>`).join("\n")}
|
|
6305
|
+
</div>
|
|
6306
|
+
` : ""}
|
|
6307
|
+
|
|
6308
|
+
${result.topFixes && result.topFixes.length > 0 ? `
|
|
6309
|
+
<h2 class="section-title">Top Fixes</h2>
|
|
6310
|
+
<div class="top-fixes">
|
|
6311
|
+
${result.topFixes.map((f, i) => `<div class="fix-item">
|
|
6312
|
+
<span class="fix-num">${i + 1}</span>
|
|
6313
|
+
<span class="fix-name">${escapeHtml(f.fix)}</span>
|
|
6314
|
+
<span class="fix-impact">${escapeHtml(f.impact)}</span>
|
|
6315
|
+
<span class="fix-effort">${escapeHtml(f.effort)} effort</span>
|
|
6316
|
+
</div>`).join("\n")}
|
|
6317
|
+
</div>
|
|
6318
|
+
` : ""}
|
|
6319
|
+
|
|
6198
6320
|
${result.opportunities.length > 0 ? `
|
|
6199
6321
|
<h2 class="section-title">Opportunities (${result.opportunities.length})</h2>
|
|
6200
6322
|
<table>
|