aiseo-audit 1.4.7 → 1.4.9
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/chunk-DTQ5AQ4G.js +753 -0
- package/dist/chunk-ZPTXGBAU.mjs +753 -0
- package/dist/cli.js +3 -4613
- package/dist/cli.mjs +3 -4589
- package/dist/index.js +1 -4510
- package/dist/index.mjs +1 -4468
- package/package.json +1 -1
|
@@ -0,0 +1,753 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var H="1.4.9";var te={Accept:"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","Accept-Language":"en-US,en;q=0.9","Accept-Encoding":"gzip, deflate, br","Cache-Control":"no-cache"};var _=class extends Error{constructor(e,o,s){super(s),this.name="FetchError",this.code=e,this.url=o}};function Se(t,e){if(t instanceof _)return t;let o=t instanceof Error?t.message:String(t),s=t instanceof Error&&t.cause instanceof Error?t.cause.message:"",r=`${o} ${s}`.toLowerCase();if(t instanceof DOMException||t instanceof Error&&t.name==="AbortError"||r.includes("abort"))return new _("TIMEOUT",e,`Request timed out. The server at "${new URL(e).hostname}" did not respond in time.`);if(r.includes("getaddrinfo")||r.includes("enotfound")){let n=new URL(e).hostname;return new _("DNS_FAILURE",e,`DNS lookup failed for "${n}". Check that the domain exists and is spelled correctly.`)}return r.includes("econnrefused")?new _("CONNECTION_REFUSED",e,`Connection refused by "${new URL(e).hostname}". The server may be down or not accepting connections.`):r.includes("cert")||r.includes("ssl")||r.includes("tls")||r.includes("unable to verify")?new _("TLS_ERROR",e,`TLS/SSL error connecting to "${new URL(e).hostname}". The site may have an invalid or expired certificate.`):new _("NETWORK_ERROR",e,`Network error fetching "${e}": ${o}`)}async function B(t){let e=new AbortController,o=setTimeout(()=>e.abort(),t.timeout);try{let s=await fetch(t.url,{method:"GET",headers:{"User-Agent":t.userAgent,...te},signal:e.signal,redirect:"follow"}),r=s.headers.get("content-length");if(r&&parseInt(r,10)>10485760)throw new _("TOO_LARGE",t.url,`Response from "${new URL(t.url).hostname}" exceeds the ${Math.round(10485760/1024/1024)}MB size limit.`);let n=await s.text();if(n.length>10485760)throw new _("TOO_LARGE",t.url,`Response from "${new URL(t.url).hostname}" exceeds the ${Math.round(10485760/1024/1024)}MB size limit.`);let a={};return s.headers.forEach((i,c)=>{a[c]=i}),{status:s.status,data:n,headers:a,finalUrl:s.url}}catch(s){throw Se(s,t.url)}finally{clearTimeout(o)}}async function oe(t){let e=new AbortController,o=setTimeout(()=>e.abort(),t.timeout);try{let s=await fetch(t.url,{method:"HEAD",headers:{"User-Agent":t.userAgent,...te},signal:e.signal,redirect:"follow"}),r={};return s.headers.forEach((n,a)=>{r[a]=n}),{status:s.status,data:"",headers:r,finalUrl:s.url}}catch(s){throw Se(s,t.url)}finally{clearTimeout(o)}}function V(t){let e=t.trim();return/^https?:\/\//i.test(e)||(e=`https://${e}`),new URL(e).toString().replace(/\/+$/,"")}function Fo(t){try{let e=V(t);return new URL(e),!0}catch (e2){return!1}}function se(t){try{return new URL(t).hostname}catch (e3){return t}}var _compromise = require('compromise'); var _compromise2 = _interopRequireDefault(_compromise);var ve=new Set(["a","an","the","and","or","but","in","on","at","to","for","of","with","by","from","as","is","was","are","were","been","be","have","has","had","do","does","did","will","would","could","should","may","might","shall","can","need","must","that","which","who","whom","this","these","those","it","its","he","she","they","we","you","i","me","him","her","us","them","my","your","his","our","their","what","when","where","how","why","all","each","every","both","few","more","most","other","some","such","no","nor","not","only","own","same","so","than","too","very","just","about","above","after","again","also","any","because","before","between","during","here","if","into","like","new","now","over","then","there","through","under","up","out","off","down","much","well","back","even","still","also","get","got","one","two","make","many","say","said","see","go","come","take","know","think","good","great","first","last","long","way","find","use","used","using","while","being","made","however","since","per","via","based","within","without","across","along","around","among","until","another","www","http","https","com"]),Ae=new Set(["I","A","OK","AM","PM","US","UK","EU","VS","EG","IE","ET","AL","HTML","CSS","JS","TS","URL","HTTP","HTTPS","API","SDK","CLI","GUI","PDF","CSV","JSON","XML","SQL","RSS","FTP","SSH","SSL","TLS","DNS","TCP","UDP","IP","RAM","ROM","CPU","GPU","SSD","HDD","USB","HDMI","FAQ","DIY","ASAP","FYI","TBD","TBA","ETA","ROI","KPI","CEO","CTO","CFO","COO","CIO","VP","SVP","EVP","HR","PR","QA","IT","RD","RND","LLC","INC","LTD","CORP","PLC","USD","EUR","GBP","JPY","CAD","ID","NO","RE","CC","BCC","GEO","SEO","SEM","PPC","CMS","CRM","ERP","SaaS","AI","ML","NLP","LLM","GPT","NER","TLDR","AKA","RSVP","PS"]),Te=/\b(?:Inc|Corp|Corporation|LLC|Ltd|Limited|Co|Company|Group|Foundation|Institute|University|Association|Society|Agency|Authority|Bureau|Commission|Council|Department|Board|Trust|Fund|Partners|Ventures|Labs|Technologies|Solutions|Systems|Services|Consulting|Media|Network|Studios|Entertainment|Healthcare|Pharmaceuticals|Dynamics|Holdings|Capital|Enterprises|International)\b/i,$e=/\b(?:Mr|Mrs|Ms|Miss|Dr|Prof|Professor|Rev|Reverend|Sen|Senator|Rep|Representative|Gov|Governor|Pres|President|Gen|General|Col|Colonel|Sgt|Sergeant|Cpl|Corporal|Pvt|Private|Adm|Admiral|Capt|Captain|Lt|Lieutenant|Maj|Major|Sir|Dame|Lord|Lady|Hon|Honorable|Judge|Justice|Chancellor|Dean|Provost)\.\s*/;function Ee(t){let e=t.match(/\b[A-Z]{2,6}\b/g);if(!e)return[];let o=new Set,s=[];for(let r of e)!Ae.has(r)&&!o.has(r)&&(o.add(r),s.push(r));return s}function Ce(t){let e=/\b([A-Z][a-z]+(?:\s+(?:of|the|and|for|de|van|von|al|el|la|le|del|der|den|das|di|du))?\s+(?:[A-Z][a-z]+)(?:\s+[A-Z][a-z]+){0,3})\b/g,o=t.split(/[.!?]\s+/),s=new Set;for(let i of o){let l=i.trim().split(/\s+/)[0];l&&s.add(l)}let r=new Set,n=[],a;for(;(a=e.exec(t))!==null;){let i=a[1],c=i.split(/\s+/)[0];if(s.has(c)&&!t.includes(`. ${i}`)&&!t.includes(`, ${i}`)){let l=i.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),p=t.match(new RegExp(l,"g"));if(!p||p.length<2)continue}!r.has(i)&&i.split(/\s+/).length>=2&&(r.add(i),n.push(i))}return n}function Re(t){return Te.test(t)}function Ie(t,e){let o=e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`(?:${$e.source})\\s*${o}`,"i").test(t)}function re(t){if(t.length===0)return[];let e=[...t].sort((r,n)=>n.length-r.length),o=[],s=new Set;for(let r of e){let n=r.toLowerCase();if(s.has(n))continue;let a=!1;for(let i of s)if(i.includes(n)){a=!0;break}a||(o.push(r),s.add(n))}return o}function ne(t,e,o){let s=[...t,...e];return re(s).slice(0,o)}function Pe(t,e){let s=t.toLowerCase().replace(/[^a-z0-9\s'-]/g," ").split(/\s+/).filter(a=>a.length>2&&!ve.has(a));if(s.length===0)return[];let r=new Map;for(let a of s)r.set(a,(r.get(a)||0)+1);for(let a=0;a<s.length-1;a++){let i=`${s[a]} ${s[a+1]}`;r.set(i,(r.get(i)||0)+1)}let n=[];for(let[a,i]of r)if(i>=2){let l=a.includes(" ")?i*1.5:i;n.push([a,l])}return n.sort((a,i)=>i[1]-a[1]),n.slice(0,e).map(([a])=>a)}function F(t,e){let o=0;for(let s of e){let r=new RegExp(s.source,s.flags),n=t.match(r);n&&(o+=n.length)}return o}function ae(t,e){let o=t.toLowerCase();return e.filter(s=>o.includes(s)).length}function Y(t){return t.split(/\s+/).filter(e=>e.length>0).length}function Oe(t){return t.split(/[.!?]+/).filter(e=>e.trim().length>5).length}function ie(t){if(t=t.toLowerCase().replace(/[^a-z]/g,""),t.length<=3)return 1;t=t.replace(/(?:[^laeiouy]es|ed|[^laeiouy]e)$/,""),t=t.replace(/^y/,"");let e=t.match(/[aeiouy]{1,2}/g);return e?Math.max(e.length,1):1}function ce(t){let e=t.split(/\s+/).filter(a=>a.length>0),o=t.split(/[.!?]+/).filter(a=>a.trim().length>5),s=e.reduce((a,i)=>a+ie(i),0);if(e.length===0||o.length===0)return 0;let r=e.length/o.length,n=s/e.length;return 206.835-1.015*r-84.6*n}function le(t){return t.split(/\s+/).filter(o=>o.length>0).filter(o=>ie(o)>=4).length}function pe(t){let e=t.split(/\s+/).filter(s=>s.length>0),o=t.split(/[.!?]+/).filter(s=>s.trim().length>5);return o.length===0?0:Math.round(e.length/o.length)}function G(t){let e=_compromise2.default.call(void 0, t),o=[...new Set(e.people().out("array"))],s=[...new Set(e.organizations().out("array"))],r=[...new Set(e.places().out("array"))],n=Ee(t),a=Ce(t),i=[],c=[],l=[];for(let y of a)Ie(t,y)?i.push(y):Re(y)?c.push(y):l.push(y);l.push(...n);let p=ne(o,i,10),h=ne(s,[...c,...l],10),d=re([...new Set(r)]).slice(0,10),v=Pe(t,15),x=e.verbs().isImperative().length,w=e.numbers().length;return{people:p,organizations:h,places:d,topics:v,imperativeVerbCount:x,numberCount:w}}var I={contentExtractability:"Content Extractability",contentStructure:"Content Structure for Reuse",answerability:"Answerability",entityClarity:"Entity Clarity",groundingSignals:"Grounding Signals",authorityContext:"Authority Context",readabilityForCompression:"Readability for Compression"};var ke=[/\bis\s+defined\s+as\b/gi,/\brefers?\s+to\b/gi,/\bmeans?\s+that\b/gi,/\bis\s+a\s+type\s+of\b/gi,/\bcan\s+be\s+described\s+as\b/gi,/\balso\s+known\s+as\b/gi],Le=[/\[\d+\]/g,/\([\w\s]+,?\s*\d{4}\)/g,/according\s+to/gi,/research\s+(?:shows|indicates|suggests)/gi,/studies?\s+(?:show|indicate|suggest|found)/gi,/data\s+from/gi,/as\s+reported\s+by/gi],De=[/according\s+to/gi,/\bsaid\b/gi,/\bstated\b/gi,/\breported\b/gi,/\bcited\s+by\b/gi],Me=[/\d+(?:\.\d+)?\s*%/g,/\d+(?:\.\d+)?\s*(?:million|billion|thousand|trillion)/gi,/\$[\d,.]+/g,/increased\s+by/gi,/decreased\s+by/gi,/grew\s+by/gi],Fe=[/step\s+\d+/gi,/^\s*\d+\.\s+\w/gm,/\bfirst(?:ly)?,?\s/gi,/\bsecond(?:ly)?,?\s/gi,/\bfinally,?\s/gi,/\bhow\s+to\b/gi],Ue=[/\bin\s+summary\b/gi,/\bin\s+conclusion\b/gi,/\bto\s+summarize\b/gi,/\bkey\s+takeaways?\b/gi,/\bbottom\s+line\b/gi,/\btl;?dr\b/gi],Ne=[/what\s+is/gi,/what\s+are/gi,/how\s+to/gi,/how\s+do/gi,/why\s+is/gi,/why\s+do/gi,/when\s+to/gi,/where\s+to/gi,/which\s+is/gi,/who\s+is/gi],ze=[/^The\s+\w+\s+is\b/gm,/^It\s+is\b/gm,/^This\s+is\b/gm,/^They\s+are\b/gm,/\bsimply\s+put\b/gi,/\bin\s+short\b/gi],_e=["however","therefore","moreover","furthermore","consequently","additionally","in contrast","similarly","as a result","for example","for instance","on the other hand","nevertheless","meanwhile","likewise","in addition","specifically","in particular","notably","importantly"],je=['[rel="author"]',".author",".byline",'[itemprop="author"]',".post-author",".entry-author",'meta[name="author"]'],He=["time[datetime]",'[itemprop="datePublished"]','[itemprop="dateModified"]',".published",".post-date",".entry-date",'meta[property="article:published_time"]','meta[property="article:modified_time"]'],Ge=/^(?:what|how|why|when|where|which|who|can|do|does|is|are|should|will)\b/i,We=[/"[^"]{10,}"\s*[-\u2013\u2014]\s*[A-Z][a-z]+/g,/"[^"]{10,}",?\s+said\s+[A-Z]/g,/"[^"]{10,}",?\s+according\s+to\s+[A-Z]/g,/according\s+to\s+[A-Z][a-z]+[^,]*,\s*"[^"]{10,}"/g,/\u201c[^\u201d]{10,}\u201d\s*[-\u2013\u2014]\s*[A-Z][a-z]+/g,/\u201c[^\u201d]{10,}\u201d,?\s+said\s+[A-Z]/g],ue=["GPTBot","ChatGPT-User","ClaudeBot","PerplexityBot","Google-Extended"],Be=['[itemprop="dateModified"]','meta[property="article:modified_time"]'],qe=["time[datetime]",'[itemprop="datePublished"]','meta[property="article:published_time"]'];function Ye(t){let e=0,o=0;return t("h2").each((s,r)=>{let n=t(r).text().trim();if(!(n.includes("?")||Ge.test(n)))return;e++;let i=t(r).nextAll("p").first();if(!i.length)return;let l=i.text().trim().split(/[.!?]/)[0]||"";l.length>0&&l.length<=200&&o++}),{total:e,withCapsule:o}}function Je(t){let e=t("h1, h2, h3, h4, h5, h6");if(e.length===0)return{sectionCount:0,avgWordsPerSection:0,sections:[]};let o=[];e.each((r,n)=>{let a=0,i=t(n).next();for(;i.length&&!i.is("h1, h2, h3, h4, h5, h6");){let c=i.text().trim();a+=c.split(/\s+/).filter(l=>l.length>0).length,i=i.next()}a>0&&o.push(a)});let s=o.length>0?Math.round(o.reduce((r,n)=>r+n,0)/o.length):0;return{sectionCount:o.length,avgWordsPerSection:s,sections:o}}function Ve(t){let e=[];return t('script[type="application/ld+json"]').each((o,s)=>{try{let r=JSON.parse(t(s).html()||"{}");Array.isArray(r)?e.push(...r):e.push(r)}catch (e4){}}),e}function E(t,e){for(let[o,s]of e)if(t>=o)return s;return 0}function Qt(t,e){let o=e>0?t/e:0;return o>=.7?"good":o>=.3?"needs_improvement":"critical"}function f(t,e,o,s,r){return{name:t,score:Math.round(Math.min(e,o)),maxScore:o,value:s,status:_nullishCoalesce(r, () => (Qt(e,o)))}}function P(t){return t.reduce((e,o)=>e+o.score,0)}function O(t){return t.reduce((e,o)=>e+o.maxScore,0)}function Qe(t,e){let o=t.cleanText,s=t.$,r=[],{imperativeVerbCount:n=0}=_nullishCoalesce(e, () => (G(o))),a=F(o,ke),i=E(a,[[6,10],[3,7],[1,4],[0,0]]);r.push(f("Definition Patterns",i,10,`${a} definition patterns`));let c=F(o,ze),l=E(c,[[5,11],[2,8],[1,4],[0,0]]);r.push(f("Direct Answer Statements",l,11,`${c} direct statements`));let p=Ye(t.$),h=p.total>0?p.withCapsule/p.total:0,d=p.total===0?0:h>=.7?13:h>=.4?9:h>0?5:2;r.push(f("Answer Capsules",d,13,p.total>0?`${p.withCapsule}/${p.total} question headings have answer capsules`:"No question-framed H2s found",p.total===0?"neutral":void 0));let v=F(o,Fe),x=s("ol").length>0,w=v+n+(x?2:0),y=E(w,[[5,10],[2,7],[1,3],[0,0]]);r.push(f("Step-by-Step Content",y,10,`${v} step indicators, ${n} instruction verbs${x?", ordered lists found":""}`));let b=o.match(/[^.!?]*\?/g)||[],m=F(o,Ne),A=E(b.length+m,[[10,11],[5,8],[2,5],[1,2],[0,0]]);r.push(f("Q/A Patterns",A,11,`${b.length} questions, ${m} query patterns`));let T=F(o,Ue),$=T>=2?9:T>0?5:0;return r.push(f("Summary/Conclusion",$,9,T>0?`${T} summary markers`:"No summary markers")),{category:{name:I.answerability,key:"answerability",score:P(r),maxScore:O(r),factors:r},rawData:{answerCapsules:p,questionsFound:b.slice(0,5)}}}function Ke(t){let e=_optionalChain([t, 'call', _2 => _2('meta[property="og:site_name"]'), 'access', _3 => _3.attr, 'call', _4 => _4("content"), 'optionalAccess', _5 => _5.trim, 'call', _6 => _6()]);if(e)return e;let o=t('script[type="application/ld+json"]'),s=null;return o.each((r,n)=>{try{let a=JSON.parse(t(n).html()||"{}");a["@type"]==="Organization"&&a.name&&(s=String(a.name).trim()),_optionalChain([a, 'access', _7 => _7.publisher, 'optionalAccess', _8 => _8.name])&&(s=s||String(a.publisher.name).trim())}catch (e5){}}),s||null}function Xe(t,e,o){if(!o)return{score:0,surfacesFound:0,surfacesChecked:0};let s=o.toLowerCase(),r=4,n=0;e.toLowerCase().includes(s)&&n++,(t('meta[property="og:title"]').attr("content")||"").toLowerCase().includes(s)&&n++,t("footer").text().toLowerCase().includes(s)&&n++;let c=t('[class*="copyright"], [class*="legal"]').text().toLowerCase(),l=t("header").text().toLowerCase();return(c.includes(s)||l.includes(s))&&n++,{score:n>=4?10:n>=3?7:n>=2?4:n>=1?2:0,surfacesFound:n,surfacesChecked:r}}function Ze(t){let e=null,o=null;for(let n of Be){let a=t(n).first();if(a.length){e=a.attr("datetime")||a.attr("content")||a.text().trim();break}}for(let n of qe){let a=t(n).first();if(a.length){o=a.attr("datetime")||a.attr("content")||a.text().trim();break}}let s=e||o,r=null;if(s){let n=new Date(s);if(!isNaN(n.getTime())){let a=new Date;r=(a.getFullYear()-n.getFullYear())*12+(a.getMonth()-n.getMonth())}}return{publishDate:o,modifiedDate:e,ageInMonths:r,hasModifiedDate:!!e}}var Kt={Article:["headline","author","datePublished"],NewsArticle:["headline","author","datePublished"],BlogPosting:["headline","author","datePublished"],FAQPage:["mainEntity"],HowTo:["name","step"],Organization:["name","url"],LocalBusiness:["name","address"],Product:["name"],WebPage:["name"]};function et(t){let e=[];for(let s of t){let r=String(s["@type"]||""),n=Kt[r];if(!n)continue;let a=n.filter(c=>s[c]!=null),i=n.filter(c=>s[c]==null);e.push({type:r,present:a,missing:i})}let o=e.length>0?e.reduce((s,r)=>s+r.present.length/(r.present.length+r.missing.length),0)/e.length:0;return{totalTypes:e.length,avgCompleteness:o,details:e}}function tt(t){let e=t.$,o=[],s={},r=!1,n="";for(let k of je){let C=e(k).first();if(C.length){r=!0,n=C.text().trim()||C.attr("content")||"Found";break}}o.push(f("Author Attribution",r?10:0,10,r?n:"Not found"));let a=t.html.includes('"@type":"Organization"')||t.html.includes('"@type": "Organization"'),i=e('meta[property="og:site_name"]').attr("content")||"",c=a||i.length>0;o.push(f("Organization Identity",c?10:0,10,c?i||"Schema found":"Not found"));let l=e('a[href*="about"], a[href*="team"], a[href*="company"]').length>0,p=e('a[href*="contact"]').length>0,h=l&&p?10:l||p?5:0;o.push(f("Contact/About Links",h,10,`${l?"About":""}${l&&p?" + ":""}${p?"Contact":""}${!l&&!p?"Not found":""}`));let d=!1,v="";for(let k of He){let C=e(k).first();if(C.length){d=!0,v=C.attr("datetime")||C.attr("content")||C.text().trim();break}}o.push(f("Publication Date",d?8:0,8,d?v:"Not found"));let x=Ze(t.$),w=0;x.ageInMonths!==null&&(x.ageInMonths<=6?w=12:x.ageInMonths<=12?w=9:x.ageInMonths<=24?w=5:w=2,x.hasModifiedDate&&w<12&&(w=Math.min(w+2,12))),o.push(f("Content Freshness",w,12,x.ageInMonths!==null?`${x.ageInMonths} months old${x.hasModifiedDate?", modified date present":""}`:"No parseable date found")),s.freshness=x;let y=e('script[type="application/ld+json"]'),b=[];y.each((k,C)=>{try{let z=JSON.parse(e(C).html()||"{}");z["@type"]&&b.push(z["@type"])}catch (e6){}});let A=["og:title","og:description","og:image","og:type"].filter(k=>e(`meta[property="${k}"]`).length>0),T=e('link[rel="canonical"]').attr("href"),$=0;b.length>0&&($+=4),A.length>=3?$+=4:A.length>0&&($+=2),T&&($+=4),s.structuredDataTypes=b,o.push(f("Structured Data",$,12,`${b.length>0?b.join(", "):"No JSON-LD"}, ${A.length}/4 OG tags${T?", canonical":""}`));let U=Ve(t.$),R=et(U),W=R.totalTypes===0?0:R.avgCompleteness>=.8?10:R.avgCompleteness>=.5?7:R.avgCompleteness>0?4:0;o.push(f("Schema Completeness",W,10,R.totalTypes>0?`${R.totalTypes} schema types, ${Math.round(R.avgCompleteness*100)}% complete`:"No recognized JSON-LD schemas found",R.totalTypes===0?"neutral":void 0)),s.schemaCompleteness=R;let M=Ke(t.$),N=Xe(t.$,t.title,M);return o.push(f("Entity Consistency",N.score,10,M?`"${M}" found in ${N.surfacesFound}/${N.surfacesChecked} surfaces`:"No identifiable entity name",M?void 0:"neutral")),s.entityConsistency={entityName:M||null,surfacesFound:N.surfacesFound,surfacesChecked:N.surfacesChecked},{category:{name:I.authorityContext,key:"authorityContext",score:P(o),maxScore:O(o),factors:o},rawData:s}}function Xt(t){let e=[],o=null;for(let s of t.split(`
|
|
2
|
+
`)){let r=s.split("#")[0].trim();if(!r){o=null;continue}let n=r.indexOf(":");if(n===-1)continue;let a=r.slice(0,n).trim().toLowerCase(),i=r.slice(n+1).trim();a==="user-agent"?(o||(o={agents:[],rules:[]},e.push(o)),o.agents.push(i.toLowerCase())):(a==="disallow"||a==="allow")&&o&&o.rules.push({type:a,path:i})}return e}function Zt(t,e){let o=[],s=[];for(let r of t)r.agents.includes(e)?o.push(...r.rules):r.agents.includes("*")&&s.push(...r.rules);return{specific:o,wildcard:s}}function eo(t,e){let o=-1,s=!1;for(let r of t){let n=r.path;!n||!e.startsWith(n)||(n.length>o?(o=n.length,s=r.type==="disallow"):n.length===o&&r.type==="allow"&&(s=!1))}return o>=0&&s}function to(t){return t.filter(e=>e.type==="disallow"&&e.path&&e.path!=="/").map(e=>e.path)}function ot(t){if(!t)return{allowed:[],blocked:[],unknown:[...ue]};let e=Xt(t),o=[],s=[],r=[],n=[];for(let a of ue){let i=a.toLowerCase(),{specific:c,wildcard:l}=Zt(e,i),p=c.length>0?c:l;if(p.length===0){r.push(a);continue}if(eo(p,"/"))s.push(a);else{o.push(a);let d=to(p);for(let v of d){let x=`${a}: ${v}`;n.includes(x)||n.push(x)}}}return{allowed:o,blocked:s,unknown:r,...n.length>0&&{partiallyBlocked:n}}}function st(t,e,o){let s=[],r={},n=e.statusCode===200?12:e.statusCode<400?8:0;s.push(f("Fetch Success",n,12,`HTTP ${e.statusCode} in ${e.fetchTimeMs}ms`));let a=t.stats.rawByteLength>0?t.stats.cleanTextLength/t.stats.rawByteLength:0,i=a>=.05&&a<=.15?12:a>.15?10:a>=.01?8:2;s.push(f("Text Extraction Quality",i,12,`${(a*100).toFixed(1)}% content ratio`));let c=t.stats.boilerplateRatio,l=E(1-c,[[.7,12],[.5,9],[.3,6],[0,2]]);s.push(f("Boilerplate Ratio",l,12,`${(c*100).toFixed(0)}% boilerplate`));let p=t.stats.wordCount,h=p>=300&&p<=3e3?12:p>3e3?10:p>=100?8:2;if(s.push(f("Word Count Adequacy",h,12,`${p} words`)),o){let b=ot(o.robotsTxt),m=b.blocked.length,A=m===0?10:m<=2?6:m<=4?3:0;s.push(f("AI Crawler Access",A,10,m===0?"All major AI crawlers allowed":`${b.blocked.join(", ")} blocked in robots.txt`)),r.crawlerAccess=b,r.llmsTxt={llmsTxtExists:o.llmsTxtExists,llmsFullTxtExists:o.llmsFullTxtExists};let T=o.llmsTxtExists,$=o.llmsFullTxtExists,U=T&&$?6:T||$?4:0;s.push(f("LLMs.txt Presence",U,6,T&&$?"llms.txt + llms-full.txt found":T?"llms.txt found":$?"llms-full.txt found":"Not found",!T&&!$?"neutral":void 0))}let d=t.stats.imageCount,v=t.stats.imagesWithAlt,x=t.$("figure figcaption").length,w=d>0?v/d:0,y=0;return d>0&&(w>=.9?y+=5:w>=.5?y+=3:y+=1,x>0&&(y+=3)),s.push(f("Image Accessibility",y,8,d>0?`${v}/${d} images have alt text${x>0?`, ${x} figcaptions`:""}`:"No images found",d===0?"neutral":void 0)),r.imageAccessibility={imageCount:d,imagesWithAlt:v,figcaptionCount:x},{category:{name:I.contentExtractability,key:"contentExtractability",score:P(s),maxScore:O(s),factors:s},rawData:r}}function rt(t){let e=t.$,o=[],s=t.stats.h1Count,r=t.stats.h2Count,n=t.stats.h3Count,a=0;s===1?a+=4:s>0&&(a+=2),r>=2?a+=4:r>0&&(a+=2),n>0&&(a+=3),o.push(f("Heading Hierarchy",a,11,`${s} H1, ${r} H2, ${n} H3`));let i=t.stats.listItemCount,c=E(i,[[10,11],[5,8],[1,4],[0,0]]);o.push(f("Lists Presence",c,11,`${i} list items`));let l=t.stats.tableCount,p=l>=2?8:l>=1?5:0;o.push(f("Tables Presence",p,8,`${l} table(s)`,l===0?"neutral":void 0));let h=t.stats.paragraphCount,d=h>0?Math.round(t.stats.wordCount/h):0,v=d>=30&&d<=150?11:d>0&&d<200?7:2;o.push(f("Paragraph Structure",v,11,`${h} paragraphs, avg ${d} words`));let x=e("strong, b").length>0,w=h>0?t.stats.headingCount/h:0,y=0;x&&(y+=4),d<=150&&(y+=4),w>=.1&&(y+=3),o.push(f("Scannability",y,11,`${x?"Bold text found":"No bold text"}, ${w.toFixed(2)} heading ratio`));let b=Je(t.$),m=0;return b.sectionCount===0?m=0:b.avgWordsPerSection>=120&&b.avgWordsPerSection<=180?m=12:b.avgWordsPerSection>=80&&b.avgWordsPerSection<=250?m=8:b.avgWordsPerSection>0&&(m=4),o.push(f("Section Length",m,12,b.sectionCount>0?`${b.sectionCount} sections, avg ${b.avgWordsPerSection} words`:"No headed sections found",b.sectionCount===0?"neutral":void 0)),{category:{name:I.contentStructure,key:"contentStructure",score:P(o),maxScore:O(o),factors:o},rawData:{sectionLengths:b}}}function nt(t,e){let o=t.cleanText,s=[],r=_nullishCoalesce(e, () => (G(o))),n=r.people.length+r.organizations.length+r.places.length+r.topics.length,a=E(n,[[9,20],[4,14],[1,7],[0,0]]);s.push(f("Entity Richness",a,20,`${n} entities (${r.people.length} people, ${r.organizations.length} orgs, ${r.places.length} places)`,n===0?"neutral":void 0));let i=t.title.toLowerCase().split(/\s+/).filter(m=>m.length>3),l=t.$("h1").first().text().toLowerCase().split(/\s+/).filter(m=>m.length>3),p=[...new Set([...i,...l])],h=r.topics.map(m=>m.toLowerCase()),d=0;for(let m of p)(h.some(A=>A.includes(m))||o.toLowerCase().split(m).length>3)&&d++;let v=p.length>0?d/p.length:0,x=p.length===0?0:v>=.5?25:v>0?15:0;s.push(f("Topic Consistency",x,25,`${d}/${p.length} title keywords align with content topics`,p.length===0?"neutral":void 0));let w=Y(o),y=w>0?n/w*100:0,b=y>=2&&y<=8?15:y>=1||y>8?10:3;return s.push(f("Entity Density",b,15,`${y.toFixed(1)} entities per 100 words`)),{category:{name:I.entityClarity,key:"entityClarity",score:P(s),maxScore:O(s),factors:s},rawData:{entities:r}}}function at(t,e){let o=t.$,s=t.cleanText,r=[],{numberCount:n=0}=_nullishCoalesce(e, () => (G(s))),a=t.externalLinks,i=E(a.length,[[6,13],[3,10],[1,6],[0,0]]);r.push(f("External References",i,13,`${a.length} external links`));let c=F(s,Le),l=o("blockquote, cite, q").length,p=c+l,h=E(p,[[6,13],[3,9],[1,5],[0,0]]);r.push(f("Citation Patterns",h,13,`${c} citation indicators, ${l} quote elements`));let d=F(s,Me),v=d+n,x=E(v,[[9,13],[4,9],[1,5],[0,0]]);r.push(f("Numeric Claims",x,13,`${d} statistical references, ${n} numeric values`));let w=F(s,De),y=E(w,[[5,11],[2,8],[1,4],[0,0]]);r.push(f("Attribution Indicators",y,11,`${w} attribution patterns`));let b=F(s,We),m=o("blockquote").filter(($,U)=>o(U).find("cite, footer, figcaption").length>0).length,A=b+m,T=E(A,[[4,10],[2,7],[1,4],[0,0]]);return r.push(f("Quoted Attribution",T,10,`${A} attributed quotes`,A===0?"neutral":void 0)),{category:{name:I.groundingSignals,key:"groundingSignals",score:P(r),maxScore:O(r),factors:r},rawData:{externalLinks:a.slice(0,10)}}}function it(t){let e=t.cleanText,o=[],s=pe(e),r=s>=12&&s<=22?15:s>=8&&s<30?10:s>0?5:0;o.push(f("Sentence Length",r,15,`Avg ${s} words/sentence`));let n=ce(e),a=n>=60&&n<=70?15:n>70?13:n>=50?10:n>=30?6:3;o.push(f("Readability",a,15,`Flesch Reading Ease: ${n.toFixed(1)}`));let i=Y(e),c=le(e),l=i>0?c/i:0,p=l<=.02?15:l<=.05?12:l<=.1?8:3;o.push(f("Jargon Density",p,15,`${(l*100).toFixed(1)}% complex words`));let h=ae(e,_e),d=E(h,[[10,15],[5,11],[2,7],[1,3],[0,0]]);return o.push(f("Transition Usage",d,15,`${h} transition types found`)),{category:{name:I.readabilityForCompression,key:"readabilityForCompression",score:P(o),maxScore:O(o),factors:o},rawData:{avgSentenceLength:s,readabilityScore:n}}}function ct(t,e,o){let s=G(t.cleanText),r=st(t,e,o),n=rt(t),a=Qe(t,s),i=nt(t,s),c=at(t,s),l=tt(t),p=it(t);return{categories:{contentExtractability:r.category,contentStructure:n.category,answerability:a.category,entityClarity:i.category,groundingSignals:c.category,authorityContext:l.category,readabilityForCompression:p.category},rawData:{title:t.title,metaDescription:t.metaDescription,wordCount:t.stats.wordCount,...r.rawData,...n.rawData,...a.rawData,...i.rawData,...c.rawData,...l.rawData,...p.rawData}}}var _cheerio = require('cheerio'); var K = _interopRequireWildcard(_cheerio);var oo=["script","style","noscript","svg","iframe","nav","header","footer","aside",'[role="navigation"]','[role="banner"]','[role="contentinfo"]',".sidebar","#sidebar",".cookie-banner","#cookie-consent",".cookie-notice",".nav",".navbar",".footer",".header",".menu",".ad",".ads",".advertisement",'[class*="cookie"]','[class*="consent"]','[class*="popup"]','[class*="modal"]'];function lt(t){for(let e of oo)t(e).remove()}function so(t){return t.replace(/\s+/g," ").trim()}var ro="p,div,td,th,li,h1,h2,h3,h4,h5,h6,dt,dd,br,blockquote,section,article";function pt(t){return t(ro).each((e,o)=>{t(o).append(" ")}),so(t("body").text())}function ut(t,e){let o=K.load(t),s=o("title").text().trim()||_optionalChain([o, 'call', _9 => _9('meta[property="og:title"]'), 'access', _10 => _10.attr, 'call', _11 => _11("content"), 'optionalAccess', _12 => _12.trim, 'call', _13 => _13()])||"",r=_optionalChain([o, 'call', _14 => _14('meta[name="description"]'), 'access', _15 => _15.attr, 'call', _16 => _16("content"), 'optionalAccess', _17 => _17.trim, 'call', _18 => _18()])||_optionalChain([o, 'call', _19 => _19('meta[property="og:description"]'), 'access', _20 => _20.attr, 'call', _21 => _21("content"), 'optionalAccess', _22 => _22.trim, 'call', _23 => _23()])||"",n=K.load(t);n("script, style, noscript").remove();let a=n("body").text().replace(/\s+/g," ").trim(),i=Buffer.byteLength(t,"utf-8"),c=o("h1").length,l=o("h2").length,p=o("h3").length,h=c+l+p+o("h4, h5, h6").length,d=o("a[href]").length,v=o("img").length,x=o("ul, ol").length,w=o("li").length,y=o("table").length,b=o("p").length,m=new Set(["image","photo","logo","icon","picture","img","graphic","thumbnail"]),A=0;o("img").each((C,z)=>{let q=_nullishCoalesce(_optionalChain([o, 'call', _24 => _24(z), 'access', _25 => _25.attr, 'call', _26 => _26("alt"), 'optionalAccess', _27 => _27.trim, 'call', _28 => _28()]), () => (""));q.split(/\s+/).filter(Jt=>Jt.length>0).length>1&&q.length<200&&!m.has(q.toLowerCase())&&A++});let T=se(e),$=[];o('a[href^="http"]').each((C,z)=>{let q=o(z).attr("href");try{se(q)!==T&&$.push({url:q,text:o(z).text().trim().substring(0,50)})}catch (e7){}});let U=$.length,R=K.load(t);lt(R);let W=pt(R),M=W.length,N=a.length>0?Math.max(0,Math.min(1,1-M/a.length)):0,k={wordCount:Y(W),sentenceCount:Oe(W),paragraphCount:b,headingCount:h,h1Count:c,h2Count:l,h3Count:p,linkCount:d,externalLinkCount:U,imageCount:v,imagesWithAlt:A,listCount:x,listItemCount:w,tableCount:y,boilerplateRatio:N,rawByteLength:i,cleanTextLength:M};return{url:e,html:t,cleanText:W,title:s,metaDescription:r,stats:k,$:o,externalLinks:$}}var _zod = require('zod');var dt=_zod.z.object({url:_zod.z.url(),timeout:_zod.z.number().positive().default(45e3),userAgent:_zod.z.string().default(`AISEOAudit/${H}`)}),zr=_zod.z.object({url:_zod.z.string(),finalUrl:_zod.z.string(),statusCode:_zod.z.number(),contentType:_zod.z.string(),html:_zod.z.string(),byteLength:_zod.z.number(),fetchTimeMs:_zod.z.number(),redirected:_zod.z.boolean()});async function X(t){let e=dt.parse(t),o=Date.now(),s=await B({url:e.url,timeout:e.timeout,userAgent:e.userAgent}),r=Date.now()-o,n=s.data,a=s.finalUrl||e.url,i=s.headers["content-type"]||"unknown";return{url:e.url,finalUrl:a,statusCode:s.status,contentType:i,html:n,byteLength:Buffer.byteLength(n,"utf-8"),fetchTimeMs:r,redirected:a!==e.url}}var mt=`<!-- Before: prose enumeration -->
|
|
3
|
+
<p>We offer design, development, and strategy services.</p>
|
|
4
|
+
|
|
5
|
+
<!-- After: unordered list -->
|
|
6
|
+
<ul>
|
|
7
|
+
<li>Design \u2014 UI/UX and brand identity</li>
|
|
8
|
+
<li>Development \u2014 web and mobile engineering</li>
|
|
9
|
+
<li>Strategy \u2014 AI readiness and growth planning</li>
|
|
10
|
+
</ul>
|
|
11
|
+
|
|
12
|
+
<!-- Ordered list for sequential steps -->
|
|
13
|
+
<ol>
|
|
14
|
+
<li>Submit your project brief</li>
|
|
15
|
+
<li>Schedule a discovery call</li>
|
|
16
|
+
<li>Receive your proposal within 48 hours</li>
|
|
17
|
+
</ol>`,ht=`<table>
|
|
18
|
+
<caption>Plan feature comparison</caption>
|
|
19
|
+
<thead>
|
|
20
|
+
<tr>
|
|
21
|
+
<th>Feature</th>
|
|
22
|
+
<th>Starter</th>
|
|
23
|
+
<th>Pro</th>
|
|
24
|
+
<th>Enterprise</th>
|
|
25
|
+
</tr>
|
|
26
|
+
</thead>
|
|
27
|
+
<tbody>
|
|
28
|
+
<tr>
|
|
29
|
+
<td>Users</td>
|
|
30
|
+
<td>1</td>
|
|
31
|
+
<td>10</td>
|
|
32
|
+
<td>Unlimited</td>
|
|
33
|
+
</tr>
|
|
34
|
+
<tr>
|
|
35
|
+
<td>Storage</td>
|
|
36
|
+
<td>10 GB</td>
|
|
37
|
+
<td>100 GB</td>
|
|
38
|
+
<td>1 TB</td>
|
|
39
|
+
</tr>
|
|
40
|
+
</tbody>
|
|
41
|
+
</table>`,gt=`<!-- Before: buried answer -->
|
|
42
|
+
<p>There are many factors involved, and while it depends on the situation,
|
|
43
|
+
in most cases companies that invest in AI SEO tend to see better visibility
|
|
44
|
+
in AI-generated answers.</p>
|
|
45
|
+
|
|
46
|
+
<!-- After: direct answer first -->
|
|
47
|
+
<p>Companies that invest in AI SEO see better visibility in AI-generated answers.
|
|
48
|
+
Results depend on content quality, structured data completeness, and how well
|
|
49
|
+
headings are framed as questions.</p>`,ft=`<h2>Key Takeaways</h2>
|
|
50
|
+
<ul>
|
|
51
|
+
<li>AI SEO focuses on being cited in generated answers, not ranked in link lists.</li>
|
|
52
|
+
<li>Structured data, answer capsules, and clear entity attribution are the highest-impact factors.</li>
|
|
53
|
+
<li>Content freshness acts as a hard gate \u2014 AI engines strongly prefer content under 12 months old.</li>
|
|
54
|
+
</ul>
|
|
55
|
+
|
|
56
|
+
<h2>Next Steps</h2>
|
|
57
|
+
<p>Run an audit on your top pages to identify your highest-priority improvements.</p>`,yt=`<!-- Before: unattributed claim -->
|
|
58
|
+
<p>72% of AI-cited content uses question-framed headings.</p>
|
|
59
|
+
|
|
60
|
+
<!-- After: attributed with a link -->
|
|
61
|
+
<p>According to <a href="https://arxiv.org/abs/2311.09735">Princeton's GEO research</a>,
|
|
62
|
+
72% of AI-cited content uses question-framed headings.</p>`,xt=`<!-- In-text citation with marker -->
|
|
63
|
+
<p>AI engines prioritize structured content by a factor of 3x <a href="#ref-1">[1]</a>.</p>
|
|
64
|
+
|
|
65
|
+
<!-- Cited title -->
|
|
66
|
+
<p>As described in <cite>Generative Engine Optimization</cite>, answer density is key.</p>
|
|
67
|
+
|
|
68
|
+
<!-- References section -->
|
|
69
|
+
<section>
|
|
70
|
+
<h2>References</h2>
|
|
71
|
+
<ol>
|
|
72
|
+
<li id="ref-1">
|
|
73
|
+
<cite><a href="https://arxiv.org/abs/2311.09735">Generative Engine Optimization (GEO)</a></cite>
|
|
74
|
+
\u2014 Aggarwal et al., Princeton University, 2023
|
|
75
|
+
</li>
|
|
76
|
+
</ol>
|
|
77
|
+
</section>`,bt=`<blockquote>
|
|
78
|
+
<p>"Structured content with clear attribution is 3x more likely to be cited
|
|
79
|
+
by generative AI engines than unstructured prose."</p>
|
|
80
|
+
<footer>
|
|
81
|
+
\u2014 <cite>Dr. Jane Smith, AI Research Lead,
|
|
82
|
+
<a href="https://example.edu">Princeton University</a></cite>
|
|
83
|
+
</footer>
|
|
84
|
+
</blockquote>`,wt=`<!-- Before: abrupt transitions -->
|
|
85
|
+
<p>AI engines extract structured content. Many pages have no structure.</p>
|
|
86
|
+
<p>Adding headings and lists improves your score.</p>
|
|
87
|
+
|
|
88
|
+
<!-- After: logical flow with transitions -->
|
|
89
|
+
<p>AI engines extract structured content. <strong>However</strong>, many pages
|
|
90
|
+
lack the organization needed for reliable extraction.</p>
|
|
91
|
+
<p><strong>Therefore</strong>, adding headings and lists directly improves
|
|
92
|
+
how AI engines process and cite your content.</p>`,St=`<!-- Before: jargon-heavy -->
|
|
93
|
+
<p>Our RAG-based LLM pipeline leverages semantic chunking and vector embeddings
|
|
94
|
+
to optimize retrieval latency for enterprise-scale deployments.</p>
|
|
95
|
+
|
|
96
|
+
<!-- After: jargon defined on first use -->
|
|
97
|
+
<p>Our AI pipeline uses Retrieval-Augmented Generation (RAG) \u2014 a technique that
|
|
98
|
+
combines a language model with a searchable knowledge base \u2014 to deliver fast,
|
|
99
|
+
accurate answers at enterprise scale.</p>`,vt=`<!-- In site navigation or footer -->
|
|
100
|
+
<nav aria-label="Company">
|
|
101
|
+
<a href="/about">About Us</a>
|
|
102
|
+
<a href="/contact">Contact</a>
|
|
103
|
+
</nav>
|
|
104
|
+
|
|
105
|
+
<!-- Optional: contactPoint in your Organization JSON-LD -->
|
|
106
|
+
"contactPoint": {
|
|
107
|
+
"@type": "ContactPoint",
|
|
108
|
+
"contactType": "customer support",
|
|
109
|
+
"url": "https://yoursite.com/contact"
|
|
110
|
+
}`,de=`<!-- Informational image with alt text -->
|
|
111
|
+
<img src="diagram.png" alt="Flowchart showing the three stages of AI content extraction">
|
|
112
|
+
|
|
113
|
+
<!-- Image with caption using figure/figcaption -->
|
|
114
|
+
<figure>
|
|
115
|
+
<img src="chart.png" alt="Bar chart comparing AI citation rates by content type">
|
|
116
|
+
<figcaption>AI engines cite structured content 3x more often than unstructured prose.</figcaption>
|
|
117
|
+
</figure>
|
|
118
|
+
|
|
119
|
+
<!-- Decorative image \u2014 empty alt tells screen readers to skip it -->
|
|
120
|
+
<img src="divider.png" alt="">`,At=`<!-- Before -->
|
|
121
|
+
<h2>Benefits of AI SEO</h2>
|
|
122
|
+
<p>There are many reasons companies are investing in AI SEO strategies today...</p>
|
|
123
|
+
|
|
124
|
+
<!-- After (answer capsule pattern) -->
|
|
125
|
+
<h2>What are the benefits of AI SEO?</h2>
|
|
126
|
+
<p>AI SEO increases your content's visibility in AI-generated answers, driving qualified traffic from ChatGPT, Claude, and Perplexity.</p>
|
|
127
|
+
<p>Companies investing in AI SEO see benefits across three areas...</p>`;function j(t){return()=>({text:t})}var Tt={"Fetch Success":j("Ensure the page returns HTTP 200 without excessive redirect chains. AI engines cannot extract content from pages that fail to load."),"Text Extraction Quality":j("Improve the ratio of meaningful text content to markup. Pages with very low text density are harder for AI engines to extract useful content from."),"Boilerplate Ratio":j("Reduce boilerplate content (navigation, footers, sidebars) relative to main content. Use semantic HTML elements like <main> and <article> to help engines isolate your content."),"Word Count Adequacy":t=>{let e=t.wordCount;return e<100?{text:`Your page has ${e} words, which is too thin for AI engines to reference. The ideal range is 300-3000 words.`}:e<300?{text:`Your page has ${e} words. AI engines prefer 300-3000 words for comprehensive coverage. Consider expanding your content.`}:{text:`Your page has ${e} words, which exceeds the ideal 300-3000 word range. Consider splitting into multiple focused pages.`}},"AI Crawler Access":t=>{let e=t.crawlerAccess;if(!e||e.blocked.length===0)return{text:"Ensure AI crawlers like GPTBot, ClaudeBot, and PerplexityBot are allowed in your robots.txt.",steps:["Check your robots.txt for Disallow rules targeting AI crawlers","Add explicit Allow rules for each AI crawler you want to reach your content"],learnMoreUrl:"https://developers.google.com/search/docs/crawling-indexing/robots/intro"};let o=e.blocked,s=o.join(", "),r=`# Add these rules to your robots.txt:
|
|
128
|
+
|
|
129
|
+
${o.map(n=>`User-agent: ${n}
|
|
130
|
+
Allow: /`).join(`
|
|
131
|
+
|
|
132
|
+
`)}`;if(e.allowed.length>0){let n=e.allowed.join(", ");return{text:`Your robots.txt is blocking ${s}. ${n} ${e.allowed.length===1?"is":"are"} allowed. Unblock all AI crawlers so your content can be discovered and cited.`,steps:["Open your robots.txt file (usually at the site root)",`Remove any Disallow rules for: ${s}`,"Add the Allow rules shown in the code example","Deploy and verify at yoursite.com/robots.txt"],codeExample:r,learnMoreUrl:"https://developers.google.com/search/docs/crawling-indexing/robots/intro"}}return{text:`Your robots.txt is blocking ${s}. Blocking these crawlers means your content cannot be discovered or cited by AI engines.`,steps:["Open your robots.txt file (usually at the site root)",`Remove any Disallow rules for: ${s}`,"Add the Allow rules shown in the code example","Deploy and verify at yoursite.com/robots.txt"],codeExample:r,learnMoreUrl:"https://developers.google.com/search/docs/crawling-indexing/robots/intro"}},"LLMs.txt Presence":t=>{let e=t.llmsTxt,o=t.title||"Your Site Name",s=t.metaDescription||"Brief description of your site",r=[];if(_optionalChain([e, 'optionalAccess', _29 => _29.llmsTxtExists])||r.push("llms.txt"),_optionalChain([e, 'optionalAccess', _30 => _30.llmsFullTxtExists])||r.push("llms-full.txt"),r.length===0)return{text:"Both llms.txt and llms-full.txt are present."};let a=!_optionalChain([e, 'optionalAccess', _31 => _31.llmsTxtExists])?`# llms.txt
|
|
133
|
+
|
|
134
|
+
# ${o}
|
|
135
|
+
|
|
136
|
+
> ${s}
|
|
137
|
+
|
|
138
|
+
## Docs
|
|
139
|
+
|
|
140
|
+
- [About](/about): Learn more about ${o}
|
|
141
|
+
- [Documentation](/docs): Technical documentation`:`# llms-full.txt
|
|
142
|
+
|
|
143
|
+
# ${o} \u2014 Full Documentation
|
|
144
|
+
|
|
145
|
+
> ${s}
|
|
146
|
+
|
|
147
|
+
This file provides comprehensive documentation for AI systems to understand and accurately reference ${o}.`,i=r[0];return _optionalChain([e, 'optionalAccess', _32 => _32.llmsTxtExists])&&!_optionalChain([e, 'optionalAccess', _33 => _33.llmsFullTxtExists])?{text:"You have llms.txt but are missing llms-full.txt. Adding llms-full.txt provides AI systems with a comprehensive version of your site documentation for deeper ingestion.",steps:["Create llms-full.txt at your domain root (e.g., yoursite.com/llms-full.txt)","Include your site's full documentation, purpose, key features, and FAQ","Deploy so the file is accessible via HTTP GET","Verify by visiting yoursite.com/llms-full.txt"],codeExample:a,learnMoreUrl:"https://llmstxt.org"}:!_optionalChain([e, 'optionalAccess', _34 => _34.llmsTxtExists])&&_optionalChain([e, 'optionalAccess', _35 => _35.llmsFullTxtExists])?{text:"You have llms-full.txt but are missing llms.txt. Adding llms.txt provides AI systems with a concise structured overview of your site's purpose and key pages.",steps:["Create llms.txt at your domain root (e.g., yoursite.com/llms.txt)","Include your site's purpose, key pages, and documentation links (see code example)","Deploy so the file is accessible via HTTP GET","Verify by visiting yoursite.com/llms.txt"],codeExample:a,learnMoreUrl:"https://llmstxt.org"}:{text:`Missing ${r.join(" and ")}. These files help AI systems understand and accurately cite your site.`,steps:[`Create ${i} at your domain root (e.g., yoursite.com/${i})`,"Fill in your site's purpose, key pages, and documentation links (see code example)","Deploy so the file is accessible via HTTP GET",`Verify by visiting yoursite.com/${i}`],codeExample:a,learnMoreUrl:"https://llmstxt.org"}},"Image Accessibility":t=>{let e=t.imageAccessibility,o=["Add a descriptive alt attribute to every <img> tag","Write alt text that describes what the image shows, not just its file name",'Leave alt empty (alt="") for purely decorative images',"Wrap images that need caption context in <figure> with a <figcaption>"];if(!e||e.imageCount===0)return{text:"Add descriptive alt text to all images and use <figure> with <figcaption> for semantic image context.",steps:o,codeExample:de};let s=e.imageCount-e.imagesWithAlt,r=Math.round(e.imagesWithAlt/e.imageCount*100),n=`${e.imagesWithAlt} of your ${e.imageCount} images have alt text (${r}%). `;return s>0&&(n+=`Add alt text to the remaining ${s} image${s===1?"":"s"}. `),e.figcaptionCount===0&&(n+="Consider using <figure> with <figcaption> for images that need descriptive context."),{text:n,steps:o,codeExample:de}},"Heading Hierarchy":t=>{let e=t.title||"Your Page Topic",o=e.split(" ").slice(-2).join(" ");return{text:"Use a clear H1 > H2 > H3 heading hierarchy. Headings serve as structural anchors that AI engines use to segment and reuse content.",steps:["Use exactly 1 H1 tag for the main page title","Use H2 tags for major sections (aim for 3+ sections)","Use H3 tags for subsections within each H2","Never skip levels (e.g., don't jump from H1 to H3)","Frame H2s as questions when possible for answer capsule compatibility"],codeExample:`<!-- Recommended heading structure -->
|
|
148
|
+
<h1>${e}</h1>
|
|
149
|
+
|
|
150
|
+
<h2>What is ${o}?</h2>
|
|
151
|
+
<p>Definition and overview...</p>
|
|
152
|
+
|
|
153
|
+
<h3>Key Features</h3>
|
|
154
|
+
<p>Details...</p>
|
|
155
|
+
|
|
156
|
+
<h2>Why Does ${o} Matter?</h2>
|
|
157
|
+
<p>Importance and context...</p>
|
|
158
|
+
|
|
159
|
+
<h2>How to Get Started</h2>
|
|
160
|
+
<p>Step-by-step guide...</p>`}},"Lists Presence":()=>({text:"Add bulleted or numbered lists to organize information. Lists are easily extracted and reused by AI engines.",steps:["Identify prose that enumerates 3 or more items in a sentence","Convert those sentences into <ul> or <ol> list elements","Use <ol> for sequential steps and <ul> for unordered collections","Keep list items parallel \u2014 each starting with the same grammatical form"],codeExample:mt}),"Tables Presence":()=>({text:"Consider adding data tables for comparative or structured data. Tables are highly parseable by AI engines.",steps:["Identify any comparisons, pricing tiers, specs, or feature matrices in your content","Structure them as HTML <table> elements with a <thead> and <tbody>","Add a <caption> element describing what the table shows","Ensure every column has a clear <th> header so AI engines can map values to labels"],codeExample:ht}),"Paragraph Structure":j("Keep paragraphs between 30-150 words for optimal readability and extractability."),Scannability:j("Use bold text, short paragraphs, and frequent headings to improve scannability for both humans and AI."),"Section Length":t=>{let e=t.sectionLengths;if(!e||e.sectionCount===0)return{text:"Add headings to create distinct sections. Each headed section should be a self-contained unit that an AI engine could extract and reuse."};let o=Math.round(e.avgWordsPerSection);return o<120?{text:`Your sections average ${o} words. The citation sweet spot is 120-180 words. Consider expanding sections with more detail rather than splitting into many short fragments.`}:{text:`Your sections average ${o} words. The citation sweet spot is 120-180 words. Consider adding more subheadings to break up long sections into self-contained units.`}},"Definition Patterns":t=>{let o=_nullishCoalesce(_optionalChain([t, 'access', _36 => _36.entities, 'optionalAccess', _37 => _37.topics, 'optionalAccess', _38 => _38[0]]), () => ("AI SEO")),s=`<!-- Inline definition on first use -->
|
|
161
|
+
<p>${o} is defined as [your one-sentence definition here].</p>
|
|
162
|
+
|
|
163
|
+
<!-- Definition list for multiple terms -->
|
|
164
|
+
<dl>
|
|
165
|
+
<dt>${o}</dt>
|
|
166
|
+
<dd>[A clear, concise definition that AI engines can extract and reuse.]</dd>
|
|
167
|
+
|
|
168
|
+
<dt>[Second key term]</dt>
|
|
169
|
+
<dd>[The definition of your second most important concept.]</dd>
|
|
170
|
+
</dl>`;return{text:'Define key terms and concepts clearly (e.g., "X is defined as..." or "X refers to..."). Clear definitions are directly reusable by AI engines.',steps:["Identify the 3 to 5 key terms central to your page topic","Add a one-sentence definition for each using the 'X is' or 'X refers to' pattern","Place each definition early in the section that first uses the term","Use a <dl> definition list when the page covers many terms"],codeExample:s}},"Direct Answer Statements":()=>({text:"Start key sentences with direct statements that could serve as standalone answers.",steps:["Find paragraphs where the main point is buried after qualifications or context","Move the core assertion to the first sentence of the paragraph","Write opening sentences so they can stand alone as a complete answer","Follow the direct statement with supporting detail, examples, and caveats"],codeExample:gt}),"Answer Capsules":t=>{let e=t.answerCapsules,o=_optionalChain([t, 'access', _39 => _39.questionsFound, 'optionalAccess', _40 => _40[0]]),s=["Rewrite H2 headings as questions your audience would ask an AI (e.g., 'Benefits of X' \u2192 'What are the benefits of X?')","Place a 1-2 sentence direct answer (under 200 characters) as the first paragraph after each H2","Start the answer with a definitive statement, not a qualifier","Follow the capsule with detailed supporting content"],r=o?`<!-- Before -->
|
|
171
|
+
<h2>${o.replace(/\?$/,"").replace(/^(what|how|why|when|where|who)\s+/i,a=>a.charAt(0).toUpperCase()+a.slice(1))}</h2>
|
|
172
|
+
<p>There are many reasons to consider this topic today...</p>
|
|
173
|
+
|
|
174
|
+
<!-- After (answer capsule pattern) -->
|
|
175
|
+
<h2>${o.endsWith("?")?o:`${o}?`}</h2>
|
|
176
|
+
<p>[Your direct, one-sentence answer here \u2014 under 200 characters.]</p>
|
|
177
|
+
<p>[Supporting detail and context follows...]</p>`:At;if(!e||e.total===0)return{text:"Frame your H2 headings as questions and place a concise answer (under 200 characters) in the first sentence. 72% of AI-cited content uses this pattern.",steps:s,codeExample:r};let n=e.total-e.withCapsule;return{text:`${e.withCapsule} of your ${e.total} question-framed H2s have a concise answer capsule. Add a short, direct answer (under 200 characters) as the first sentence after the remaining ${n}. 72% of AI-cited content uses this pattern.`,steps:s,codeExample:r}},"Step-by-Step Content":j("Break down processes into clear, numbered steps. Step-by-step content is highly reusable by AI engines."),"Q/A Patterns":t=>{let e=t.questionsFound;return!e||e.length===0?{text:'Include and answer common questions your audience might have. Structure content to directly answer "what is", "how to" style queries.'}:{text:`Found ${e.length} question${e.length===1?"":"s"} in your content. Add more question-and-answer patterns to cover the queries your audience asks AI engines.`}},"Summary/Conclusion":()=>({text:"Add a conclusion section with key takeaways or a summary. This helps AI engines quickly extract the main points.",steps:["Add an H2 heading at the end of the page: 'Summary', 'Key Takeaways', or 'Conclusion'","List 3 to 5 bullet points covering the most important points from the page","Keep each bullet to one sentence \u2014 conclusion bullets are the most-cited part of a page","Optionally follow the summary with a 'Next Steps' or 'Learn More' section"],codeExample:ft}),"Entity Richness":t=>{let e=t.entities,o=9,s=["Name the key people, organizations, and places relevant to your topic","Link people and organizations to authoritative sources like Wikipedia or official sites","Add context for each entity: their role, location, or relevance to the topic",`Aim for ${o} or more distinct named entities per page`];if(!e)return{text:"Reference relevant experts, organizations, and places in your field. Named entities help AI engines understand context.",steps:s};let r=e.people.length+e.organizations.length+e.places.length+e.topics.length,n=[];return e.people.length>0&&n.push(`${e.people.length} people`),e.organizations.length>0&&n.push(`${e.organizations.length} organizations`),e.places.length>0&&n.push(`${e.places.length} places`),e.topics.length>0&&n.push(`${e.topics.length} topics`),r===0?{text:"No named entities were detected. Reference specific people, organizations, and places to help AI engines understand what your content is about.",steps:s}:{text:`Found ${r} unique entities (${n.join(", ")}). AI engines perform best with ${o}+ distinct entities. Add more specific names, organizations, and places relevant to your topic.`,steps:s}},"Topic Consistency":j("Align your main topics with your title and headings. Topic consistency helps AI engines understand what your page is about."),"Entity Density":j("Ensure a balanced density of named entities (2-8 per 100 words). Too few makes content vague; too many makes it hard to parse."),"External References":t=>{let e=t.externalLinks,o=_nullishCoalesce(_optionalChain([e, 'optionalAccess', _41 => _41.length]), () => (0)),s=6,r=["Identify factual claims that can be supported by an external source","Find authoritative sources: research papers, industry reports, official documentation","Wrap the linked text in a meaningful anchor \u2014 describe what you are linking to, not 'click here'",`Aim for ${s} or more external links per page`],n=_optionalChain([e, 'optionalAccess', _42 => _42[0]]),a=n?`<!-- Anchor an external reference to the claim it supports -->
|
|
178
|
+
<p>
|
|
179
|
+
As referenced in <a href="${n.url}"
|
|
180
|
+
rel="noopener">${n.text||"this source"}</a>, [your claim here].
|
|
181
|
+
</p>
|
|
182
|
+
|
|
183
|
+
<!-- Add more references using the same pattern -->
|
|
184
|
+
<p>
|
|
185
|
+
According to <a href="[source-url]" rel="noopener">[Source Name]</a>,
|
|
186
|
+
[another claim supported by evidence].
|
|
187
|
+
</p>`:`<!-- Anchor an external reference to the claim it supports -->
|
|
188
|
+
<p>
|
|
189
|
+
Structured content is cited 3x more often by AI engines,
|
|
190
|
+
according to <a href="https://arxiv.org/abs/2311.09735"
|
|
191
|
+
rel="noopener">Princeton's GEO research</a>.
|
|
192
|
+
</p>`;return o===0?{text:"Add links to reputable external sources to ground your claims. AI engines use external references to verify and attribute information.",steps:r,codeExample:a}:{text:`Found ${o} external link${o===1?"":"s"}. AI engines prefer content with ${s}+ external references. Add more links to authoritative sources that support your claims.`,steps:r,codeExample:a}},"Citation Patterns":()=>({text:'Use formal citation patterns (e.g., [1], "according to") when referencing sources.',steps:["Add in-text citation markers like [1] or (Author, Year) after specific claims","Include a 'References' or 'Sources' section at the bottom of the page","Use <cite> elements around titles of books, articles, or research papers","Link each citation marker to its corresponding reference entry"],codeExample:xt}),"Numeric Claims":j("Include relevant statistics and data points to support your content with verifiable claims."),"Attribution Indicators":()=>({text:'Attribute claims to specific sources or experts. Phrases like "according to" help AI engines trace information.',steps:["Identify factual claims that currently have no source","Prepend 'According to [Source]' or 'Per [Organization]' before each claim","Link the source name to its original URL so AI engines can follow the reference","Add a citation marker (e.g., [1]) for formal references tied to a sources section"],codeExample:yt}),"Quoted Attribution":()=>({text:'Add expert quotes with clear attribution. Use patterns like "Quote text" \u2014 Expert Name, or "Quote text," said Expert Name. Research shows quotation addition increased AI visibility by 30-40%.',steps:["Find a relevant quote from an expert, publication, or research paper","Wrap it in a <blockquote> with a <footer> containing a <cite> attribution","Include the expert's full name, title, and organization","Link the attribution to the original source where possible"],codeExample:bt,learnMoreUrl:"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote"}),"Author Attribution":t=>{let e=_optionalChain([t, 'access', _43 => _43.entities, 'optionalAccess', _44 => _44.people, 'optionalAccess', _45 => _45[0]])||"Author Name",o=e.toLowerCase().replace(/\s+/g,"-");return{text:"Add visible author information with a byline to establish content credibility and enable AI attribution.",steps:["Add a visible byline near the top of the article (after the H1)",'Link the author name to an about/bio page using rel="author"',"Add author information to your JSON-LD schema (see code example)"],codeExample:`<!-- Add a visible byline -->
|
|
193
|
+
<p class="byline">By <a href="/about/${o}" rel="author">${e}</a></p>
|
|
194
|
+
|
|
195
|
+
<!-- Add to your JSON-LD schema -->
|
|
196
|
+
"author": {
|
|
197
|
+
"@type": "Person",
|
|
198
|
+
"name": "${e}",
|
|
199
|
+
"url": "https://yoursite.com/about/${o}"
|
|
200
|
+
}`,learnMoreUrl:"https://schema.org/author"}},"Organization Identity":t=>{let e=_nullishCoalesce(_optionalChain([t, 'access', _46 => _46.entities, 'optionalAccess', _47 => _47.organizations, 'optionalAccess', _48 => _48[0]]), () => ("Your Organization"));return{text:"Add Organization structured data or og:site_name to help engines identify the source.",steps:["Add an og:site_name meta tag to every page's <head>","Add an Organization JSON-LD block to your site's global <head>","Ensure the organization name is identical across JSON-LD, og:site_name, and visible page content"],codeExample:`<!-- og:site_name in <head> -->
|
|
201
|
+
<meta property="og:site_name" content="${e}">
|
|
202
|
+
|
|
203
|
+
<!-- Organization JSON-LD (add to global site header) -->
|
|
204
|
+
<script type="application/ld+json">
|
|
205
|
+
{
|
|
206
|
+
"@context": "https://schema.org",
|
|
207
|
+
"@type": "Organization",
|
|
208
|
+
"name": "${e}",
|
|
209
|
+
"url": "https://yoursite.com",
|
|
210
|
+
"logo": "https://yoursite.com/logo.png",
|
|
211
|
+
"sameAs": [
|
|
212
|
+
"https://twitter.com/yourhandle",
|
|
213
|
+
"https://linkedin.com/company/yourcompany"
|
|
214
|
+
]
|
|
215
|
+
}
|
|
216
|
+
</script>`,learnMoreUrl:"https://schema.org/Organization"}},"Contact/About Links":()=>({text:"Link to About and Contact pages to establish credibility and enable source verification.",steps:["Add links to your About and Contact pages in the site navigation","Include them in the footer of every page","Ensure the links are reachable via plain anchor tags \u2014 not JavaScript-only interactions"],codeExample:vt}),"Publication Date":()=>{let t=new Date().toISOString().split("T")[0];return{text:"Include publication and last-updated dates using proper HTML5 time elements or schema markup.",steps:["Add a visible publication date near the article title or byline","Wrap the date in a <time> element with a machine-readable datetime attribute","Add datePublished and dateModified to your JSON-LD schema"],codeExample:`<!-- Visible dates with <time> elements -->
|
|
217
|
+
<p>Published: <time datetime="${t}" itemprop="datePublished">${t}</time></p>
|
|
218
|
+
<p>Updated: <time datetime="${t}" itemprop="dateModified">${t}</time></p>
|
|
219
|
+
|
|
220
|
+
<!-- In your JSON-LD schema -->
|
|
221
|
+
"datePublished": "${t}",
|
|
222
|
+
"dateModified": "${t}"`,learnMoreUrl:"https://schema.org/datePublished"}},"Content Freshness":t=>{let e=t.freshness,o=new Date().toISOString().split("T")[0],s=`<!-- Add/update in your HTML -->
|
|
223
|
+
<time datetime="${o}" itemprop="dateModified">${o}</time>
|
|
224
|
+
|
|
225
|
+
<!-- Add/update in your JSON-LD -->
|
|
226
|
+
"dateModified": "${o}"`,r=["Review and update your content with current information","Update the dateModified in both visible HTML and JSON-LD schema (see code example)","Set up a recurring reminder to review content every 6 months"];if(!e||e.ageInMonths===null)return{text:"Add a publication or modified date to your content. 65% of AI crawler hits target content less than 1 year old. Without a parseable date, AI engines may deprioritize your content.",steps:["Add a <time> element with a datetime attribute to your page","Add datePublished and dateModified to your JSON-LD schema",r[2]],codeExample:s};let n=Math.round(e.ageInMonths),a;return n>24?a=`Your content was last updated ${n} months ago. AI engines strongly prefer content less than 12 months old. Consider updating with current information and refreshing the modified date.`:n>12?a=`Your content was last updated ${n} months ago. 65% of AI crawler hits target content less than 1 year old. Refresh your content and update the modified date.`:e.hasModifiedDate?a="Update your content to include a recent publication or modified date. Content freshness acts as a hard gate for AI engine citations.":a="Your content has a publish date but no modified date. Adding a dateModified signal shows active maintenance and gives a freshness boost with AI engines.",{text:a,steps:r,codeExample:s}},"Structured Data":t=>{let e=t.structuredDataTypes;if(e&&e.length>0)return{text:`Found ${e.join(", ")} schema${e.length===1?"":"s"}. Ensure you also have Open Graph tags (og:title, og:description, og:image) and a canonical URL for complete structured data coverage.`,steps:["Verify all JSON-LD types have required properties (check Schema Completeness factor)","Add og:title, og:description, and og:image meta tags if missing",'Add a <link rel="canonical"> tag pointing to the preferred URL'],learnMoreUrl:"https://schema.org/docs/gs.html"};let o=t.title||"Your Page Title",s=t.metaDescription||"Your page description",r=_optionalChain([t, 'access', _49 => _49.questionsFound, 'optionalAccess', _50 => _50.length])?"FAQPage":"Article",n=new Date().toISOString().split("T")[0],a;return r==="FAQPage"&&_optionalChain([t, 'access', _51 => _51.questionsFound, 'optionalAccess', _52 => _52.length])?a=`<script type="application/ld+json">
|
|
227
|
+
{
|
|
228
|
+
"@context": "https://schema.org",
|
|
229
|
+
"@type": "FAQPage",
|
|
230
|
+
"mainEntity": [
|
|
231
|
+
${t.questionsFound.slice(0,3).map(l=>` {
|
|
232
|
+
"@type": "Question",
|
|
233
|
+
"name": "${l}",
|
|
234
|
+
"acceptedAnswer": {
|
|
235
|
+
"@type": "Answer",
|
|
236
|
+
"text": "Your answer here"
|
|
237
|
+
}
|
|
238
|
+
}`).join(`,
|
|
239
|
+
`)}
|
|
240
|
+
]
|
|
241
|
+
}
|
|
242
|
+
</script>`:a=`<script type="application/ld+json">
|
|
243
|
+
{
|
|
244
|
+
"@context": "https://schema.org",
|
|
245
|
+
"@type": "Article",
|
|
246
|
+
"headline": "${o}",
|
|
247
|
+
"description": "${s}",
|
|
248
|
+
"author": {
|
|
249
|
+
"@type": "Person",
|
|
250
|
+
"name": "Author Name"
|
|
251
|
+
},
|
|
252
|
+
"publisher": {
|
|
253
|
+
"@type": "Organization",
|
|
254
|
+
"name": "Your Organization"
|
|
255
|
+
},
|
|
256
|
+
"datePublished": "${n}",
|
|
257
|
+
"dateModified": "${n}"
|
|
258
|
+
}
|
|
259
|
+
</script>`,{text:"Add JSON-LD structured data and Open Graph tags to provide machine-readable context.",steps:[`Add a ${r} JSON-LD block to your <head> (see code example)`,"Fill in author, publisher, and date fields with real values","Add og:title, og:description, and og:image <meta> tags",'Add a <link rel="canonical"> pointing to the preferred URL',"Validate at https://search.google.com/test/rich-results"],codeExample:a,learnMoreUrl:"https://schema.org/docs/gs.html"}},"Schema Completeness":t=>{let e=t.schemaCompleteness;if(!e||e.details.length===0)return{text:"Add JSON-LD schema with all recommended properties. Complete schemas help AI engines attribute and trust your content.",learnMoreUrl:"https://schema.org/docs/gs.html"};let o=e.details.filter(c=>c.missing.length>0);if(o.length===0)return{text:"Ensure your JSON-LD schema types include all recommended properties for maximum AI engine trust."};let s=o.map(c=>`${c.type} is missing ${c.missing.join(", ")}`),r=o[0],n={headline:`"headline": "${t.title||"Your headline"}"`,author:'"author": { "@type": "Person", "name": "Author Name" }',datePublished:`"datePublished": "${new Date().toISOString().split("T")[0]}"`,dateModified:`"dateModified": "${new Date().toISOString().split("T")[0]}"`,description:`"description": "${t.metaDescription||"Your description"}"`,image:'"image": "https://yoursite.com/image.jpg"',publisher:'"publisher": { "@type": "Organization", "name": "Your Org" }',name:`"name": "${t.title||"Your Name"}"`,url:'"url": "https://yoursite.com"',mainEntity:'"mainEntity": []',step:'"step": [{ "@type": "HowToStep", "text": "Step 1..." }]',address:'"address": { "@type": "PostalAddress", "streetAddress": "..." }'},a=r.missing.map(c=>n[c]||`"${c}": "..."`),i=`// Add these properties to your existing ${r.type} schema:
|
|
260
|
+
{
|
|
261
|
+
${a.join(`,
|
|
262
|
+
`)}
|
|
263
|
+
}`;return{text:`Your ${s.join("; ")}. Adding these properties helps AI engines attribute and trust your content.`,steps:o.map(c=>`Add ${c.missing.join(", ")} to your ${c.type} schema`),codeExample:i,learnMoreUrl:`https://schema.org/${r.type}`}},"Entity Consistency":t=>{let e=t.entityConsistency;return!e||!e.entityName?{text:"Add a consistent brand or organization name across your page title, OG tags, JSON-LD schema, and footer. Consistent entity signals help AI engines confidently attribute content to your brand."}:{text:`"${e.entityName}" was found on ${e.surfacesFound} of ${e.surfacesChecked} page surfaces. Ensure it appears consistently in the page title, OG tags, schema, and footer for strong brand attribution.`}},"Sentence Length":t=>{let e=t.avgSentenceLength;if(e===void 0)return{text:"Aim for an average sentence length of 12-22 words for optimal readability and compressibility."};let o=Math.round(e);return o>22?{text:`Your average sentence is ${o} words. The ideal range for AI compression is 12-22 words. Break long sentences into shorter, more direct statements.`}:o<12?{text:`Your average sentence is ${o} words. While short sentences are readable, combining some into 12-22 word sentences provides better context for AI summarization.`}:{text:`Your average sentence length is ${o} words. Fine-tune toward the 12-22 word sweet spot for optimal AI compression.`}},Readability:t=>{let e=t.readabilityScore;if(e===void 0)return{text:"Simplify language where possible. A Flesch Reading Ease score of 60-70 is ideal for broad AI reusability."};let o=Math.round(e);return o<30?{text:`Your Flesch Reading Ease score is ${o} (very difficult). A score of 60-70 is ideal. Shorten sentences, use simpler vocabulary, and break up complex ideas.`}:o<50?{text:`Your Flesch Reading Ease score is ${o} (difficult). A score of 60-70 is ideal for broad AI reusability. Simplify where possible without losing meaning.`}:o<60?{text:`Your Flesch Reading Ease score is ${o} (fairly difficult). You're close to the ideal 60-70 range. Minor simplification would improve AI compressibility.`}:{text:`Your Flesch Reading Ease score is ${o}. A score of 60-70 is ideal for broad AI reusability.`}},"Jargon Density":()=>({text:"Define technical terms or replace with simpler alternatives. High jargon density reduces AI reusability.",steps:["List the 5 most domain-specific terms on the page","For each term: either add a plain-English definition on first use, or replace with simpler language","Use the 'is defined as' or 'also known as' pattern for terms you must keep","Aim for a Flesch Reading Ease score of 60 to 70 by simplifying sentence structure"],codeExample:St}),"Transition Usage":()=>({text:"Use transition words (however, therefore, additionally) to improve content flow and logical structure.",steps:["Add contrast transitions between opposing ideas: 'however', 'although', 'on the other hand'","Add sequence transitions between steps or points: 'first', 'next', 'finally'","Add addition transitions to build on a point: 'additionally', 'furthermore', 'in addition'","Add conclusion transitions at the end of sections: 'therefore', 'as a result', 'in summary'"],codeExample:wt})};function $t(t){let e=[];for(let s of Object.values(t.categories))for(let r of s.factors){let n=r.maxScore>0?r.score/r.maxScore:1;if(n>=.7)continue;let a=n<.3?"high":n<.5?"medium":"low",i=Tt[r.name],c=i?i(t.rawData):{text:`Review and improve "${r.name}" based on best practices for AI search readiness.`};e.push({category:s.name,factor:r.name,currentValue:r.value,priority:a,recommendation:c.text,...c.steps&&{steps:c.steps},...c.codeExample&&{codeExample:c.codeExample},...c.learnMoreUrl&&{learnMoreUrl:c.learnMoreUrl}})}let o={high:0,medium:1,low:2};return e.sort((s,r)=>{let n=o[s.priority]-o[r.priority];return n!==0?n:s.factor.localeCompare(r.factor)}),e}var Et=[[93,"A"],[90,"A-"],[87,"B+"],[83,"B"],[80,"B-"],[77,"C+"],[73,"C"],[70,"C-"],[67,"D+"],[63,"D"],[60,"D-"],[0,"F"]];function Ct(t,e){let o={contentExtractability:e.contentExtractability,contentStructure:e.contentStructure,answerability:e.answerability,entityClarity:e.entityClarity,groundingSignals:e.groundingSignals,authorityContext:e.authorityContext,readabilityForCompression:e.readabilityForCompression},s=Object.values(o).reduce((l,p)=>l+p,0),r=0,n=0,a=0;for(let[l,p]of Object.entries(t)){r+=p.score,n+=p.maxScore;let h=_nullishCoalesce(o[l], () => (1)),d=s>0?h/s:1/7,v=p.maxScore>0?p.score/p.maxScore*100:0;a+=v*d}let i=Math.round(a),c=me(i);return{overallScore:i,grade:c,totalPoints:r,maxPoints:n}}function me(t){for(let[e,o]of Et)if(t>=e)return o;return"F"}async function he(t,e,o){let s=Math.min(e,5e3),[r,n,a]=await Promise.allSettled([B({url:`${t}/robots.txt`,timeout:s,userAgent:o}),oe({url:`${t}/llms.txt`,timeout:s,userAgent:o}),oe({url:`${t}/llms-full.txt`,timeout:s,userAgent:o})]);return{signalsBase:t,robotsTxt:r.status==="fulfilled"&&r.value.status===200?r.value.data:null,llmsTxtExists:n.status==="fulfilled"&&n.value.status===200,llmsFullTxtExists:a.status==="fulfilled"&&a.value.status===200}}function Rt(t,e,o,s){let r=ut(e.html,t),n=ct(r,e,o),a=Ct(n.categories,s.weights),i=$t(n);return{url:t,signalsBase:o.signalsBase,analyzedAt:new Date().toISOString(),overallScore:a.overallScore,grade:a.grade,totalPoints:a.totalPoints,maxPoints:a.maxPoints,categories:n.categories,recommendations:i,rawData:n.rawData,meta:{version:H}}}async function It(t,e,o,s){let r=Date.now(),n=Rt(t,e,o,s);return{...n,meta:{...n.meta,analysisDurationMs:Date.now()-r}}}async function hn(t,e){let o=Date.now(),s=V(t.url),r=_nullishCoalesce(t.timeout, () => (e.timeout)),n=_nullishCoalesce(t.userAgent, () => (e.userAgent)),a=await X({url:s,timeout:r,userAgent:n}),i=_nullishCoalesce(_nullishCoalesce(t.signalsBase, () => (a.finalUrl)), () => (s)),c=await he(i,r,n),l=Rt(s,a,c,e);return{...l,meta:{...l.meta,analysisDurationMs:Date.now()-o}}}var _promises = require('fs/promises');async function Pt(t){try{return await _promises.access.call(void 0, t),!0}catch (e8){return!1}}async function xn(t,e){await _promises.writeFile.call(void 0, t,e,"utf-8")}var _path = require('path');var Ot=["aiseo.config.json",".aiseo.config.json","aiseo-audit.config.json"];var kt=`AISEOAudit/${H}`,Lt={contentExtractability:1,contentStructure:1,answerability:1,entityClarity:1,groundingSignals:1,authorityContext:1,readabilityForCompression:1},co=_zod.z.object({contentExtractability:_zod.z.number().min(0).default(1),contentStructure:_zod.z.number().min(0).default(1),answerability:_zod.z.number().min(0).default(1),entityClarity:_zod.z.number().min(0).default(1),groundingSignals:_zod.z.number().min(0).default(1),authorityContext:_zod.z.number().min(0).default(1),readabilityForCompression:_zod.z.number().min(0).default(1)}).default(Lt),Z=_zod.z.object({timeout:_zod.z.number().positive().default(45e3),userAgent:_zod.z.string().default(kt),format:_zod.z.enum(["pretty","json","md","html"]).default("pretty"),failUnder:_zod.z.number().min(0).max(100).optional(),weights:co}).default({timeout:45e3,userAgent:kt,format:"pretty",weights:Lt});async function uo(t){let e=_path.resolve.call(void 0, t);for(;;){for(let s of Ot){let r=_path.join.call(void 0, e,s);if(await Pt(r))return r}let o=_path.dirname.call(void 0, e);if(o===e)return null;e=o}}async function kn(t){if(t){let o=_path.resolve.call(void 0, t),s=await _promises.readFile.call(void 0, o,"utf-8");try{return Z.parse(JSON.parse(s))}catch(r){throw new Error(`Invalid config file "${o}": ${r instanceof Error?r.message:String(r)}`)}}let e=await uo(process.cwd());if(e){let o=await _promises.readFile.call(void 0, e,"utf-8");try{return Z.parse(JSON.parse(o))}catch(s){throw new Error(`Invalid config file "${e}": ${s instanceof Error?s.message:String(s)}`)}}return Z.parse({})}function ee(t){return t>=90?"#00cc66":t>=50?"#ffaa33":"#ff3333"}function ge(t){return t>=90?"#008800":t>=50?"#ffaa33":"#cc0000"}function fe(t){return t>=90?"pass":t>=50?"average":"fail"}function mo(t){return t==="good"?"✓":t==="neutral"?"—":t==="needs_improvement"?"▲":"✗"}function ho(t){return t==="good"?"good":t==="neutral"?"neutral":t==="needs_improvement"?"warn":"fail"}function S(t){return t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function Ft(){return`:root {
|
|
264
|
+
--pass: #00cc66;
|
|
265
|
+
--pass-text: #008800;
|
|
266
|
+
--average: #ffaa33;
|
|
267
|
+
--average-text: #ffaa33;
|
|
268
|
+
--fail: #ff3333;
|
|
269
|
+
--fail-text: #cc0000;
|
|
270
|
+
--bg: #fff;
|
|
271
|
+
--surface: #fff;
|
|
272
|
+
--text: #212121;
|
|
273
|
+
--text-secondary: #757575;
|
|
274
|
+
--border: #e0e0e0;
|
|
275
|
+
--font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, sans-serif;
|
|
276
|
+
}
|
|
277
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
278
|
+
body { font-family: var(--font); background: var(--bg); color: var(--text); line-height: 1.6; -webkit-font-smoothing: antialiased; }
|
|
279
|
+
.topbar { display: flex; align-items: center; height: 40px; padding: 0 16px; background: var(--surface); border-bottom: 1px solid var(--border); font-size: 13px; }
|
|
280
|
+
.topbar-title { font-weight: 600; margin-right: 12px; white-space: nowrap; }
|
|
281
|
+
.topbar-url { color: var(--text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
282
|
+
.report { max-width: 960px; margin: 0 auto; padding: 0 32px; }
|
|
283
|
+
.footer { padding: 16px 0; border-top: 1px solid var(--border); font-size: 11px; color: var(--text-secondary); display: flex; justify-content: space-between; flex-wrap: wrap; gap: 8px; }
|
|
284
|
+
.pass { color: var(--pass-text); }
|
|
285
|
+
.average { color: var(--average-text); }
|
|
286
|
+
.fail { color: var(--fail-text); }`}function go(t){let e=Math.max(0,Math.min(100,t)),o=ee(e),s=ge(e),r=56,n=2*Math.PI*r,a=n*(1-e/100),i=64,c=22,l=7;return`<svg class="gauge" viewBox="0 0 120 120" width="${i}" height="${i}">
|
|
287
|
+
<circle cx="60" cy="60" r="${r}" fill="none" stroke="#e0e0e0" stroke-width="${l}"/>
|
|
288
|
+
<circle cx="60" cy="60" r="${r}" fill="none" stroke="${o}" stroke-width="${l}"
|
|
289
|
+
stroke-dasharray="${n}" stroke-dashoffset="${a}"
|
|
290
|
+
stroke-linecap="round" transform="rotate(-90 60 60)"/>
|
|
291
|
+
<text x="60" y="${60+c*.35}" text-anchor="middle" font-size="${c}" font-weight="700" fill="${s}">${t}</text>
|
|
292
|
+
</svg>`}function fo(t,e,o,s,r){let h=2*Math.PI*80,d=ge(t),v='<circle cx="95" cy="95" r="80" fill="none" stroke="#e8e8e8" stroke-width="14"/>',x=[],w=0,y=0;for(let m of r){let A=s>0?m.score/s*360:0;if(A<.1){w+=A;continue}let T=m.maxScore>0?Math.round(m.score/m.maxScore*100):0,$=ee(T),U=A/360*h,R=h*.25-w/360*h,W=S(m.name),M=y;x.push(`<circle cx="95" cy="95" r="80" fill="none"
|
|
293
|
+
stroke="${$}" stroke-width="14"
|
|
294
|
+
stroke-dasharray="${U.toFixed(2)} ${(h-U).toFixed(2)}"
|
|
295
|
+
stroke-dashoffset="${R.toFixed(2)}"
|
|
296
|
+
class="seg-arc" data-idx="${M}"
|
|
297
|
+
onmouseenter="document.getElementById('seg-pop-${M}').style.display='flex'"
|
|
298
|
+
onmouseleave="document.getElementById('seg-pop-${M}').style.display='none'"/>`),w+=A;let N=w/360*2*Math.PI-Math.PI/2,k=14/2+1,C=Math.cos(N),z=Math.sin(N);x.push(`<line x1="${(95+(80-k)*C).toFixed(2)}" y1="${(95+(80-k)*z).toFixed(2)}"
|
|
299
|
+
x2="${(95+(80+k)*C).toFixed(2)}" y2="${(95+(80+k)*z).toFixed(2)}"
|
|
300
|
+
stroke="#fff" stroke-width="2" pointer-events="none"/>`),y++}let b=r.filter(m=>m.score>0).map((m,A)=>{let T=m.maxScore>0?Math.round(m.score/m.maxScore*100):0,$=ee(T);return`<div id="seg-pop-${A}" class="seg-popover">
|
|
301
|
+
<span class="seg-popover-dot" style="background:${$}"></span>
|
|
302
|
+
<span class="seg-popover-name">${S(m.name)}</span>
|
|
303
|
+
<span class="seg-popover-score">${T}%</span>
|
|
304
|
+
<span class="seg-popover-pts">${m.score}/${m.maxScore} pts</span>
|
|
305
|
+
</div>`}).join("");return`<div class="overall-gauge-wrap">
|
|
306
|
+
<svg class="gauge" viewBox="0 0 190 190" width="190" height="190">
|
|
307
|
+
${v}
|
|
308
|
+
${x.join(`
|
|
309
|
+
`)}
|
|
310
|
+
<text x="95" y="87" text-anchor="middle" font-size="40" font-weight="700" fill="${d}">${t}</text>
|
|
311
|
+
<text x="95" y="109" text-anchor="middle" font-size="14" font-weight="600" fill="${d}">${S(e)}</text>
|
|
312
|
+
<text x="95" y="125" text-anchor="middle" font-size="11" fill="#999">${o}/${s} pts</text>
|
|
313
|
+
</svg>
|
|
314
|
+
<div class="seg-popovers">${b}</div>
|
|
315
|
+
<div class="score-scale">
|
|
316
|
+
<span class="scale-fail">0-49</span>
|
|
317
|
+
<span class="scale-average">50-89</span>
|
|
318
|
+
<span class="scale-pass">90-100</span>
|
|
319
|
+
</div>
|
|
320
|
+
</div>`}function yo(t){let e=t.maxScore>0?Math.round(t.score/t.maxScore*100):0;return`<a class="gauge-item" href="#cat-${S(t.name.replace(/\s+/g,"-").toLowerCase())}">
|
|
321
|
+
${go(e)}
|
|
322
|
+
<span class="gauge-label">${S(t.name)}</span>
|
|
323
|
+
</a>`}function xo(t){let e=t.maxScore>0?Math.round(t.score/t.maxScore*100):0,o=fe(e),s=t.name.replace(/\s+/g,"-").toLowerCase(),r=t.factors.map(n=>`
|
|
324
|
+
<div class="audit-row">
|
|
325
|
+
<span class="audit-icon ${ho(n.status)}">${mo(n.status)}</span>
|
|
326
|
+
<span class="audit-name">${S(n.name)}</span>
|
|
327
|
+
<span class="audit-detail">${S(n.value)}</span>
|
|
328
|
+
<span class="audit-score">${n.score}/${n.maxScore}</span>
|
|
329
|
+
</div>`).join("");return`
|
|
330
|
+
<div class="category" id="cat-${s}">
|
|
331
|
+
<div class="category-header">
|
|
332
|
+
<div class="category-title ${o}">${S(t.name)}</div>
|
|
333
|
+
<div class="category-score ${o}">${e}%</div>
|
|
334
|
+
</div>
|
|
335
|
+
<div class="audits">${r}</div>
|
|
336
|
+
</div>`}function bo(t){let e=t.priority==="high"?"priority-high":t.priority==="medium"?"priority-med":"priority-low",o=t.priority==="high"?"HIGH":t.priority==="medium"?"MED":"LOW",s="";if(t.steps||t.codeExample||t.learnMoreUrl){let r="";if(t.steps&&t.steps.length>0){let n=t.steps.map(a=>`<li>${S(a)}</li>`).join("");r+=`<ol class="rec-steps">${n}</ol>`}t.codeExample&&(r+=`<pre class="rec-code"><code>${S(t.codeExample)}</code></pre>`),t.learnMoreUrl&&(r+=`<a class="rec-learn-more" href="${S(t.learnMoreUrl)}" target="_blank" rel="noopener">Learn more →</a>`),s=`<div class="rec-detail">${r}</div>`}return`
|
|
337
|
+
<div class="rec-row ${e}">
|
|
338
|
+
<span class="rec-tag">${o}</span>
|
|
339
|
+
<span class="rec-factor">${S(t.factor)}</span>
|
|
340
|
+
<span class="rec-text">${S(t.recommendation)}</span>
|
|
341
|
+
</div>${s}`}function wo(t,e){let o=Object.values(e).map(n=>n.name),s=new Map;for(let n of o){let a=t.filter(i=>i.category===n);a.length>0&&s.set(n,a)}if(s.size===0)return"";let r=`<div class="recs-section">
|
|
342
|
+
<div class="recs-title">Recommendations</div>`;for(let[n,a]of s)r+=`<div class="rec-group">
|
|
343
|
+
<div class="rec-group-name">${S(n)}</div>`,r+=a.map(bo).join(""),r+="</div>";return r+="</div>",r}function Ut(t){let e=Object.entries(t.categories),o=e.map(([,c])=>c),s=e.map(([c,l])=>({key:c,name:l.name,score:l.score,maxScore:l.maxScore})),r=o.map(yo).join(""),n=o.map(xo).join(""),a=wo(t.recommendations,t.categories),i=fo(t.overallScore,t.grade,t.totalPoints,t.maxPoints,s);return`<!DOCTYPE html>
|
|
344
|
+
<html lang="en">
|
|
345
|
+
<head>
|
|
346
|
+
<meta charset="utf-8">
|
|
347
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
348
|
+
<title>AI SEO Audit - ${S(t.url)}</title>
|
|
349
|
+
<style>
|
|
350
|
+
${Ft()}
|
|
351
|
+
.gauges-row {
|
|
352
|
+
display: flex;
|
|
353
|
+
flex-wrap: wrap;
|
|
354
|
+
justify-content: center;
|
|
355
|
+
align-items: flex-start;
|
|
356
|
+
gap: 12px;
|
|
357
|
+
padding: 24px 0;
|
|
358
|
+
border-bottom: 1px solid var(--border);
|
|
359
|
+
}
|
|
360
|
+
.gauge-item {
|
|
361
|
+
display: flex;
|
|
362
|
+
flex-direction: column;
|
|
363
|
+
align-items: center;
|
|
364
|
+
width: 110px;
|
|
365
|
+
padding: 10px 6px 8px;
|
|
366
|
+
text-decoration: none;
|
|
367
|
+
color: var(--text);
|
|
368
|
+
border-radius: 8px;
|
|
369
|
+
transition: background 0.15s;
|
|
370
|
+
}
|
|
371
|
+
.gauge-item:hover {
|
|
372
|
+
background: #f5f5f5;
|
|
373
|
+
}
|
|
374
|
+
.gauge-item .gauge { display: block; }
|
|
375
|
+
.gauge-label {
|
|
376
|
+
margin-top: 8px;
|
|
377
|
+
font-size: 11px;
|
|
378
|
+
font-weight: 500;
|
|
379
|
+
text-align: center;
|
|
380
|
+
color: var(--text-secondary);
|
|
381
|
+
line-height: 1.25;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/* Overall score */
|
|
385
|
+
.overall {
|
|
386
|
+
display: flex;
|
|
387
|
+
align-items: center;
|
|
388
|
+
flex-direction: column;
|
|
389
|
+
padding: 32px 0 24px;
|
|
390
|
+
border-bottom: 1px solid var(--border);
|
|
391
|
+
}
|
|
392
|
+
.overall-gauge-wrap {
|
|
393
|
+
display: flex;
|
|
394
|
+
flex-direction: column;
|
|
395
|
+
align-items: center;
|
|
396
|
+
position: relative;
|
|
397
|
+
}
|
|
398
|
+
.overall-gauge-wrap .gauge {
|
|
399
|
+
display: block;
|
|
400
|
+
overflow: visible;
|
|
401
|
+
}
|
|
402
|
+
.seg-arc {
|
|
403
|
+
cursor: pointer;
|
|
404
|
+
transition: stroke-width 0.15s ease, filter 0.15s ease;
|
|
405
|
+
}
|
|
406
|
+
.seg-arc:hover {
|
|
407
|
+
stroke-width: 20;
|
|
408
|
+
filter: brightness(1.1);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/* Segment popovers */
|
|
412
|
+
.seg-popovers {
|
|
413
|
+
position: relative;
|
|
414
|
+
min-height: 36px;
|
|
415
|
+
display: flex;
|
|
416
|
+
justify-content: center;
|
|
417
|
+
margin-top: 4px;
|
|
418
|
+
}
|
|
419
|
+
.seg-popover {
|
|
420
|
+
display: none;
|
|
421
|
+
align-items: center;
|
|
422
|
+
gap: 8px;
|
|
423
|
+
background: #fff;
|
|
424
|
+
border: 1px solid var(--border);
|
|
425
|
+
border-radius: 8px;
|
|
426
|
+
padding: 8px 14px;
|
|
427
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
|
428
|
+
font-size: 13px;
|
|
429
|
+
white-space: nowrap;
|
|
430
|
+
}
|
|
431
|
+
.seg-popover-dot {
|
|
432
|
+
width: 10px;
|
|
433
|
+
height: 10px;
|
|
434
|
+
border-radius: 50%;
|
|
435
|
+
flex-shrink: 0;
|
|
436
|
+
}
|
|
437
|
+
.seg-popover-name { font-weight: 600; }
|
|
438
|
+
.seg-popover-score { font-weight: 700; }
|
|
439
|
+
.seg-popover-pts { color: var(--text-secondary); }
|
|
440
|
+
|
|
441
|
+
/* Score scale legend */
|
|
442
|
+
.score-scale {
|
|
443
|
+
display: flex;
|
|
444
|
+
justify-content: center;
|
|
445
|
+
gap: 16px;
|
|
446
|
+
margin-top: 12px;
|
|
447
|
+
font-size: 11px;
|
|
448
|
+
color: var(--text-secondary);
|
|
449
|
+
}
|
|
450
|
+
.score-scale span::before {
|
|
451
|
+
content: "";
|
|
452
|
+
display: inline-block;
|
|
453
|
+
width: 8px;
|
|
454
|
+
height: 8px;
|
|
455
|
+
border-radius: 50%;
|
|
456
|
+
margin-right: 4px;
|
|
457
|
+
vertical-align: middle;
|
|
458
|
+
}
|
|
459
|
+
.scale-fail::before { background: var(--fail); }
|
|
460
|
+
.scale-average::before { background: var(--average); }
|
|
461
|
+
.scale-pass::before { background: var(--pass); }
|
|
462
|
+
|
|
463
|
+
/* Categories */
|
|
464
|
+
.category {
|
|
465
|
+
padding: 24px 0 16px;
|
|
466
|
+
border-bottom: 1px solid var(--border);
|
|
467
|
+
}
|
|
468
|
+
.category:last-child { border-bottom: none; }
|
|
469
|
+
.category-header {
|
|
470
|
+
display: flex;
|
|
471
|
+
justify-content: space-between;
|
|
472
|
+
align-items: baseline;
|
|
473
|
+
margin-bottom: 12px;
|
|
474
|
+
}
|
|
475
|
+
.category-title {
|
|
476
|
+
font-size: 18px;
|
|
477
|
+
font-weight: 600;
|
|
478
|
+
}
|
|
479
|
+
.category-title.pass { color: var(--pass-text); }
|
|
480
|
+
.category-title.average { color: var(--average-text); }
|
|
481
|
+
.category-title.fail { color: var(--fail-text); }
|
|
482
|
+
.category-score {
|
|
483
|
+
font-size: 14px;
|
|
484
|
+
font-weight: 700;
|
|
485
|
+
}
|
|
486
|
+
.category-score.pass { color: var(--pass-text); }
|
|
487
|
+
.category-score.average { color: var(--average-text); }
|
|
488
|
+
.category-score.fail { color: var(--fail-text); }
|
|
489
|
+
|
|
490
|
+
/* Audit rows */
|
|
491
|
+
.audit-row {
|
|
492
|
+
display: flex;
|
|
493
|
+
align-items: baseline;
|
|
494
|
+
padding: 8px 0;
|
|
495
|
+
border-top: 1px solid #f0f0f0;
|
|
496
|
+
font-size: 13px;
|
|
497
|
+
gap: 8px;
|
|
498
|
+
}
|
|
499
|
+
.audit-icon {
|
|
500
|
+
width: 18px;
|
|
501
|
+
flex-shrink: 0;
|
|
502
|
+
text-align: center;
|
|
503
|
+
font-size: 12px;
|
|
504
|
+
}
|
|
505
|
+
.audit-icon.good { color: var(--pass); }
|
|
506
|
+
.audit-icon.warn { color: var(--average); }
|
|
507
|
+
.audit-icon.fail { color: var(--fail); }
|
|
508
|
+
.audit-icon.neutral { color: var(--text-secondary); }
|
|
509
|
+
.audit-name {
|
|
510
|
+
font-weight: 500;
|
|
511
|
+
min-width: 180px;
|
|
512
|
+
flex-shrink: 0;
|
|
513
|
+
}
|
|
514
|
+
.audit-detail {
|
|
515
|
+
flex: 1;
|
|
516
|
+
color: var(--text-secondary);
|
|
517
|
+
}
|
|
518
|
+
.audit-score {
|
|
519
|
+
color: var(--text-secondary);
|
|
520
|
+
white-space: nowrap;
|
|
521
|
+
text-align: right;
|
|
522
|
+
min-width: 44px;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/* Recommendations */
|
|
526
|
+
.recs-section {
|
|
527
|
+
padding: 24px 0 16px;
|
|
528
|
+
border-top: 1px solid var(--border);
|
|
529
|
+
}
|
|
530
|
+
.recs-title {
|
|
531
|
+
font-size: 20px;
|
|
532
|
+
font-weight: 600;
|
|
533
|
+
margin-bottom: 20px;
|
|
534
|
+
}
|
|
535
|
+
.rec-group {
|
|
536
|
+
margin-bottom: 20px;
|
|
537
|
+
}
|
|
538
|
+
.rec-group-name {
|
|
539
|
+
font-size: 13px;
|
|
540
|
+
font-weight: 600;
|
|
541
|
+
text-transform: uppercase;
|
|
542
|
+
letter-spacing: 0.4px;
|
|
543
|
+
color: var(--text-secondary);
|
|
544
|
+
padding-bottom: 6px;
|
|
545
|
+
border-bottom: 1px solid var(--border);
|
|
546
|
+
margin-bottom: 2px;
|
|
547
|
+
}
|
|
548
|
+
.rec-row {
|
|
549
|
+
display: flex;
|
|
550
|
+
gap: 10px;
|
|
551
|
+
align-items: baseline;
|
|
552
|
+
padding: 8px 0;
|
|
553
|
+
border-bottom: 1px solid #f5f5f5;
|
|
554
|
+
font-size: 13px;
|
|
555
|
+
}
|
|
556
|
+
.rec-tag {
|
|
557
|
+
font-size: 9px;
|
|
558
|
+
font-weight: 700;
|
|
559
|
+
padding: 2px 5px;
|
|
560
|
+
border-radius: 3px;
|
|
561
|
+
white-space: nowrap;
|
|
562
|
+
flex-shrink: 0;
|
|
563
|
+
letter-spacing: 0.3px;
|
|
564
|
+
}
|
|
565
|
+
.priority-high .rec-tag { background: #fce8e6; color: var(--fail-text); }
|
|
566
|
+
.priority-med .rec-tag { background: #fef7e0; color: var(--average-text); }
|
|
567
|
+
.priority-low .rec-tag { background: #f1f3f4; color: var(--text-secondary); }
|
|
568
|
+
.rec-factor {
|
|
569
|
+
font-weight: 600;
|
|
570
|
+
white-space: nowrap;
|
|
571
|
+
flex-shrink: 0;
|
|
572
|
+
}
|
|
573
|
+
.rec-text { color: var(--text-secondary); }
|
|
574
|
+
.rec-detail {
|
|
575
|
+
padding: 8px 0 8px 16px;
|
|
576
|
+
border-bottom: 1px solid #f5f5f5;
|
|
577
|
+
font-size: 12px;
|
|
578
|
+
color: var(--text-secondary);
|
|
579
|
+
}
|
|
580
|
+
.rec-steps {
|
|
581
|
+
margin: 0 0 8px 0;
|
|
582
|
+
padding-left: 20px;
|
|
583
|
+
}
|
|
584
|
+
.rec-steps li { margin-bottom: 3px; }
|
|
585
|
+
.rec-code {
|
|
586
|
+
background: #f8f9fa;
|
|
587
|
+
border: 1px solid var(--border);
|
|
588
|
+
border-radius: 4px;
|
|
589
|
+
padding: 10px 12px;
|
|
590
|
+
font-size: 11px;
|
|
591
|
+
overflow-x: auto;
|
|
592
|
+
margin: 0 0 8px 0;
|
|
593
|
+
white-space: pre;
|
|
594
|
+
}
|
|
595
|
+
.rec-learn-more {
|
|
596
|
+
font-size: 11px;
|
|
597
|
+
color: var(--text-secondary);
|
|
598
|
+
text-decoration: none;
|
|
599
|
+
}
|
|
600
|
+
.rec-learn-more:hover { text-decoration: underline; }
|
|
601
|
+
@media (max-width: 600px) {
|
|
602
|
+
.report { padding: 0 16px; }
|
|
603
|
+
.gauges-row { gap: 4px; }
|
|
604
|
+
.gauge-item { width: 80px; padding: 8px 4px; }
|
|
605
|
+
.audit-row { flex-wrap: wrap; }
|
|
606
|
+
.audit-name { min-width: 140px; }
|
|
607
|
+
.rec-row { flex-wrap: wrap; }
|
|
608
|
+
}
|
|
609
|
+
</style>
|
|
610
|
+
</head>
|
|
611
|
+
<body>
|
|
612
|
+
|
|
613
|
+
<div class="topbar">
|
|
614
|
+
<span class="topbar-title">AI SEO Audit</span>
|
|
615
|
+
<span class="topbar-url">${S(t.url)}</span>
|
|
616
|
+
</div>
|
|
617
|
+
|
|
618
|
+
<div class="report">
|
|
619
|
+
<div class="gauges-row">
|
|
620
|
+
${r}
|
|
621
|
+
</div>
|
|
622
|
+
|
|
623
|
+
<div class="overall">
|
|
624
|
+
${i}
|
|
625
|
+
</div>
|
|
626
|
+
|
|
627
|
+
${n}
|
|
628
|
+
|
|
629
|
+
${a}
|
|
630
|
+
|
|
631
|
+
<div class="footer">
|
|
632
|
+
<span>Generated by aiseo-audit v${S(t.meta.version)}</span>
|
|
633
|
+
<span>${S(t.analyzedAt)} · ${t.meta.analysisDurationMs}ms</span>
|
|
634
|
+
<span>Domain signals checked at: <code>${S(t.signalsBase)}</code></span>
|
|
635
|
+
${t.url.startsWith("http://")?'<span style="color:#e8a735;margin-top:4px">Note: Audited over HTTP. Domain signals (robots.txt, llms.txt) may differ in production.</span>':""}
|
|
636
|
+
</div>
|
|
637
|
+
</div>
|
|
638
|
+
|
|
639
|
+
</body>
|
|
640
|
+
</html>`}function So(t,e){if(t.status==="failed")return`
|
|
641
|
+
<div class="sitemap-url-section failed">
|
|
642
|
+
<div class="sitemap-url-header">
|
|
643
|
+
<span class="sitemap-url-status fail">✗</span>
|
|
644
|
+
<span class="sitemap-url-label">${S(t.url)}</span>
|
|
645
|
+
</div>
|
|
646
|
+
<div class="sitemap-url-error">Error: ${S(t.error)}</div>
|
|
647
|
+
</div>`;let{result:o}=t,s=o.overallScore,r=ee(s),n=Object.entries(o.categories),a=o.recommendations[0],i=n.map(([,l])=>{let p=l.maxScore>0?Math.round(l.score/l.maxScore*100):0,h=fe(p);return`<div class="sitemap-cat-row">
|
|
648
|
+
<span class="sitemap-cat-name">${S(l.name)}</span>
|
|
649
|
+
<span class="sitemap-cat-score ${h}">${p}%</span>
|
|
650
|
+
</div>`}).join(""),c=a?`<div class="sitemap-top-rec">Top recommendation: <strong>${S(a.factor)}</strong> \u2014 ${S(a.recommendation)}</div>`:"";return`
|
|
651
|
+
<div class="sitemap-url-section" id="url-${e}">
|
|
652
|
+
<div class="sitemap-url-header">
|
|
653
|
+
<span class="sitemap-url-status" style="color:${r}">✓</span>
|
|
654
|
+
<span class="sitemap-url-label">${S(o.url)}</span>
|
|
655
|
+
<span class="sitemap-url-score" style="color:${r}">${o.overallScore}/100</span>
|
|
656
|
+
<span class="sitemap-url-grade" style="color:${r}">${S(o.grade)}</span>
|
|
657
|
+
</div>
|
|
658
|
+
<div class="sitemap-url-body">
|
|
659
|
+
<div class="sitemap-cats">${i}</div>
|
|
660
|
+
${c}
|
|
661
|
+
</div>
|
|
662
|
+
</div>`}function Nt(t){let e=ge(t.averageScore),o=t.urlResults.some(n=>n.status==="success"&&n.result.url.startsWith("http://")),s=Object.values(t.categoryAverages).map(n=>{let a=fe(n.averagePct);return`<div class="sitemap-cat-row">
|
|
663
|
+
<span class="sitemap-cat-name">${S(n.name)}</span>
|
|
664
|
+
<span class="sitemap-cat-score ${a}">${n.averagePct}%</span>
|
|
665
|
+
</div>`}).join(""),r=t.urlResults.map((n,a)=>So(n,a)).join("");return`<!DOCTYPE html>
|
|
666
|
+
<html lang="en">
|
|
667
|
+
<head>
|
|
668
|
+
<meta charset="utf-8">
|
|
669
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
670
|
+
<title>AI SEO Sitemap Audit - ${S(t.sitemapUrl)}</title>
|
|
671
|
+
<style>
|
|
672
|
+
${Ft()}
|
|
673
|
+
.summary { display: flex; gap: 32px; padding: 32px 0 24px; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
|
|
674
|
+
.summary-score { display: flex; flex-direction: column; align-items: center; }
|
|
675
|
+
.summary-score-value { font-size: 64px; font-weight: 700; line-height: 1; }
|
|
676
|
+
.summary-score-grade { font-size: 24px; font-weight: 600; }
|
|
677
|
+
.summary-stats { display: flex; flex-direction: column; gap: 6px; font-size: 14px; justify-content: center; }
|
|
678
|
+
.summary-stat { color: var(--text-secondary); }
|
|
679
|
+
.summary-signals { font-size: 12px; color: var(--text-secondary); padding-top: 4px; }
|
|
680
|
+
.category-averages { padding: 24px 0; border-bottom: 1px solid var(--border); }
|
|
681
|
+
.category-averages-title { font-size: 18px; font-weight: 600; margin-bottom: 12px; }
|
|
682
|
+
.sitemap-cat-row { display: flex; justify-content: space-between; align-items: center; padding: 6px 0; border-top: 1px solid #f0f0f0; font-size: 13px; }
|
|
683
|
+
.sitemap-cat-name { color: var(--text); }
|
|
684
|
+
.sitemap-cat-score { font-weight: 700; }
|
|
685
|
+
.sitemap-cat-score.pass { color: var(--pass-text); }
|
|
686
|
+
.sitemap-cat-score.average { color: var(--average-text); }
|
|
687
|
+
.sitemap-cat-score.fail { color: var(--fail-text); }
|
|
688
|
+
.url-results { padding: 24px 0; }
|
|
689
|
+
.url-results-title { font-size: 18px; font-weight: 600; margin-bottom: 16px; }
|
|
690
|
+
.sitemap-url-section { border: 1px solid var(--border); border-radius: 8px; margin-bottom: 12px; overflow: hidden; }
|
|
691
|
+
.sitemap-url-section.failed { border-color: #fce8e6; }
|
|
692
|
+
.sitemap-url-header { display: flex; align-items: center; gap: 10px; padding: 12px 16px; background: #fafafa; cursor: pointer; font-size: 13px; }
|
|
693
|
+
.sitemap-url-status { font-size: 14px; flex-shrink: 0; }
|
|
694
|
+
.sitemap-url-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; }
|
|
695
|
+
.sitemap-url-score { font-weight: 700; white-space: nowrap; }
|
|
696
|
+
.sitemap-url-grade { font-weight: 700; white-space: nowrap; }
|
|
697
|
+
.sitemap-url-body { padding: 12px 16px; border-top: 1px solid var(--border); }
|
|
698
|
+
.sitemap-url-error { padding: 12px 16px; color: var(--fail-text); font-size: 13px; }
|
|
699
|
+
.sitemap-top-rec { font-size: 12px; color: var(--text-secondary); margin-top: 10px; padding-top: 10px; border-top: 1px solid #f0f0f0; }
|
|
700
|
+
@media (max-width: 600px) {
|
|
701
|
+
.report { padding: 0 16px; }
|
|
702
|
+
.summary { flex-direction: column; gap: 16px; }
|
|
703
|
+
}
|
|
704
|
+
</style>
|
|
705
|
+
</head>
|
|
706
|
+
<body>
|
|
707
|
+
|
|
708
|
+
<div class="topbar">
|
|
709
|
+
<span class="topbar-title">AI SEO Sitemap Audit</span>
|
|
710
|
+
<span class="topbar-url">${S(t.sitemapUrl)}</span>
|
|
711
|
+
</div>
|
|
712
|
+
|
|
713
|
+
<div class="report">
|
|
714
|
+
<div class="summary">
|
|
715
|
+
<div class="summary-score">
|
|
716
|
+
<span class="summary-score-value" style="color:${e}">${t.averageScore}</span>
|
|
717
|
+
<span class="summary-score-grade" style="color:${e}">${S(t.averageGrade)}</span>
|
|
718
|
+
<span style="font-size:12px;color:var(--text-secondary);margin-top:4px">Average Score</span>
|
|
719
|
+
</div>
|
|
720
|
+
<div class="summary-stats">
|
|
721
|
+
<div class="summary-stat">Total URLs: <strong>${t.totalUrls}</strong></div>
|
|
722
|
+
<div class="summary-stat">Audited: <strong style="color:var(--pass-text)">${t.succeededCount}</strong></div>
|
|
723
|
+
<div class="summary-stat">Failed: <strong style="color:${t.failedCount>0?"var(--fail-text)":"var(--text-secondary)"}">${t.failedCount}</strong></div>
|
|
724
|
+
<div class="summary-signals">Domain signals checked at: <code>${S(t.signalsBase)}</code></div>
|
|
725
|
+
</div>
|
|
726
|
+
</div>
|
|
727
|
+
|
|
728
|
+
<div class="category-averages">
|
|
729
|
+
<div class="category-averages-title">Site-Wide Category Averages</div>
|
|
730
|
+
${s}
|
|
731
|
+
</div>
|
|
732
|
+
|
|
733
|
+
<div class="url-results">
|
|
734
|
+
<div class="url-results-title">URL Results</div>
|
|
735
|
+
${r}
|
|
736
|
+
</div>
|
|
737
|
+
|
|
738
|
+
<div class="footer">
|
|
739
|
+
<span>Generated by aiseo-audit v${S(t.meta.version)}</span>
|
|
740
|
+
<span>${S(t.analyzedAt)} · ${t.meta.analysisDurationMs}ms</span>
|
|
741
|
+
${o?'<span style="color:#e8a735;margin-top:4px">Note: Some URLs were audited over HTTP. Domain signals (robots.txt, llms.txt) may differ in production.</span>':""}
|
|
742
|
+
</div>
|
|
743
|
+
</div>
|
|
744
|
+
|
|
745
|
+
</body>
|
|
746
|
+
</html>`}function zt(t){let e=[];t.url.startsWith("http://")&&e.push("Audited over HTTP. Domain signals (robots.txt, llms.txt) may differ in production.");let o=e.length>0?{...t,notes:e}:t;return JSON.stringify(o,null,2)}function _t(t){let e=[];t.urlResults.some(r=>r.status==="success"&&r.result.url.startsWith("http://"))&&e.push("Some URLs were audited over HTTP. Domain signals (robots.txt, llms.txt) may differ in production.");let s=e.length>0?{...t,notes:e}:t;return JSON.stringify(s,null,2)}function jt(t){let e=[];e.push("# AI SEO Audit"),e.push(""),e.push(`**URL:** ${t.url}`),e.push(""),e.push(`**Domain signals checked at:** \`${t.signalsBase}\``),e.push(""),e.push("| Category | Score | Percentage |"),e.push("|----------|-------|------------|");for(let o of Object.values(t.categories)){let s=o.maxScore>0?Math.round(o.score/o.maxScore*100):0;e.push(`| ${o.name} | ${o.score}/${o.maxScore} | ${s}% |`)}e.push(""),e.push(`## Overall: ${t.overallScore}/100 (${t.grade}) - ${t.totalPoints}/${t.maxPoints} pts`),e.push("");for(let o of Object.values(t.categories)){let s=o.maxScore>0?Math.round(o.score/o.maxScore*100):0;e.push(`### ${o.name} (${s}%)`),e.push(""),e.push("| Factor | Score | Status | Details |"),e.push("|--------|-------|--------|---------|");for(let r of o.factors){let n=r.status==="good"?"pass":r.status==="neutral"?"-":r.status==="needs_improvement"?"warn":"fail";e.push(`| ${r.name} | ${r.score}/${r.maxScore} | ${n} | ${r.value} |`)}e.push("")}if(t.recommendations.length>0){e.push("## Recommendations"),e.push("");let o=Object.values(t.categories).map(s=>s.name);for(let s of o){let r=t.recommendations.filter(n=>n.category===s);if(r.length!==0){e.push(`### ${s}`),e.push("");for(let n of r){let a=n.priority==="high"?"**HIGH**":n.priority==="medium"?"*MED*":"LOW";e.push(`- [${a}] **${n.factor}**: ${n.recommendation}`),n.steps&&n.steps.length>0&&n.steps.forEach((i,c)=>{e.push(` ${c+1}. ${i}`)}),n.codeExample&&(e.push(""),e.push(" ```"),n.codeExample.split(`
|
|
747
|
+
`).forEach(i=>{e.push(` ${i}`)}),e.push(" ```")),n.learnMoreUrl&&(e.push(""),e.push(` [Learn more](${n.learnMoreUrl})`)),(n.steps||n.codeExample||n.learnMoreUrl)&&e.push("")}e.push("")}}}return e.push("---"),e.push(`*Generated by aiseo-audit v${t.meta.version} | ${t.analyzedAt} | ${t.meta.analysisDurationMs}ms*`),t.url.startsWith("http://")&&(e.push(""),e.push("> **Note:** Audited over HTTP. Domain signals (robots.txt, llms.txt) may differ in production.")),e.join(`
|
|
748
|
+
`)}function Ht(t){let e=[];if(e.push("# AI SEO Sitemap Audit Report"),e.push(""),e.push(`**Sitemap:** ${t.sitemapUrl}`),e.push(`**Domain signals checked at:** \`${t.signalsBase}\``),e.push(`**Analyzed at:** ${t.analyzedAt}`),e.push(""),e.push("## Summary"),e.push(""),e.push("| Metric | Value |"),e.push("|--------|-------|"),e.push(`| Average Score | ${t.averageScore}/100 |`),e.push(`| Average Grade | ${t.averageGrade} |`),e.push(`| Total URLs | ${t.totalUrls} |`),e.push(`| Succeeded | ${t.succeededCount} |`),e.push(`| Failed | ${t.failedCount} |`),e.push(""),Object.keys(t.categoryAverages).length>0){e.push("## Site-Wide Category Averages"),e.push(""),e.push("| Category | Average Score |"),e.push("|----------|---------------|");for(let s of Object.values(t.categoryAverages))e.push(`| ${s.name} | ${s.averagePct}% |`);e.push("")}e.push("## URL Results"),e.push("");for(let s of t.urlResults){if(s.status==="failed"){e.push(`### \u274C ${s.url}`),e.push(""),e.push(`**Error:** ${s.error}`),e.push("");continue}let{result:r}=s;e.push(`### ${r.url}`),e.push(""),e.push(`**Score:** ${r.overallScore}/100 | **Grade:** ${r.grade} | **Points:** ${r.totalPoints}/${r.maxPoints}`),e.push(""),e.push("| Category | Score | Percentage |"),e.push("|----------|-------|------------|");for(let n of Object.values(r.categories)){let a=n.maxScore>0?Math.round(n.score/n.maxScore*100):0;e.push(`| ${n.name} | ${n.score}/${n.maxScore} | ${a}% |`)}if(e.push(""),r.recommendations.length>0){e.push("**Recommendations:**"),e.push("");for(let n of r.recommendations){let a=n.priority==="high"?"**HIGH**":n.priority==="medium"?"*MED*":"LOW";e.push(`- [${a}] **${n.factor}**: ${n.recommendation}`)}e.push("")}}return e.push("---"),e.push(`*Generated by aiseo-audit v${t.meta.version} | ${t.analyzedAt} | ${t.meta.analysisDurationMs}ms*`),t.urlResults.some(s=>s.status==="success"&&s.result.url.startsWith("http://"))&&(e.push(""),e.push("> **Note:** Some URLs were audited over HTTP. Domain signals (robots.txt, llms.txt) may differ in production.")),e.join(`
|
|
749
|
+
`)}var _chalk = require('chalk'); var _chalk2 = _interopRequireDefault(_chalk);function J(t,e){let o=e>0?t/e*100:0;return o>=90?_chalk2.default.green:o>=50?_chalk2.default.yellow:_chalk2.default.red}function ye(t){return t.startsWith("A")?_chalk2.default.green:t.startsWith("B")||t.startsWith("C")?_chalk2.default.yellow:_chalk2.default.red}function xe(t,e){return t+" ".repeat(Math.max(0,e-t.length))}function be(t){return _chalk2.default.dim(".".repeat(t))}function vo(t,e,o){let s=o.crawlerAccess!==void 0,r=_nullishCoalesce(_optionalChain([o, 'access', _53 => _53.llmsTxt, 'optionalAccess', _54 => _54.llmsTxtExists]), () => (!1)),n=_nullishCoalesce(_optionalChain([o, 'access', _55 => _55.llmsTxt, 'optionalAccess', _56 => _56.llmsFullTxtExists]), () => (!1));t.push(_chalk2.default.dim(` Domain signals checked at: ${e}`)),t.push(_chalk2.default.dim(` robots.txt ........ ${s?_chalk2.default.green("found"):_chalk2.default.red("not found")}`)),t.push(_chalk2.default.dim(` llms.txt .......... ${r?_chalk2.default.green("found"):_chalk2.default.red("not found")}`)),t.push(_chalk2.default.dim(` llms-full.txt ..... ${n?_chalk2.default.green("found"):_chalk2.default.red("not found")}`))}function Gt(t){let e=[],s=_chalk2.default.dim("=".repeat(60)),r=_chalk2.default.dim("-".repeat(60));e.push(""),e.push(s),e.push(_chalk2.default.bold(" AI SEO Audit Report")),e.push(_chalk2.default.dim(` ${t.url}`)),e.push(s),e.push("");let n=J(t.overallScore,100),a=ye(t.grade);e.push(` Overall Score: ${n(`${t.overallScore}/100`)} Grade: ${a(t.grade)}`),e.push(_chalk2.default.dim(` Points: ${t.totalPoints}/${t.maxPoints}`)),e.push(""),vo(e,t.signalsBase,t.rawData),e.push(""),e.push(r);for(let i of Object.values(t.categories)){let c=J(i.score,i.maxScore),l=i.maxScore>0?Math.round(i.score/i.maxScore*100):0,p=xe(i.name,38),h=be(Math.max(2,40-i.name.length));e.push(""),e.push(` ${_chalk2.default.bold(p)} ${h} ${c(`${i.score}/${i.maxScore}`)} ${_chalk2.default.dim(`(${l}%)`)}`);for(let d of i.factors){let v=J(d.score,d.maxScore),x=xe(` ${d.name}`,40),w=be(Math.max(2,42-d.name.length));e.push(` ${_chalk2.default.dim(x)} ${w} ${v(`${d.score}/${d.maxScore}`)} ${_chalk2.default.dim(d.value)}`)}}if(e.push(""),e.push(r),t.recommendations.length>0){e.push(""),e.push(_chalk2.default.bold(" Recommendations:")),e.push("");for(let i=0;i<t.recommendations.length;i++){let c=t.recommendations[i],l=c.priority==="high"?_chalk2.default.red("[HIGH]"):c.priority==="medium"?_chalk2.default.yellow("[MED] "):_chalk2.default.dim("[LOW] ");e.push(` ${i+1}. ${l} ${_chalk2.default.bold(c.factor)}`),e.push(` ${_chalk2.default.dim(c.recommendation)}`),c.steps&&c.steps.length>0&&(e.push(""),e.push(` ${_chalk2.default.dim("Steps:")}`),c.steps.forEach((p,h)=>{e.push(` ${_chalk2.default.dim(`${h+1}. ${p}`)}`)})),c.codeExample&&(e.push(""),e.push(` ${_chalk2.default.dim("Example:")}`),e.push(` ${_chalk2.default.dim("\u250C"+"\u2500".repeat(50))}`),c.codeExample.split(`
|
|
750
|
+
`).forEach(p=>{e.push(` ${_chalk2.default.dim("\u2502")} ${_chalk2.default.dim(p)}`)}),e.push(` ${_chalk2.default.dim("\u2514"+"\u2500".repeat(50))}`)),c.learnMoreUrl&&(e.push(""),e.push(` ${_chalk2.default.dim(`Learn more: ${c.learnMoreUrl}`)}`)),e.push("")}}return e.push(s),e.push(_chalk2.default.dim(` Analyzed at: ${t.analyzedAt}`)),e.push(_chalk2.default.dim(` Duration: ${t.meta.analysisDurationMs}ms`)),t.url.startsWith("http://")&&e.push(_chalk2.default.yellow(" Note: Audited over HTTP. Domain signals (robots.txt, llms.txt) may differ in production.")),e.push(s),e.push(""),e.join(`
|
|
751
|
+
`)}function Wt(t){let e=[],s=_chalk2.default.dim("=".repeat(60)),r=_chalk2.default.dim("-".repeat(60));e.push(""),e.push(s),e.push(_chalk2.default.bold(" AI SEO Sitemap Audit Report")),e.push(_chalk2.default.dim(` ${t.sitemapUrl}`)),e.push(s),e.push("");let n=J(t.averageScore,100),a=ye(t.averageGrade);if(e.push(` Average Score: ${n(`${t.averageScore}/100`)} Grade: ${a(t.averageGrade)}`),e.push(_chalk2.default.dim(` URLs: ${t.succeededCount} audited, ${t.failedCount} failed, ${t.totalUrls} total`)),e.push(""),e.push(_chalk2.default.dim(` Domain signals checked at: ${t.signalsBase}`)),e.push(""),e.push(r),Object.keys(t.categoryAverages).length>0){e.push(""),e.push(_chalk2.default.bold(" Site-Wide Category Averages:")),e.push("");for(let c of Object.values(t.categoryAverages)){let l=J(c.averagePct,100),p=xe(c.name,38),h=be(Math.max(2,40-c.name.length));e.push(` ${_chalk2.default.bold(p)} ${h} ${l(`${c.averagePct}%`)}`)}e.push(""),e.push(r)}e.push(""),e.push(_chalk2.default.bold(" URL Results:")),e.push("");for(let c of t.urlResults){if(c.status==="failed"){e.push(` ${_chalk2.default.red("\u2717")} ${_chalk2.default.dim(c.url)}`),e.push(` ${_chalk2.default.red(`Error: ${c.error}`)}`),e.push("");continue}let{result:l}=c,p=J(l.overallScore,100),h=ye(l.grade),d=l.recommendations[0];e.push(` ${_chalk2.default.green("\u2713")} ${_chalk2.default.dim(l.url)}`),e.push(` Score: ${p(`${l.overallScore}/100`)} Grade: ${h(l.grade)}`),d&&e.push(` ${_chalk2.default.dim(`Top rec: ${d.factor} \u2014 ${d.recommendation}`)}`),e.push("")}return e.push(s),e.push(_chalk2.default.dim(` Analyzed at: ${t.analyzedAt}`)),e.push(_chalk2.default.dim(` Duration: ${t.meta.analysisDurationMs}ms`)),t.urlResults.some(c=>c.status==="success"&&c.result.url.startsWith("http://"))&&e.push(_chalk2.default.yellow(" Note: Some URLs were audited over HTTP. Domain signals (robots.txt, llms.txt) may differ in production.")),e.push(s),e.push(""),e.join(`
|
|
752
|
+
`)}function Jn(t,e){switch(e.format){case"json":return zt(t);case"md":return jt(t);case"html":return Ut(t);default:return Gt(t)}}function Vn(t,e){switch(e.format){case"json":return _t(t);case"md":return Ht(t);case"html":return Nt(t);default:return Wt(t)}}var _xmltohtmlconverter = require('xml-to-html-converter');function Ao(t){let e=t.trim();return e.startsWith("<![CDATA[")&&e.endsWith("]]>")?e.slice(9,-3):e}function we(t,e){for(let o of t){if(o.xmlTag==="loc"&&o.children){let s=o.children.filter(r=>r.role==="textLeaf").map(r=>Ao(r.raw)).join("").trim();s&&e.push(s)}o.children&&we(o.children,e)}}function Bt(t){let e=_xmltohtmlconverter.scaffold.call(void 0, t),o=[];return we(e,o),o}function Yt(t){for(let e of t)if(e.xmlTag==="sitemapindex"||e.children&&Yt(e.children))return!0;return!1}async function To(t,e,o){let s=await B({url:t,timeout:e,userAgent:o});if(s.status!==200)throw new Error(`Failed to fetch sitemap: HTTP ${s.status}`);let r=_xmltohtmlconverter.scaffold.call(void 0, s.data);if(Yt(r))return $o(s.data,e,o);let n=[];return we(r,n),n}async function $o(t,e,o){let s=Bt(t),r=[];for(let n of s){let a=await B({url:n,timeout:e,userAgent:o});a.status===200&&r.push(...Bt(a.data))}return r}function Eo(t){let e=t.filter(r=>r.status==="success").map(r=>r.result);if(e.length===0)return{};let o={};for(let r of e)for(let[n,a]of Object.entries(r.categories)){let i=a.maxScore>0?a.score/a.maxScore*100:0;o[n]||(o[n]={name:a.name,totalPct:0,count:0}),o[n].totalPct+=i,o[n].count+=1}let s={};for(let[r,n]of Object.entries(o))s[r]={name:n.name,averagePct:Math.round(n.totalPct/n.count)};return s}async function na(t,e){let o=Date.now(),s=_nullishCoalesce(t.timeout, () => (e.timeout)),r=_nullishCoalesce(t.userAgent, () => (e.userAgent)),n=await To(t.sitemapUrl,s,r),a=t.sitemapUrl.substring(0,t.sitemapUrl.lastIndexOf("/")),i=_nullishCoalesce(t.signalsBase, () => (a)),c=await he(i,s,r),l=[];for(let y of n){let b=V(y);try{let m=await X({url:b,timeout:s,userAgent:r}),A=await It(b,m,c,e);l.push({status:"success",result:A})}catch(m){l.push({status:"failed",url:b,error:m instanceof Error?m.message:String(m)})}}let p=l.filter(y=>y.status==="success").map(y=>y.result),h=p.length,d=l.length-h,v=h>0?Math.round(p.reduce((y,b)=>y+b.overallScore,0)/h):0,x=me(v),w=Eo(l);return{sitemapUrl:t.sitemapUrl,signalsBase:c.signalsBase,analyzedAt:new Date().toISOString(),totalUrls:l.length,succeededCount:h,failedCount:d,averageScore:v,averageGrade:x,categoryAverages:w,urlResults:l,meta:{version:H,analysisDurationMs:Date.now()-o}}}exports.a = H; exports.b = _; exports.c = Fo; exports.d = hn; exports.e = xn; exports.f = kn; exports.g = Jn; exports.h = Vn; exports.i = na;
|
|
753
|
+
//# sourceMappingURL=chunk-DTQ5AQ4G.js.map
|