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.
Files changed (62) hide show
  1. package/README.md +132 -17
  2. package/dist/angular.d.mts +29 -0
  3. package/dist/angular.d.ts +29 -0
  4. package/dist/angular.js +1314 -0
  5. package/dist/angular.js.map +1 -0
  6. package/dist/angular.mjs +1310 -0
  7. package/dist/angular.mjs.map +1 -0
  8. package/dist/astro.d.mts +8 -2
  9. package/dist/astro.d.ts +8 -2
  10. package/dist/astro.js +342 -100
  11. package/dist/astro.js.map +1 -1
  12. package/dist/astro.mjs +342 -100
  13. package/dist/astro.mjs.map +1 -1
  14. package/dist/cli.d.mts +1 -0
  15. package/dist/cli.d.ts +1 -0
  16. package/dist/cli.js +1880 -0
  17. package/dist/cli.js.map +1 -0
  18. package/dist/cli.mjs +1878 -0
  19. package/dist/cli.mjs.map +1 -0
  20. package/dist/index.d.mts +178 -4
  21. package/dist/index.d.ts +178 -4
  22. package/dist/index.js +972 -19
  23. package/dist/index.js.map +1 -1
  24. package/dist/index.mjs +952 -20
  25. package/dist/index.mjs.map +1 -1
  26. package/dist/next.d.mts +2 -17
  27. package/dist/next.d.ts +2 -17
  28. package/dist/next.js +262 -73
  29. package/dist/next.js.map +1 -1
  30. package/dist/next.mjs +262 -73
  31. package/dist/next.mjs.map +1 -1
  32. package/dist/nuxt.d.mts +13 -0
  33. package/dist/nuxt.d.ts +13 -0
  34. package/dist/nuxt.js +1344 -0
  35. package/dist/nuxt.js.map +1 -0
  36. package/dist/nuxt.mjs +1337 -0
  37. package/dist/nuxt.mjs.map +1 -0
  38. package/dist/react.d.mts +1 -1
  39. package/dist/react.d.ts +1 -1
  40. package/dist/{types-BTY-v-7i.d.mts → types-Cn_Qbkmg.d.mts} +34 -0
  41. package/dist/{types-BTY-v-7i.d.ts → types-Cn_Qbkmg.d.ts} +34 -0
  42. package/dist/vite.d.mts +5 -0
  43. package/dist/vite.d.ts +5 -0
  44. package/dist/vite.js +1370 -0
  45. package/dist/vite.js.map +1 -0
  46. package/dist/vite.mjs +1366 -0
  47. package/dist/vite.mjs.map +1 -0
  48. package/dist/vue.d.mts +19 -0
  49. package/dist/vue.d.ts +19 -0
  50. package/dist/vue.js +1078 -0
  51. package/dist/vue.js.map +1 -0
  52. package/dist/vue.mjs +1072 -0
  53. package/dist/vue.mjs.map +1 -0
  54. package/dist/webpack.d.mts +1 -1
  55. package/dist/webpack.d.ts +1 -1
  56. package/dist/webpack.js +178 -18
  57. package/dist/webpack.js.map +1 -1
  58. package/dist/webpack.mjs +178 -18
  59. package/dist/webpack.mjs.map +1 -1
  60. package/dist/widget.d.mts +1 -1
  61. package/dist/widget.d.ts +1 -1
  62. package/package.json +48 -2
package/dist/next.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as AeoConfig } from './types-BTY-v-7i.mjs';
1
+ import { A as AeoConfig } from './types-Cn_Qbkmg.mjs';
2
2
 
