aeo.js 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +132 -17
- package/dist/angular.d.mts +29 -0
- package/dist/angular.d.ts +29 -0
- package/dist/angular.js +1314 -0
- package/dist/angular.js.map +1 -0
- package/dist/angular.mjs +1310 -0
- package/dist/angular.mjs.map +1 -0
- package/dist/astro.d.mts +8 -2
- package/dist/astro.d.ts +8 -2
- package/dist/astro.js +342 -100
- package/dist/astro.js.map +1 -1
- package/dist/astro.mjs +342 -100
- package/dist/astro.mjs.map +1 -1
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +1880 -0
- package/dist/cli.js.map +1 -0
- package/dist/cli.mjs +1878 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/index.d.mts +178 -4
- package/dist/index.d.ts +178 -4
- package/dist/index.js +972 -19
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +952 -20
- package/dist/index.mjs.map +1 -1
- package/dist/next.d.mts +2 -17
- package/dist/next.d.ts +2 -17
- package/dist/next.js +262 -73
- package/dist/next.js.map +1 -1
- package/dist/next.mjs +262 -73
- package/dist/next.mjs.map +1 -1
- package/dist/nuxt.d.mts +13 -0
- package/dist/nuxt.d.ts +13 -0
- package/dist/nuxt.js +1344 -0
- package/dist/nuxt.js.map +1 -0
- package/dist/nuxt.mjs +1337 -0
- package/dist/nuxt.mjs.map +1 -0
- package/dist/react.d.mts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/{types-BTY-v-7i.d.mts → types-Cn_Qbkmg.d.mts} +34 -0
- package/dist/{types-BTY-v-7i.d.ts → types-Cn_Qbkmg.d.ts} +34 -0
- package/dist/vite.d.mts +5 -0
- package/dist/vite.d.ts +5 -0
- package/dist/vite.js +1370 -0
- package/dist/vite.js.map +1 -0
- package/dist/vite.mjs +1366 -0
- package/dist/vite.mjs.map +1 -0
- package/dist/vue.d.mts +19 -0
- package/dist/vue.d.ts +19 -0
- package/dist/vue.js +1078 -0
- package/dist/vue.js.map +1 -0
- package/dist/vue.mjs +1072 -0
- package/dist/vue.mjs.map +1 -0
- package/dist/webpack.d.mts +1 -1
- package/dist/webpack.d.ts +1 -1
- package/dist/webpack.js +178 -18
- package/dist/webpack.js.map +1 -1
- package/dist/webpack.mjs +178 -18
- package/dist/webpack.mjs.map +1 -1
- package/dist/widget.d.mts +1 -1
- package/dist/widget.d.ts +1 -1
- package/package.json +48 -2
package/dist/astro.js
CHANGED
|
@@ -166,7 +166,7 @@ function detectFramework(projectRoot = process.cwd()) {
|
|
|
166
166
|
};
|
|
167
167
|
}
|
|
168
168
|
function resolveConfig(config = {}) {
|
|
169
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
|
|
169
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M;
|
|
170
170
|
const frameworkInfo = detectFramework();
|
|
171
171
|
return {
|
|
172
172
|
title: config.title || "My Site",
|
|
@@ -182,26 +182,43 @@ function resolveConfig(config = {}) {
|
|
|
182
182
|
rawMarkdown: ((_d = config.generators) == null ? void 0 : _d.rawMarkdown) !== false,
|
|
183
183
|
manifest: ((_e = config.generators) == null ? void 0 : _e.manifest) !== false,
|
|
184
184
|
sitemap: ((_f = config.generators) == null ? void 0 : _f.sitemap) !== false,
|
|
185
|
-
aiIndex: ((_g = config.generators) == null ? void 0 : _g.aiIndex) !== false
|
|
185
|
+
aiIndex: ((_g = config.generators) == null ? void 0 : _g.aiIndex) !== false,
|
|
186
|
+
schema: ((_h = config.generators) == null ? void 0 : _h.schema) !== false
|
|
186
187
|
},
|
|
187
188
|
robots: {
|
|
188
|
-
allow: ((
|
|
189
|
-
disallow: ((
|
|
190
|
-
crawlDelay: ((
|
|
191
|
-
sitemap: ((
|
|
189
|
+
allow: ((_i = config.robots) == null ? void 0 : _i.allow) || ["/"],
|
|
190
|
+
disallow: ((_j = config.robots) == null ? void 0 : _j.disallow) || [],
|
|
191
|
+
crawlDelay: ((_k = config.robots) == null ? void 0 : _k.crawlDelay) || 0,
|
|
192
|
+
sitemap: ((_l = config.robots) == null ? void 0 : _l.sitemap) || ""
|
|
193
|
+
},
|
|
194
|
+
schema: {
|
|
195
|
+
enabled: ((_m = config.schema) == null ? void 0 : _m.enabled) !== false,
|
|
196
|
+
organization: {
|
|
197
|
+
name: ((_o = (_n = config.schema) == null ? void 0 : _n.organization) == null ? void 0 : _o.name) || config.title || "My Site",
|
|
198
|
+
url: ((_q = (_p = config.schema) == null ? void 0 : _p.organization) == null ? void 0 : _q.url) || config.url || "https://example.com",
|
|
199
|
+
logo: ((_s = (_r = config.schema) == null ? void 0 : _r.organization) == null ? void 0 : _s.logo) || "",
|
|
200
|
+
sameAs: ((_u = (_t = config.schema) == null ? void 0 : _t.organization) == null ? void 0 : _u.sameAs) || []
|
|
201
|
+
},
|
|
202
|
+
defaultType: ((_v = config.schema) == null ? void 0 : _v.defaultType) || "WebPage"
|
|
203
|
+
},
|
|
204
|
+
og: {
|
|
205
|
+
enabled: ((_w = config.og) == null ? void 0 : _w.enabled) !== false,
|
|
206
|
+
image: ((_x = config.og) == null ? void 0 : _x.image) || "",
|
|
207
|
+
twitterHandle: ((_y = config.og) == null ? void 0 : _y.twitterHandle) || "",
|
|
208
|
+
type: ((_z = config.og) == null ? void 0 : _z.type) || "website"
|
|
192
209
|
},
|
|
193
210
|
widget: {
|
|
194
|
-
enabled: ((
|
|
195
|
-
position: ((
|
|
211
|
+
enabled: ((_A = config.widget) == null ? void 0 : _A.enabled) !== false,
|
|
212
|
+
position: ((_B = config.widget) == null ? void 0 : _B.position) || "bottom-right",
|
|
196
213
|
theme: {
|
|
197
|
-
background: ((
|
|
198
|
-
text: ((
|
|
199
|
-
accent: ((
|
|
200
|
-
badge: ((
|
|
214
|
+
background: ((_D = (_C = config.widget) == null ? void 0 : _C.theme) == null ? void 0 : _D.background) || "rgba(18, 18, 24, 0.9)",
|
|
215
|
+
text: ((_F = (_E = config.widget) == null ? void 0 : _E.theme) == null ? void 0 : _F.text) || "#C0C0C5",
|
|
216
|
+
accent: ((_H = (_G = config.widget) == null ? void 0 : _G.theme) == null ? void 0 : _H.accent) || "#E8E8EA",
|
|
217
|
+
badge: ((_J = (_I = config.widget) == null ? void 0 : _I.theme) == null ? void 0 : _J.badge) || "#4ADE80"
|
|
201
218
|
},
|
|
202
|
-
humanLabel: ((
|
|
203
|
-
aiLabel: ((
|
|
204
|
-
showBadge: ((
|
|
219
|
+
humanLabel: ((_K = config.widget) == null ? void 0 : _K.humanLabel) || "Human",
|
|
220
|
+
aiLabel: ((_L = config.widget) == null ? void 0 : _L.aiLabel) || "AI",
|
|
221
|
+
showBadge: ((_M = config.widget) == null ? void 0 : _M.showBadge) !== false
|
|
205
222
|
}
|
|
206
223
|
};
|
|
207
224
|
}
|
|
@@ -500,8 +517,8 @@ function generatePageMarkdownFiles(config) {
|
|
|
500
517
|
const generated = [];
|
|
501
518
|
const pages = config.pages || [];
|
|
502
519
|
for (const page of pages) {
|
|
520
|
+
if (!page.content) continue;
|
|
503
521
|
const pageTitle = page.title || (page.pathname === "/" ? config.title : void 0);
|
|
504
|
-
if (!page.content && !pageTitle) continue;
|
|
505
522
|
let filename;
|
|
506
523
|
if (page.pathname === "/") {
|
|
507
524
|
filename = "index.md";
|
|
@@ -771,6 +788,147 @@ function generateAIIndex(config) {
|
|
|
771
788
|
};
|
|
772
789
|
return JSON.stringify(index, null, 2);
|
|
773
790
|
}
|
|
791
|
+
|
|
792
|
+
// src/core/schema.ts
|
|
793
|
+
function generateSchema(config) {
|
|
794
|
+
const output = generateSchemaObjects(config);
|
|
795
|
+
return JSON.stringify(output, null, 2);
|
|
796
|
+
}
|
|
797
|
+
function generateSchemaObjects(config) {
|
|
798
|
+
const siteSchemas = generateSiteSchemas(config);
|
|
799
|
+
const pageSchemas = {};
|
|
800
|
+
for (const page of config.pages) {
|
|
801
|
+
const schemas = generatePageSchemas(page, config);
|
|
802
|
+
if (schemas.length > 0) {
|
|
803
|
+
pageSchemas[page.pathname] = schemas;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
return { site: siteSchemas, pages: pageSchemas };
|
|
807
|
+
}
|
|
808
|
+
function generateSiteSchemas(config) {
|
|
809
|
+
const schemas = [];
|
|
810
|
+
schemas.push({
|
|
811
|
+
"@context": "https://schema.org",
|
|
812
|
+
"@type": "WebSite",
|
|
813
|
+
name: config.title,
|
|
814
|
+
description: config.description || void 0,
|
|
815
|
+
url: config.url
|
|
816
|
+
});
|
|
817
|
+
const org = config.schema.organization;
|
|
818
|
+
if (org.name || org.sameAs.length > 0) {
|
|
819
|
+
const orgSchema = {
|
|
820
|
+
"@context": "https://schema.org",
|
|
821
|
+
"@type": "Organization",
|
|
822
|
+
name: org.name,
|
|
823
|
+
url: org.url
|
|
824
|
+
};
|
|
825
|
+
if (org.logo) orgSchema.logo = org.logo;
|
|
826
|
+
if (org.sameAs.length > 0) orgSchema.sameAs = org.sameAs;
|
|
827
|
+
schemas.push(orgSchema);
|
|
828
|
+
}
|
|
829
|
+
return schemas;
|
|
830
|
+
}
|
|
831
|
+
function generatePageSchemas(page, config) {
|
|
832
|
+
const schemas = [];
|
|
833
|
+
const pageUrl = page.pathname === "/" ? config.url : `${config.url.replace(/\/$/, "")}${page.pathname}`;
|
|
834
|
+
const faqItems = detectFaqPatterns(page.content || "");
|
|
835
|
+
if (faqItems.length > 0) {
|
|
836
|
+
schemas.push({
|
|
837
|
+
"@context": "https://schema.org",
|
|
838
|
+
"@type": "FAQPage",
|
|
839
|
+
mainEntity: faqItems.map(({ question, answer }) => ({
|
|
840
|
+
"@type": "Question",
|
|
841
|
+
name: question,
|
|
842
|
+
acceptedAnswer: {
|
|
843
|
+
"@type": "Answer",
|
|
844
|
+
text: answer
|
|
845
|
+
}
|
|
846
|
+
}))
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
const pageType = config.schema.defaultType;
|
|
850
|
+
const pageSchema = {
|
|
851
|
+
"@context": "https://schema.org",
|
|
852
|
+
"@type": pageType,
|
|
853
|
+
name: page.title || config.title,
|
|
854
|
+
url: pageUrl
|
|
855
|
+
};
|
|
856
|
+
if (page.description) pageSchema.description = page.description;
|
|
857
|
+
if (pageType === "Article") {
|
|
858
|
+
pageSchema.headline = page.title || config.title;
|
|
859
|
+
pageSchema.author = {
|
|
860
|
+
"@type": "Organization",
|
|
861
|
+
name: config.schema.organization.name
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
schemas.push(pageSchema);
|
|
865
|
+
if (page.pathname !== "/") {
|
|
866
|
+
const breadcrumbs = generateBreadcrumbs(page.pathname, config);
|
|
867
|
+
if (breadcrumbs.length > 1) {
|
|
868
|
+
schemas.push({
|
|
869
|
+
"@context": "https://schema.org",
|
|
870
|
+
"@type": "BreadcrumbList",
|
|
871
|
+
itemListElement: breadcrumbs.map((crumb, i) => ({
|
|
872
|
+
"@type": "ListItem",
|
|
873
|
+
position: i + 1,
|
|
874
|
+
name: crumb.name,
|
|
875
|
+
item: crumb.url
|
|
876
|
+
}))
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
return schemas;
|
|
881
|
+
}
|
|
882
|
+
function generateBreadcrumbs(pathname, config) {
|
|
883
|
+
const baseUrl = config.url.replace(/\/$/, "");
|
|
884
|
+
const parts = pathname.split("/").filter(Boolean);
|
|
885
|
+
const crumbs = [
|
|
886
|
+
{ name: "Home", url: baseUrl + "/" }
|
|
887
|
+
];
|
|
888
|
+
let currentPath = "";
|
|
889
|
+
for (const part of parts) {
|
|
890
|
+
currentPath += "/" + part;
|
|
891
|
+
crumbs.push({
|
|
892
|
+
name: part.charAt(0).toUpperCase() + part.slice(1).replace(/-/g, " "),
|
|
893
|
+
url: baseUrl + currentPath
|
|
894
|
+
});
|
|
895
|
+
}
|
|
896
|
+
return crumbs;
|
|
897
|
+
}
|
|
898
|
+
function detectFaqPatterns(content) {
|
|
899
|
+
const items = [];
|
|
900
|
+
const lines = content.split("\n");
|
|
901
|
+
for (let i = 0; i < lines.length; i++) {
|
|
902
|
+
const line = lines[i].trim();
|
|
903
|
+
const headingMatch = line.match(/^#{1,6}\s+(.+\?)\s*$/);
|
|
904
|
+
if (headingMatch) {
|
|
905
|
+
const answerLines = [];
|
|
906
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
907
|
+
const nextLine = lines[j].trim();
|
|
908
|
+
if (!nextLine) {
|
|
909
|
+
if (answerLines.length > 0) break;
|
|
910
|
+
continue;
|
|
911
|
+
}
|
|
912
|
+
if (/^#{1,6}\s/.test(nextLine)) break;
|
|
913
|
+
answerLines.push(nextLine);
|
|
914
|
+
}
|
|
915
|
+
if (answerLines.length > 0) {
|
|
916
|
+
items.push({
|
|
917
|
+
question: headingMatch[1],
|
|
918
|
+
answer: answerLines.join(" ").slice(0, 500)
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
return items;
|
|
924
|
+
}
|
|
925
|
+
function generateJsonLdScript(schemas) {
|
|
926
|
+
if (schemas.length === 0) return "";
|
|
927
|
+
if (schemas.length === 1) {
|
|
928
|
+
return `<script type="application/ld+json">${JSON.stringify(schemas[0])}</script>`;
|
|
929
|
+
}
|
|
930
|
+
return schemas.map((s) => `<script type="application/ld+json">${JSON.stringify(s)}</script>`).join("\n");
|
|
931
|
+
}
|
|
774
932
|
async function generateAEOFiles(configOrRoot, maybeConfig) {
|
|
775
933
|
var _a;
|
|
776
934
|
let config;
|
|
@@ -799,7 +957,7 @@ async function generateAEOFiles(configOrRoot, maybeConfig) {
|
|
|
799
957
|
if (config.generators.llmsTxt) {
|
|
800
958
|
try {
|
|
801
959
|
const content = generateLlmsTxt(config);
|
|
802
|
-
fs.writeFileSync(path.join(outDir, "llms.txt"),
|
|
960
|
+
fs.writeFileSync(path.join(outDir, "llms.txt"), content, "utf-8");
|
|
803
961
|
files.push("llms.txt");
|
|
804
962
|
} catch (e) {
|
|
805
963
|
errors.push(`llms.txt: ${e.message}`);
|
|
@@ -808,7 +966,7 @@ async function generateAEOFiles(configOrRoot, maybeConfig) {
|
|
|
808
966
|
if (config.generators.llmsFullTxt) {
|
|
809
967
|
try {
|
|
810
968
|
const content = generateLlmsFullTxt(config);
|
|
811
|
-
fs.writeFileSync(path.join(outDir, "llms-full.txt"),
|
|
969
|
+
fs.writeFileSync(path.join(outDir, "llms-full.txt"), content, "utf-8");
|
|
812
970
|
files.push("llms-full.txt");
|
|
813
971
|
} catch (e) {
|
|
814
972
|
errors.push(`llms-full.txt: ${e.message}`);
|
|
@@ -859,12 +1017,131 @@ async function generateAEOFiles(configOrRoot, maybeConfig) {
|
|
|
859
1017
|
errors.push(`ai-index.json: ${e.message}`);
|
|
860
1018
|
}
|
|
861
1019
|
}
|
|
1020
|
+
if (config.generators.schema && config.schema.enabled) {
|
|
1021
|
+
try {
|
|
1022
|
+
const content = generateSchema(config);
|
|
1023
|
+
fs.writeFileSync(path.join(outDir, "schema.json"), content, "utf-8");
|
|
1024
|
+
files.push("schema.json");
|
|
1025
|
+
} catch (e) {
|
|
1026
|
+
errors.push(`schema.json: ${e.message}`);
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
862
1029
|
return { files, errors };
|
|
863
1030
|
}
|
|
1031
|
+
|
|
1032
|
+
// src/core/html-extract.ts
|
|
1033
|
+
function extractTextFromHtml(html) {
|
|
1034
|
+
let text = html;
|
|
1035
|
+
text = text.replace(/<script[\s\S]*?<\/script>/gi, "");
|
|
1036
|
+
text = text.replace(/<style[\s\S]*?<\/style>/gi, "");
|
|
1037
|
+
text = text.replace(/<svg[\s\S]*?<\/svg>/gi, "");
|
|
1038
|
+
const mainMatch = text.match(/<main[^>]*>([\s\S]*)<\/main>/i);
|
|
1039
|
+
if (mainMatch) {
|
|
1040
|
+
text = mainMatch[1];
|
|
1041
|
+
} else {
|
|
1042
|
+
text = text.replace(/<nav[\s\S]*?<\/nav>/gi, "");
|
|
1043
|
+
text = text.replace(/<header[\s\S]*?<\/header>/gi, "");
|
|
1044
|
+
text = text.replace(/<footer[\s\S]*?<\/footer>/gi, "");
|
|
1045
|
+
}
|
|
1046
|
+
text = text.replace(/<a[^>]+href=["']([^"']*)["'][^>]*>([\s\S]*?)<\/a>/gi, (_, url, inner) => {
|
|
1047
|
+
if (/<(?:h[1-6]|div|p|section)[^>]*>/i.test(inner)) {
|
|
1048
|
+
const cleanInner = inner.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
1049
|
+
return `
|
|
1050
|
+
[${cleanInner.slice(0, 120).trim()}](${url})
|
|
1051
|
+
`;
|
|
1052
|
+
}
|
|
1053
|
+
return `[${inner}](${url})`;
|
|
1054
|
+
});
|
|
1055
|
+
text = text.replace(/<h1[^>]*>([\s\S]*?)<\/h1>/gi, "\n\n## $1\n\n");
|
|
1056
|
+
text = text.replace(/<h2[^>]*>([\s\S]*?)<\/h2>/gi, "\n\n## $1\n\n");
|
|
1057
|
+
text = text.replace(/<h3[^>]*>([\s\S]*?)<\/h3>/gi, "\n\n### $1\n\n");
|
|
1058
|
+
text = text.replace(/<h4[^>]*>([\s\S]*?)<\/h4>/gi, "\n\n#### $1\n\n");
|
|
1059
|
+
text = text.replace(/<h5[^>]*>([\s\S]*?)<\/h5>/gi, "\n\n##### $1\n\n");
|
|
1060
|
+
text = text.replace(/<h6[^>]*>([\s\S]*?)<\/h6>/gi, "\n\n###### $1\n\n");
|
|
1061
|
+
text = text.replace(/<a[^>]+href=["']([^"']*)["'][^>]*>([\s\S]*?)<\/a>/gi, "[$2]($1)");
|
|
1062
|
+
text = text.replace(/<(?:strong|b)[^>]*>([\s\S]*?)<\/(?:strong|b)>/gi, "**$1**");
|
|
1063
|
+
text = text.replace(/<(?:em|i)[^>]*>([\s\S]*?)<\/(?:em|i)>/gi, "*$1*");
|
|
1064
|
+
text = text.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, "\n- $1");
|
|
1065
|
+
text = text.replace(/<blockquote[^>]*>([\s\S]*?)<\/blockquote>/gi, "\n\n> $1\n\n");
|
|
1066
|
+
text = text.replace(/<hr[^>]*\/?>/gi, "\n\n---\n\n");
|
|
1067
|
+
text = text.replace(/<br[^>]*\/?>/gi, "\n");
|
|
1068
|
+
text = text.replace(/<\/p>/gi, "\n\n");
|
|
1069
|
+
text = text.replace(/<p[^>]*>/gi, "");
|
|
1070
|
+
text = text.replace(/<\/?(?:div|section|article|header|main|aside|figure|figcaption|table|thead|tbody|tr|td|th|ul|ol|dl|dt|dd)[^>]*>/gi, "\n");
|
|
1071
|
+
text = text.replace(/<[^>]+>/g, "");
|
|
1072
|
+
text = text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/ /g, " ").replace(/©/g, "(c)");
|
|
1073
|
+
text = text.replace(/[\u{1F1E0}-\u{1FAFF}\u{2600}-\u{27BF}\u{FE00}-\u{FE0F}\u{200D}\u{20E3}]/gu, "");
|
|
1074
|
+
text = text.split("\n").map((l) => l.replace(/\s+/g, " ").trim()).join("\n");
|
|
1075
|
+
text = text.replace(/\n{3,}/g, "\n\n");
|
|
1076
|
+
text = text.replace(/\[[\s\n]+/g, "[").replace(/[\s\n]+\]/g, "]");
|
|
1077
|
+
text = text.replace(/(#{2,6})\s*\n+\s*/g, "$1 ");
|
|
1078
|
+
text = text.replace(/^#{2,6}\s*$/gm, "");
|
|
1079
|
+
text = text.replace(/\n{3,}/g, "\n\n");
|
|
1080
|
+
return text.trim().slice(0, 8e3);
|
|
1081
|
+
}
|
|
1082
|
+
function extractTitle2(html) {
|
|
1083
|
+
var _a, _b;
|
|
1084
|
+
const match = html.match(/<title>([^<]*)<\/title>/i);
|
|
1085
|
+
if (!match) return void 0;
|
|
1086
|
+
return ((_b = (_a = match[1]) == null ? void 0 : _a.split("|")[0]) == null ? void 0 : _b.trim()) || match[1];
|
|
1087
|
+
}
|
|
1088
|
+
function extractDescription(html) {
|
|
1089
|
+
const match = html.match(/<meta\s+name=["']description["']\s+content=["']([^"']*)["']/i);
|
|
1090
|
+
return match == null ? void 0 : match[1];
|
|
1091
|
+
}
|
|
1092
|
+
function htmlToMarkdown(html, pagePath, config) {
|
|
1093
|
+
const rawTitle = extractTitle2(html);
|
|
1094
|
+
const description = extractDescription(html);
|
|
1095
|
+
const textContent = extractTextFromHtml(html);
|
|
1096
|
+
const pageUrl = pagePath === "/" ? config.url : `${config.url.replace(/\/$/, "")}${pagePath}`;
|
|
1097
|
+
const lines = [];
|
|
1098
|
+
lines.push("---");
|
|
1099
|
+
if (rawTitle) lines.push(`title: "${rawTitle}"`);
|
|
1100
|
+
if (description) lines.push(`description: "${description}"`);
|
|
1101
|
+
lines.push(`url: ${pageUrl}`);
|
|
1102
|
+
lines.push(`source: ${pageUrl}`);
|
|
1103
|
+
lines.push(`generated_by: aeo.js`);
|
|
1104
|
+
lines.push("---", "");
|
|
1105
|
+
if (rawTitle) lines.push(`# ${rawTitle}`, "");
|
|
1106
|
+
if (description) lines.push(`${description}`, "");
|
|
1107
|
+
if (textContent) lines.push(textContent);
|
|
1108
|
+
return lines.join("\n");
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
// src/core/opengraph.ts
|
|
1112
|
+
function generateOGTags(page, config) {
|
|
1113
|
+
const tags = [];
|
|
1114
|
+
const pageUrl = page.pathname === "/" ? config.url : `${config.url.replace(/\/$/, "")}${page.pathname}`;
|
|
1115
|
+
const title = page.title || config.title;
|
|
1116
|
+
const description = page.description || config.description;
|
|
1117
|
+
tags.push({ property: "og:type", content: config.og.type });
|
|
1118
|
+
tags.push({ property: "og:title", content: title });
|
|
1119
|
+
if (description) tags.push({ property: "og:description", content: description });
|
|
1120
|
+
tags.push({ property: "og:url", content: pageUrl });
|
|
1121
|
+
tags.push({ property: "og:site_name", content: config.title });
|
|
1122
|
+
if (config.og.image) tags.push({ property: "og:image", content: config.og.image });
|
|
1123
|
+
tags.push({ name: "twitter:card", content: config.og.image ? "summary_large_image" : "summary" });
|
|
1124
|
+
tags.push({ name: "twitter:title", content: title });
|
|
1125
|
+
if (description) tags.push({ name: "twitter:description", content: description });
|
|
1126
|
+
if (config.og.twitterHandle) tags.push({ name: "twitter:site", content: config.og.twitterHandle });
|
|
1127
|
+
if (config.og.image) tags.push({ name: "twitter:image", content: config.og.image });
|
|
1128
|
+
return tags;
|
|
1129
|
+
}
|
|
1130
|
+
function generateOGTagsHtml(page, config) {
|
|
1131
|
+
const tags = generateOGTags(page, config);
|
|
1132
|
+
return tags.map((tag) => {
|
|
1133
|
+
if (tag.property) return `<meta property="${tag.property}" content="${escapeAttr(tag.content)}" />`;
|
|
1134
|
+
return `<meta name="${tag.name}" content="${escapeAttr(tag.content)}" />`;
|
|
1135
|
+
}).join("\n ");
|
|
1136
|
+
}
|
|
1137
|
+
function escapeAttr(str) {
|
|
1138
|
+
return str.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
// src/plugins/astro.ts
|
|
864
1142
|
function scanBuiltPages(dir, baseUrl) {
|
|
865
1143
|
const pages = [];
|
|
866
1144
|
function walk(currentDir) {
|
|
867
|
-
var _a;
|
|
868
1145
|
try {
|
|
869
1146
|
const entries = fs.readdirSync(currentDir);
|
|
870
1147
|
for (const entry of entries) {
|
|
@@ -875,8 +1152,8 @@ function scanBuiltPages(dir, baseUrl) {
|
|
|
875
1152
|
} else if (entry === "index.html" || entry.endsWith(".html") && entry !== "404.html" && entry !== "500.html") {
|
|
876
1153
|
try {
|
|
877
1154
|
const html = fs.readFileSync(fullPath, "utf-8");
|
|
878
|
-
const
|
|
879
|
-
const
|
|
1155
|
+
const title = extractTitle2(html);
|
|
1156
|
+
const description = extractDescription(html);
|
|
880
1157
|
const textContent = extractTextFromHtml(html);
|
|
881
1158
|
let pathname;
|
|
882
1159
|
const relative8 = fullPath.slice(dir.length);
|
|
@@ -887,12 +1164,10 @@ function scanBuiltPages(dir, baseUrl) {
|
|
|
887
1164
|
pathname = "/" + relative8.replace(/\.html$/, "");
|
|
888
1165
|
}
|
|
889
1166
|
pathname = pathname.replace(/\/+/g, "/") || "/";
|
|
890
|
-
const rawTitle = titleMatch ? titleMatch[1] : void 0;
|
|
891
|
-
const title = ((_a = rawTitle == null ? void 0 : rawTitle.split("|")[0]) == null ? void 0 : _a.trim()) || rawTitle;
|
|
892
1167
|
pages.push({
|
|
893
1168
|
pathname,
|
|
894
1169
|
title,
|
|
895
|
-
description
|
|
1170
|
+
description,
|
|
896
1171
|
content: textContent
|
|
897
1172
|
});
|
|
898
1173
|
} catch {
|
|
@@ -937,76 +1212,6 @@ function scanDevPages(pagesDir) {
|
|
|
937
1212
|
}
|
|
938
1213
|
return pages;
|
|
939
1214
|
}
|
|
940
|
-
function extractTextFromHtml(html) {
|
|
941
|
-
let text = html;
|
|
942
|
-
text = text.replace(/<script[\s\S]*?<\/script>/gi, "");
|
|
943
|
-
text = text.replace(/<style[\s\S]*?<\/style>/gi, "");
|
|
944
|
-
text = text.replace(/<svg[\s\S]*?<\/svg>/gi, "");
|
|
945
|
-
const mainMatch = text.match(/<main[^>]*>([\s\S]*)<\/main>/i);
|
|
946
|
-
if (mainMatch) {
|
|
947
|
-
text = mainMatch[1];
|
|
948
|
-
} else {
|
|
949
|
-
text = text.replace(/<nav[\s\S]*?<\/nav>/gi, "");
|
|
950
|
-
text = text.replace(/<header[\s\S]*?<\/header>/gi, "");
|
|
951
|
-
text = text.replace(/<footer[\s\S]*?<\/footer>/gi, "");
|
|
952
|
-
}
|
|
953
|
-
text = text.replace(/<a[^>]+href=["']([^"']*)["'][^>]*>([\s\S]*?)<\/a>/gi, (_, url, inner) => {
|
|
954
|
-
if (/<(?:h[1-6]|div|p|section)[^>]*>/i.test(inner)) {
|
|
955
|
-
const cleanInner = inner.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
956
|
-
return `
|
|
957
|
-
[${cleanInner.slice(0, 120).trim()}](${url})
|
|
958
|
-
`;
|
|
959
|
-
}
|
|
960
|
-
return `[${inner}](${url})`;
|
|
961
|
-
});
|
|
962
|
-
text = text.replace(/<h1[^>]*>([\s\S]*?)<\/h1>/gi, "\n\n## $1\n\n");
|
|
963
|
-
text = text.replace(/<h2[^>]*>([\s\S]*?)<\/h2>/gi, "\n\n## $1\n\n");
|
|
964
|
-
text = text.replace(/<h3[^>]*>([\s\S]*?)<\/h3>/gi, "\n\n### $1\n\n");
|
|
965
|
-
text = text.replace(/<h4[^>]*>([\s\S]*?)<\/h4>/gi, "\n\n#### $1\n\n");
|
|
966
|
-
text = text.replace(/<h5[^>]*>([\s\S]*?)<\/h5>/gi, "\n\n##### $1\n\n");
|
|
967
|
-
text = text.replace(/<h6[^>]*>([\s\S]*?)<\/h6>/gi, "\n\n###### $1\n\n");
|
|
968
|
-
text = text.replace(/<a[^>]+href=["']([^"']*)["'][^>]*>([\s\S]*?)<\/a>/gi, "[$2]($1)");
|
|
969
|
-
text = text.replace(/<(?:strong|b)[^>]*>([\s\S]*?)<\/(?:strong|b)>/gi, "**$1**");
|
|
970
|
-
text = text.replace(/<(?:em|i)[^>]*>([\s\S]*?)<\/(?:em|i)>/gi, "*$1*");
|
|
971
|
-
text = text.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, "\n- $1");
|
|
972
|
-
text = text.replace(/<blockquote[^>]*>([\s\S]*?)<\/blockquote>/gi, "\n\n> $1\n\n");
|
|
973
|
-
text = text.replace(/<hr[^>]*\/?>/gi, "\n\n---\n\n");
|
|
974
|
-
text = text.replace(/<br[^>]*\/?>/gi, "\n");
|
|
975
|
-
text = text.replace(/<\/p>/gi, "\n\n");
|
|
976
|
-
text = text.replace(/<p[^>]*>/gi, "");
|
|
977
|
-
text = text.replace(/<\/?(?:div|section|article|header|main|aside|figure|figcaption|table|thead|tbody|tr|td|th|ul|ol|dl|dt|dd)[^>]*>/gi, "\n");
|
|
978
|
-
text = text.replace(/<[^>]+>/g, "");
|
|
979
|
-
text = text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/ /g, " ").replace(/©/g, "(c)");
|
|
980
|
-
text = text.replace(/[\u{1F1E0}-\u{1FAFF}\u{2600}-\u{27BF}\u{FE00}-\u{FE0F}\u{200D}\u{20E3}]/gu, "");
|
|
981
|
-
text = text.split("\n").map((l) => l.replace(/\s+/g, " ").trim()).join("\n");
|
|
982
|
-
text = text.replace(/\n{3,}/g, "\n\n");
|
|
983
|
-
text = text.replace(/\[[\s\n]+/g, "[").replace(/[\s\n]+\]/g, "]");
|
|
984
|
-
text = text.replace(/(#{2,6})\s*\n+\s*/g, "$1 ");
|
|
985
|
-
text = text.replace(/^#{2,6}\s*$/gm, "");
|
|
986
|
-
text = text.replace(/\n{3,}/g, "\n\n");
|
|
987
|
-
return text.trim().slice(0, 8e3);
|
|
988
|
-
}
|
|
989
|
-
function htmlToMarkdown(html, pagePath, config) {
|
|
990
|
-
var _a, _b;
|
|
991
|
-
const titleMatch = html.match(/<title>([^<]*)<\/title>/i);
|
|
992
|
-
const descMatch = html.match(/<meta\s+name=["']description["']\s+content=["']([^"']*)["']/i);
|
|
993
|
-
const textContent = extractTextFromHtml(html);
|
|
994
|
-
const rawTitle = titleMatch ? (_b = (_a = titleMatch[1]) == null ? void 0 : _a.split("|")[0]) == null ? void 0 : _b.trim() : void 0;
|
|
995
|
-
const description = descMatch == null ? void 0 : descMatch[1];
|
|
996
|
-
const pageUrl = pagePath === "/" ? config.url : `${config.url.replace(/\/$/, "")}${pagePath}`;
|
|
997
|
-
const lines = [];
|
|
998
|
-
lines.push("---");
|
|
999
|
-
if (rawTitle) lines.push(`title: "${rawTitle}"`);
|
|
1000
|
-
if (description) lines.push(`description: "${description}"`);
|
|
1001
|
-
lines.push(`url: ${pageUrl}`);
|
|
1002
|
-
lines.push(`source: ${pageUrl}`);
|
|
1003
|
-
lines.push(`generated_by: aeo.js`);
|
|
1004
|
-
lines.push("---", "");
|
|
1005
|
-
if (rawTitle) lines.push(`# ${rawTitle}`, "");
|
|
1006
|
-
if (description) lines.push(`${description}`, "");
|
|
1007
|
-
if (textContent) lines.push(textContent);
|
|
1008
|
-
return lines.join("\n");
|
|
1009
|
-
}
|
|
1010
1215
|
function aeoAstroIntegration(options = {}) {
|
|
1011
1216
|
let resolvedConfig = resolveConfig(options);
|
|
1012
1217
|
let astroConfig;
|
|
@@ -1027,14 +1232,33 @@ function aeoAstroIntegration(options = {}) {
|
|
|
1027
1232
|
}
|
|
1028
1233
|
}
|
|
1029
1234
|
if (resolvedConfig.widget.enabled && injectScript) {
|
|
1030
|
-
const
|
|
1235
|
+
const widgetConfig = JSON.stringify({
|
|
1236
|
+
title: resolvedConfig.title,
|
|
1237
|
+
description: resolvedConfig.description,
|
|
1238
|
+
url: resolvedConfig.url,
|
|
1239
|
+
widget: resolvedConfig.widget
|
|
1240
|
+
});
|
|
1031
1241
|
injectScript(
|
|
1032
1242
|
"page",
|
|
1033
1243
|
`import { AeoWidget } from 'aeo.js/widget';
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1244
|
+
let __aeoWidget;
|
|
1245
|
+
function __initAeoWidget() {
|
|
1246
|
+
if (__aeoWidget) __aeoWidget.destroy();
|
|
1247
|
+
try {
|
|
1248
|
+
__aeoWidget = new AeoWidget({ config: ${widgetConfig} });
|
|
1249
|
+
} catch (e) {
|
|
1250
|
+
console.warn('[aeo.js] Widget initialization failed:', e);
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
// astro:page-load fires on initial load AND after every View Transition navigation
|
|
1254
|
+
document.addEventListener('astro:page-load', __initAeoWidget);
|
|
1255
|
+
// Fallback for Astro sites without View Transitions
|
|
1256
|
+
if (!document.querySelector('meta[name="astro-view-transitions-enabled"]')) {
|
|
1257
|
+
if (document.readyState === 'loading') {
|
|
1258
|
+
document.addEventListener('DOMContentLoaded', __initAeoWidget);
|
|
1259
|
+
} else {
|
|
1260
|
+
__initAeoWidget();
|
|
1261
|
+
}
|
|
1038
1262
|
}`
|
|
1039
1263
|
);
|
|
1040
1264
|
}
|
|
@@ -1154,8 +1378,24 @@ if (document.readyState === 'loading') {
|
|
|
1154
1378
|
}
|
|
1155
1379
|
};
|
|
1156
1380
|
}
|
|
1157
|
-
var AeoMetaTags = ({ config }) => {
|
|
1381
|
+
var AeoMetaTags = ({ config, page }) => {
|
|
1158
1382
|
const resolvedConfig = resolveConfig(config);
|
|
1383
|
+
const currentPage = page || { pathname: "/" };
|
|
1384
|
+
const pageEntry = {
|
|
1385
|
+
pathname: currentPage.pathname || "/",
|
|
1386
|
+
title: currentPage.title,
|
|
1387
|
+
description: currentPage.description,
|
|
1388
|
+
content: currentPage.content
|
|
1389
|
+
};
|
|
1390
|
+
let jsonLd = "";
|
|
1391
|
+
if (resolvedConfig.schema.enabled) {
|
|
1392
|
+
const schemas = generatePageSchemas(pageEntry, resolvedConfig);
|
|
1393
|
+
jsonLd = generateJsonLdScript(schemas);
|
|
1394
|
+
}
|
|
1395
|
+
let ogTags = "";
|
|
1396
|
+
if (resolvedConfig.og.enabled) {
|
|
1397
|
+
ogTags = generateOGTagsHtml(pageEntry, resolvedConfig);
|
|
1398
|
+
}
|
|
1159
1399
|
return `
|
|
1160
1400
|
<link rel="alternate" type="text/plain" href="/llms.txt" title="LLM Summary" />
|
|
1161
1401
|
<link rel="alternate" type="text/plain" href="/llms-full.txt" title="Full Content for LLMs" />
|
|
@@ -1164,6 +1404,8 @@ var AeoMetaTags = ({ config }) => {
|
|
|
1164
1404
|
<meta name="aeo:title" content="${resolvedConfig.title}" />
|
|
1165
1405
|
<meta name="aeo:description" content="${resolvedConfig.description}" />
|
|
1166
1406
|
<meta name="aeo:url" content="${resolvedConfig.url}" />
|
|
1407
|
+
${ogTags}
|
|
1408
|
+
${jsonLd}
|
|
1167
1409
|
`;
|
|
1168
1410
|
};
|
|
1169
1411
|
function defineAeoConfig(config) {
|