3
3
  interface NextAeoConfig {
4
4
  aeo?: AeoConfig;
@@ -7,22 +7,7 @@ interface NextAeoConfig {
7
7
  [key: string]: any;
8
8
  }
9
9
  declare function withAeo(nextConfig?: NextAeoConfig): Record<string, any>;
10
- declare function generateAeoMetadata(config?: AeoConfig): Promise<{
11
- title: string;
12
- description: string;
13
- alternates: {
14
- types: {
15
- 'text/plain': {
16
- url: string;
17
- title: string;
18
- }[];
19
- 'application/json': {
20
- url: string;
21
- title: string;
22
- }[];
23
- };
24
- };
25
- }>;
10
+ declare function generateAeoMetadata(config?: AeoConfig): Promise<Record<string, any>>;
26
11
  /**
27
12
  * Post-build function that reads pre-rendered HTML from .next/server/
28
13
  * and regenerates AEO files with actual page content.
package/dist/next.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as AeoConfig } from './types-BTY-v-7i.js';
1
+ import { A as AeoConfig } from './types-Cn_Qbkmg.js';
2
2
 
3
3
  interface NextAeoConfig {
4
4
  aeo?: AeoConfig;
@@ -7,22 +7,7 @@ interface NextAeoConfig {
7
7
  [key: string]: any;
8
8
  }
9
9
  declare function withAeo(nextConfig?: NextAeoConfig): Record<string, any>;
10
- declare function generateAeoMetadata(config?: AeoConfig): Promise<{
11
- title: string;
12
- description: string;
13
- alternates: {
14
- types: {
15
- 'text/plain': {
16
- url: string;
17
- title: string;
18
- }[];
19
- 'application/json': {
20
- url: string;
21
- title: string;
22
- }[];
23
- };
24
- };
25
- }>;
10
+ declare function generateAeoMetadata(config?: AeoConfig): Promise<Record<string, any>>;
26
11
  /**
27
12
  * Post-build function that reads pre-rendered HTML from .next/server/
28
13
  * and regenerates AEO files with actual page content.
package/dist/next.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: ((_h = config.robots) == null ? void 0 : _h.allow) || ["/"],
189
- disallow: ((_i = config.robots) == null ? void 0 : _i.disallow) || [],
190
- crawlDelay: ((_j = config.robots) == null ? void 0 : _j.crawlDelay) || 0,
191
- sitemap: ((_k = config.robots) == null ? void 0 : _k.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: ((_l = config.widget) == null ? void 0 : _l.enabled) !== false,
195
- position: ((_m = config.widget) == null ? void 0 : _m.position) || "bottom-right",
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: ((_o = (_n = config.widget) == null ? void 0 : _n.theme) == null ? void 0 : _o.background) || "rgba(18, 18, 24, 0.9)",
198
- text: ((_q = (_p = config.widget) == null ? void 0 : _p.theme) == null ? void 0 : _q.text) || "#C0C0C5",
199
- accent: ((_s = (_r = config.widget) == null ? void 0 : _r.theme) == null ? void 0 : _s.accent) || "#E8E8EA",
200
- badge: ((_u = (_t = config.widget) == null ? void 0 : _t.theme) == null ? void 0 : _u.badge) || "#4ADE80"
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: ((_v = config.widget) == null ? void 0 : _v.humanLabel) || "Human",
203
- aiLabel: ((_w = config.widget) == null ? void 0 : _w.aiLabel) || "AI",
204
- showBadge: ((_x = config.widget) == null ? void 0 : _x.showBadge) !== false
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,140 @@ 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
+ }
774
925
  async function generateAEOFiles(configOrRoot, maybeConfig) {
775
926
  var _a;
776
927
  let config;
@@ -799,7 +950,7 @@ async function generateAEOFiles(configOrRoot, maybeConfig) {
799
950
  if (config.generators.llmsTxt) {
800
951
  try {
801
952
  const content = generateLlmsTxt(config);
802
- fs.writeFileSync(path.join(outDir, "llms.txt"), "\uFEFF" + content, "utf-8");
953
+ fs.writeFileSync(path.join(outDir, "llms.txt"), content, "utf-8");
803
954
  files.push("llms.txt");
804
955
  } catch (e) {
805
956
  errors.push(`llms.txt: ${e.message}`);
@@ -808,7 +959,7 @@ async function generateAEOFiles(configOrRoot, maybeConfig) {
808
959
  if (config.generators.llmsFullTxt) {
809
960
  try {
810
961
  const content = generateLlmsFullTxt(config);
811
- fs.writeFileSync(path.join(outDir, "llms-full.txt"), "\uFEFF" + content, "utf-8");
962
+ fs.writeFileSync(path.join(outDir, "llms-full.txt"), content, "utf-8");
812
963
  files.push("llms-full.txt");
813
964
  } catch (e) {
814
965
  errors.push(`llms-full.txt: ${e.message}`);
@@ -859,8 +1010,78 @@ async function generateAEOFiles(configOrRoot, maybeConfig) {
859
1010
  errors.push(`ai-index.json: ${e.message}`);
860
1011
  }
861
1012
  }
1013
+ if (config.generators.schema && config.schema.enabled) {
1014
+ try {
1015
+ const content = generateSchema(config);
1016
+ fs.writeFileSync(path.join(outDir, "schema.json"), content, "utf-8");
1017
+ files.push("schema.json");
1018
+ } catch (e) {
1019
+ errors.push(`schema.json: ${e.message}`);
1020
+ }
1021
+ }
862
1022
  return { files, errors };
863
1023
  }
1024
+
1025
+ // src/core/html-extract.ts
1026
+ function extractTextFromHtml(html) {
1027
+ let text = html;
1028
+ text = text.replace(/<script[\s\S]*?<\/script>/gi, "");
1029
+ text = text.replace(/<style[\s\S]*?<\/style>/gi, "");
1030
+ text = text.replace(/<svg[\s\S]*?<\/svg>/gi, "");
1031
+ const mainMatch = text.match(/<main[^>]*>([\s\S]*)<\/main>/i);
1032
+ if (mainMatch) {
1033
+ text = mainMatch[1];
1034
+ } else {
1035
+ text = text.replace(/<nav[\s\S]*?<\/nav>/gi, "");
1036
+ text = text.replace(/<header[\s\S]*?<\/header>/gi, "");
1037
+ text = text.replace(/<footer[\s\S]*?<\/footer>/gi, "");
1038
+ }
1039
+ text = text.replace(/<a[^>]+href=["']([^"']*)["'][^>]*>([\s\S]*?)<\/a>/gi, (_, url, inner) => {
1040
+ if (/<(?:h[1-6]|div|p|section)[^>]*>/i.test(inner)) {
1041
+ const cleanInner = inner.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
1042
+ return `
1043
+ [${cleanInner.slice(0, 120).trim()}](${url})
1044
+ `;
1045
+ }
1046
+ return `[${inner}](${url})`;
1047
+ });
1048
+ text = text.replace(/<h1[^>]*>([\s\S]*?)<\/h1>/gi, "\n\n## $1\n\n");
1049
+ text = text.replace(/<h2[^>]*>([\s\S]*?)<\/h2>/gi, "\n\n## $1\n\n");
1050
+ text = text.replace(/<h3[^>]*>([\s\S]*?)<\/h3>/gi, "\n\n### $1\n\n");
1051
+ text = text.replace(/<h4[^>]*>([\s\S]*?)<\/h4>/gi, "\n\n#### $1\n\n");
1052
+ text = text.replace(/<h5[^>]*>([\s\S]*?)<\/h5>/gi, "\n\n##### $1\n\n");
1053
+ text = text.replace(/<h6[^>]*>([\s\S]*?)<\/h6>/gi, "\n\n###### $1\n\n");
1054
+ text = text.replace(/<a[^>]+href=["']([^"']*)["'][^>]*>([\s\S]*?)<\/a>/gi, "[$2]($1)");
1055
+ text = text.replace(/<(?:strong|b)[^>]*>([\s\S]*?)<\/(?:strong|b)>/gi, "**$1**");
1056
+ text = text.replace(/<(?:em|i)[^>]*>([\s\S]*?)<\/(?:em|i)>/gi, "*$1*");
1057
+ text = text.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, "\n- $1");
1058
+ text = text.replace(/<blockquote[^>]*>([\s\S]*?)<\/blockquote>/gi, "\n\n> $1\n\n");
1059
+ text = text.replace(/<hr[^>]*\/?>/gi, "\n\n---\n\n");
1060
+ text = text.replace(/<br[^>]*\/?>/gi, "\n");
1061
+ text = text.replace(/<\/p>/gi, "\n\n");
1062
+ text = text.replace(/<p[^>]*>/gi, "");
1063
+ text = text.replace(/<\/?(?:div|section|article|header|main|aside|figure|figcaption|table|thead|tbody|tr|td|th|ul|ol|dl|dt|dd)[^>]*>/gi, "\n");
1064
+ text = text.replace(/<[^>]+>/g, "");
1065
+ text = text.replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&nbsp;/g, " ").replace(/&copy;/g, "(c)");
1066
+ text = text.replace(/[\u{1F1E0}-\u{1FAFF}\u{2600}-\u{27BF}\u{FE00}-\u{FE0F}\u{200D}\u{20E3}]/gu, "");
1067
+ text = text.split("\n").map((l) => l.replace(/\s+/g, " ").trim()).join("\n");
1068
+ text = text.replace(/\n{3,}/g, "\n\n");
1069
+ text = text.replace(/\[[\s\n]+/g, "[").replace(/[\s\n]+\]/g, "]");
1070
+ text = text.replace(/(#{2,6})\s*\n+\s*/g, "$1 ");
1071
+ text = text.replace(/^#{2,6}\s*$/gm, "");
1072
+ text = text.replace(/\n{3,}/g, "\n\n");
1073
+ return text.trim().slice(0, 8e3);
1074
+ }
1075
+ function extractTitle2(html) {
1076
+ var _a, _b;
1077
+ const match = html.match(/<title>([^<]*)<\/title>/i);
1078
+ if (!match) return void 0;
1079
+ return ((_b = (_a = match[1]) == null ? void 0 : _a.split("|")[0]) == null ? void 0 : _b.trim()) || match[1];
1080
+ }
1081
+ function extractDescription(html) {
1082
+ const match = html.match(/<meta\s+name=["']description["']\s+content=["']([^"']*)["']/i);
1083
+ return match == null ? void 0 : match[1];
1084
+ }
864
1085
  function scanNextPages(projectRoot) {
865
1086
  const pages = [];
866
1087
  for (const base of ["app", "src/app"]) {
@@ -975,7 +1196,7 @@ async function generateAeoMetadata(config) {
975
1196
  if (process.env.NODE_ENV === "production") {
976
1197
  await generateAEOFiles(resolvedConfig);
977
1198
  }
978
- return {
1199
+ const metadata = {
979
1200
  title: resolvedConfig.title,
980
1201
  description: resolvedConfig.description,
981
1202
  alternates: {
@@ -991,62 +1212,30 @@ async function generateAeoMetadata(config) {
991
1212
  }
992
1213
  }
993
1214
  };
994
- }
995
- function extractText(html) {
996
- let text = html;
997
- text = text.replace(/<script[\s\S]*?<\/script>/gi, "");
998
- text = text.replace(/<style[\s\S]*?<\/style>/gi, "");
999
- text = text.replace(/<svg[\s\S]*?<\/svg>/gi, "");
1000
- const mainMatch = text.match(/<main[^>]*>([\s\S]*)<\/main>/i);
1001
- if (mainMatch) {
1002
- text = mainMatch[1];
1003
- } else {
1004
- text = text.replace(/<nav[\s\S]*?<\/nav>/gi, "");
1005
- text = text.replace(/<header[\s\S]*?<\/header>/gi, "");
1006
- text = text.replace(/<footer[\s\S]*?<\/footer>/gi, "");
1215
+ if (resolvedConfig.og.enabled) {
1216
+ metadata.openGraph = {
1217
+ type: resolvedConfig.og.type,
1218
+ title: resolvedConfig.title,
1219
+ description: resolvedConfig.description,
1220
+ url: resolvedConfig.url,
1221
+ siteName: resolvedConfig.title,
1222
+ ...resolvedConfig.og.image ? { images: [{ url: resolvedConfig.og.image }] } : {}
1223
+ };
1224
+ metadata.twitter = {
1225
+ card: resolvedConfig.og.image ? "summary_large_image" : "summary",
1226
+ title: resolvedConfig.title,
1227
+ description: resolvedConfig.description,
1228
+ ...resolvedConfig.og.twitterHandle ? { site: resolvedConfig.og.twitterHandle } : {},
1229
+ ...resolvedConfig.og.image ? { images: [resolvedConfig.og.image] } : {}
1230
+ };
1007
1231
  }
1008
- text = text.replace(/<a[^>]+href=["']([^"']*)["'][^>]*>([\s\S]*?)<\/a>/gi, (_, url, inner) => {
1009
- if (/<(?:h[1-6]|div|p|section)[^>]*>/i.test(inner)) {
1010
- const cleanInner = inner.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
1011
- return `
1012
- [${cleanInner.slice(0, 120).trim()}](${url})
1013
- `;
1014
- }
1015
- return `[${inner}](${url})`;
1016
- });
1017
- text = text.replace(/<h1[^>]*>([\s\S]*?)<\/h1>/gi, "\n\n## $1\n\n");
1018
- text = text.replace(/<h2[^>]*>([\s\S]*?)<\/h2>/gi, "\n\n## $1\n\n");
1019
- text = text.replace(/<h3[^>]*>([\s\S]*?)<\/h3>/gi, "\n\n### $1\n\n");
1020
- text = text.replace(/<h4[^>]*>([\s\S]*?)<\/h4>/gi, "\n\n#### $1\n\n");
1021
- text = text.replace(/<h5[^>]*>([\s\S]*?)<\/h5>/gi, "\n\n##### $1\n\n");
1022
- text = text.replace(/<h6[^>]*>([\s\S]*?)<\/h6>/gi, "\n\n###### $1\n\n");
1023
- text = text.replace(/<a[^>]+href=["']([^"']*)["'][^>]*>([\s\S]*?)<\/a>/gi, "[$2]($1)");
1024
- text = text.replace(/<(?:strong|b)[^>]*>([\s\S]*?)<\/(?:strong|b)>/gi, "**$1**");
1025
- text = text.replace(/<(?:em|i)[^>]*>([\s\S]*?)<\/(?:em|i)>/gi, "*$1*");
1026
- text = text.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, "\n- $1");
1027
- text = text.replace(/<blockquote[^>]*>([\s\S]*?)<\/blockquote>/gi, "\n\n> $1\n\n");
1028
- text = text.replace(/<hr[^>]*\/?>/gi, "\n\n---\n\n");
1029
- text = text.replace(/<br[^>]*\/?>/gi, "\n");
1030
- text = text.replace(/<\/p>/gi, "\n\n");
1031
- text = text.replace(/<p[^>]*>/gi, "");
1032
- text = text.replace(/<\/?(?:div|section|article|header|main|aside|figure|figcaption|table|thead|tbody|tr|td|th|ul|ol|dl|dt|dd)[^>]*>/gi, "\n");
1033
- text = text.replace(/<[^>]+>/g, "");
1034
- text = text.replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&nbsp;/g, " ").replace(/&copy;/g, "(c)");
1035
- text = text.replace(/[\u{1F1E0}-\u{1FAFF}\u{2600}-\u{27BF}\u{FE00}-\u{FE0F}\u{200D}\u{20E3}]/gu, "");
1036
- text = text.split("\n").map((l) => l.replace(/\s+/g, " ").trim()).join("\n");
1037
- text = text.replace(/\n{3,}/g, "\n\n");
1038
- text = text.replace(/\[[\s\n]+/g, "[").replace(/[\s\n]+\]/g, "]");
1039
- text = text.replace(/(#{2,6})\s*\n+\s*/g, "$1 ");
1040
- text = text.replace(/^#{2,6}\s*$/gm, "");
1041
- text = text.replace(/\n{3,}/g, "\n\n");
1042
- return text.trim().slice(0, 8e3);
1232
+ return metadata;
1043
1233
  }
1044
1234
  function scanNextBuildOutput(projectRoot) {
1045
1235
  const pages = [];
1046
1236
  const serverAppDir = path.join(projectRoot, ".next", "server", "app");
1047
1237
  if (!fs.existsSync(serverAppDir)) return pages;
1048
1238
  function walk(dir, basePath = "") {
1049
- var _a, _b;
1050
1239
  try {
1051
1240
  const entries = fs.readdirSync(dir);
1052
1241
  for (const entry of entries) {
@@ -1056,14 +1245,14 @@ function scanNextBuildOutput(projectRoot) {
1056
1245
  walk(fullPath, `${basePath}/${entry}`);
1057
1246
  } else if (entry === "index.html") {
1058
1247
  const html = fs.readFileSync(fullPath, "utf-8");
1059
- const titleMatch = html.match(/<title>([^<]*)<\/title>/i);
1060
- const descMatch = html.match(/<meta\s+name=["']description["']\s+content=["']([^"']*)["']/i);
1061
- const textContent = extractText(html);
1248
+ const title = extractTitle2(html);
1249
+ const description = extractDescription(html);
1250
+ const textContent = extractTextFromHtml(html);
1062
1251
  const pathname = basePath || "/";
1063
1252
  pages.push({
1064
1253
  pathname,
1065
- title: (_b = (_a = titleMatch == null ? void 0 : titleMatch[1]) == null ? void 0 : _a.split("|")[0]) == null ? void 0 : _b.trim(),
1066
- description: descMatch == null ? void 0 : descMatch[1],
1254
+ title,
1255
+ description,
1067
1256
  content: textContent
1068
1257
  });
1069
1258
  }