@better-seo/crawl 0.0.1

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/index.cjs ADDED
@@ -0,0 +1,175 @@
1
+ 'use strict';
2
+
3
+ // src/syndication.ts
4
+ function escXml(s) {
5
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
6
+ }
7
+ function rfc822(d) {
8
+ return d.toUTCString();
9
+ }
10
+ function renderRssXml(channel) {
11
+ const lines = [
12
+ '<?xml version="1.0" encoding="UTF-8"?>',
13
+ '<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">',
14
+ " <channel>",
15
+ ` <title>${escXml(channel.title)}</title>`,
16
+ ` <link>${escXml(channel.link)}</link>`
17
+ ];
18
+ if (channel.description) {
19
+ lines.push(` <description>${escXml(channel.description)}</description>`);
20
+ }
21
+ if (channel.language?.trim()) {
22
+ lines.push(` <language>${escXml(channel.language.trim())}</language>`);
23
+ }
24
+ lines.push(
25
+ ` <atom:link href="${escXml(channel.link)}" rel="self" type="application/rss+xml"/>`
26
+ );
27
+ for (const item of channel.items) {
28
+ lines.push(" <item>");
29
+ lines.push(` <title>${escXml(item.title)}</title>`);
30
+ lines.push(` <link>${escXml(item.link)}</link>`);
31
+ if (item.description) {
32
+ lines.push(` <description>${escXml(item.description)}</description>`);
33
+ }
34
+ if (item.pubDate !== void 0) {
35
+ const d = typeof item.pubDate === "string" ? new Date(item.pubDate) : item.pubDate;
36
+ lines.push(` <pubDate>${escXml(rfc822(d))}</pubDate>`);
37
+ }
38
+ lines.push(` <guid isPermaLink="true">${escXml(item.link)}</guid>`);
39
+ lines.push(" </item>");
40
+ }
41
+ lines.push(" </channel>", "</rss>");
42
+ return `${lines.join("\n")}
43
+ `;
44
+ }
45
+ function iso(d) {
46
+ const x = typeof d === "string" ? new Date(d) : d;
47
+ return x.toISOString();
48
+ }
49
+ function renderAtomFeed(feed) {
50
+ const lines = [
51
+ '<?xml version="1.0" encoding="utf-8"?>',
52
+ '<feed xmlns="http://www.w3.org/2005/Atom">',
53
+ ` <title>${escXml(feed.title)}</title>`,
54
+ ` <link href="${escXml(feed.link)}" rel="alternate"/>`,
55
+ ` <id>${escXml(feed.id)}</id>`,
56
+ ` <updated>${escXml(iso(feed.updated))}</updated>`
57
+ ];
58
+ for (const e of feed.entries) {
59
+ lines.push(" <entry>");
60
+ lines.push(` <title>${escXml(e.title)}</title>`);
61
+ lines.push(` <link href="${escXml(e.link)}" rel="alternate"/>`);
62
+ lines.push(` <id>${escXml(e.id)}</id>`);
63
+ lines.push(` <updated>${escXml(iso(e.updated))}</updated>`);
64
+ if (e.summary) lines.push(` <summary>${escXml(e.summary)}</summary>`);
65
+ lines.push(" </entry>");
66
+ }
67
+ lines.push("</feed>");
68
+ return `${lines.join("\n")}
69
+ `;
70
+ }
71
+ function renderLlmsTxt(opts) {
72
+ const parts = [`# ${opts.title.trim()}`];
73
+ if (opts.summary?.trim()) {
74
+ parts.push("", `> ${opts.summary.trim()}`);
75
+ }
76
+ if (opts.blocks?.length) {
77
+ for (const b of opts.blocks) {
78
+ parts.push("");
79
+ if (b.heading?.trim()) parts.push(`## ${b.heading.trim()}`);
80
+ for (const line of b.lines) {
81
+ const t = line.trim();
82
+ if (t) parts.push(t.startsWith("-") ? t : `- ${t}`);
83
+ }
84
+ }
85
+ }
86
+ return `${parts.join("\n").trim()}
87
+ `;
88
+ }
89
+ function renderSitemapIndexXml(sitemapUrls) {
90
+ const lines = [
91
+ '<?xml version="1.0" encoding="UTF-8"?>',
92
+ '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'
93
+ ];
94
+ for (const u of sitemapUrls) {
95
+ const t = u.trim();
96
+ if (!t) continue;
97
+ lines.push(" <sitemap>");
98
+ lines.push(` <loc>${escXml(t)}</loc>`);
99
+ lines.push(" </sitemap>");
100
+ }
101
+ lines.push("</sitemapindex>");
102
+ return `${lines.join("\n")}
103
+ `;
104
+ }
105
+
106
+ // src/index.ts
107
+ function renderRobotsTxt(opts = {}) {
108
+ const rules = opts.rules?.length ? opts.rules : [{ userAgent: "*", allow: ["/"] }];
109
+ const lines = [];
110
+ for (const r of rules) {
111
+ lines.push(`User-agent: ${r.userAgent}`);
112
+ if (r.allow?.length) for (const p of r.allow) lines.push(`Allow: ${p}`);
113
+ if (r.disallow?.length) for (const p of r.disallow) lines.push(`Disallow: ${p}`);
114
+ lines.push("");
115
+ }
116
+ if (opts.host?.trim()) {
117
+ lines.push(`Host: ${opts.host.trim()}`);
118
+ lines.push("");
119
+ }
120
+ if (opts.sitemap !== void 0) {
121
+ const list = typeof opts.sitemap === "string" ? [opts.sitemap] : opts.sitemap;
122
+ for (const u of list) {
123
+ const t = u.trim();
124
+ if (t) lines.push(`Sitemap: ${t}`);
125
+ }
126
+ lines.push("");
127
+ }
128
+ return `${lines.join("\n").trimEnd()}
129
+ `;
130
+ }
131
+ function escXml2(s) {
132
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
133
+ }
134
+ function renderSitemapXml(entries) {
135
+ const lines = [
136
+ '<?xml version="1.0" encoding="UTF-8"?>',
137
+ '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'
138
+ ];
139
+ for (const e of entries) {
140
+ lines.push(" <url>");
141
+ lines.push(` <loc>${escXml2(e.loc)}</loc>`);
142
+ if (e.lastmod) lines.push(` <lastmod>${escXml2(e.lastmod)}</lastmod>`);
143
+ if (e.changefreq) lines.push(` <changefreq>${e.changefreq}</changefreq>`);
144
+ if (e.priority !== void 0) {
145
+ lines.push(` <priority>${String(Math.min(1, Math.max(0, e.priority)))}</priority>`);
146
+ }
147
+ lines.push(" </url>");
148
+ }
149
+ lines.push("</urlset>");
150
+ return `${lines.join("\n")}
151
+ `;
152
+ }
153
+ function defaultSitemapUrlFromSEO(seo, baseUrl) {
154
+ const c = seo.meta.canonical;
155
+ const b = baseUrl?.replace(/\/$/, "");
156
+ if (c?.startsWith("http://") || c?.startsWith("https://")) {
157
+ try {
158
+ return `${new URL(c).origin}/sitemap.xml`;
159
+ } catch {
160
+ return void 0;
161
+ }
162
+ }
163
+ if (b) return `${b}/sitemap.xml`;
164
+ return void 0;
165
+ }
166
+
167
+ exports.defaultSitemapUrlFromSEO = defaultSitemapUrlFromSEO;
168
+ exports.renderAtomFeed = renderAtomFeed;
169
+ exports.renderLlmsTxt = renderLlmsTxt;
170
+ exports.renderRobotsTxt = renderRobotsTxt;
171
+ exports.renderRssXml = renderRssXml;
172
+ exports.renderSitemapIndexXml = renderSitemapIndexXml;
173
+ exports.renderSitemapXml = renderSitemapXml;
174
+ //# sourceMappingURL=index.cjs.map
175
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/syndication.ts","../src/index.ts"],"names":["escXml"],"mappings":"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","file":"index.cjs","sourcesContent":["function escXml(s: string): string {\n return s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n}\n\nfunction rfc822(d: Date): string {\n return d.toUTCString()\n}\n\nexport interface RssItem {\n readonly title: string\n readonly link: string\n readonly description?: string\n readonly pubDate?: string | Date\n}\n\nexport interface RssChannelOptions {\n readonly title: string\n readonly link: string\n readonly description?: string\n readonly language?: string\n readonly items: readonly RssItem[]\n}\n\n/** RSS 2.0 feed (UTF-8). Wave 12 / W*. */\nexport function renderRssXml(channel: RssChannelOptions): string {\n const lines: string[] = [\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>',\n '<rss version=\"2.0\" xmlns:atom=\"http://www.w3.org/2005/Atom\">',\n \" <channel>\",\n ` <title>${escXml(channel.title)}</title>`,\n ` <link>${escXml(channel.link)}</link>`,\n ]\n if (channel.description) {\n lines.push(` <description>${escXml(channel.description)}</description>`)\n }\n if (channel.language?.trim()) {\n lines.push(` <language>${escXml(channel.language.trim())}</language>`)\n }\n lines.push(\n ` <atom:link href=\"${escXml(channel.link)}\" rel=\"self\" type=\"application/rss+xml\"/>`,\n )\n for (const item of channel.items) {\n lines.push(\" <item>\")\n lines.push(` <title>${escXml(item.title)}</title>`)\n lines.push(` <link>${escXml(item.link)}</link>`)\n if (item.description) {\n lines.push(` <description>${escXml(item.description)}</description>`)\n }\n if (item.pubDate !== undefined) {\n const d = typeof item.pubDate === \"string\" ? new Date(item.pubDate) : item.pubDate\n lines.push(` <pubDate>${escXml(rfc822(d))}</pubDate>`)\n }\n lines.push(` <guid isPermaLink=\"true\">${escXml(item.link)}</guid>`)\n lines.push(\" </item>\")\n }\n lines.push(\" </channel>\", \"</rss>\")\n return `${lines.join(\"\\n\")}\\n`\n}\n\nexport interface AtomEntry {\n readonly title: string\n readonly link: string\n readonly id: string\n readonly updated: string | Date\n readonly summary?: string\n}\n\nexport interface AtomFeedOptions {\n readonly title: string\n readonly link: string\n readonly id: string\n readonly updated: string | Date\n readonly entries: readonly AtomEntry[]\n}\n\nfunction iso(d: string | Date): string {\n const x = typeof d === \"string\" ? new Date(d) : d\n return x.toISOString()\n}\n\n/** Atom 1.0 feed. Wave 12. */\nexport function renderAtomFeed(feed: AtomFeedOptions): string {\n const lines: string[] = [\n '<?xml version=\"1.0\" encoding=\"utf-8\"?>',\n '<feed xmlns=\"http://www.w3.org/2005/Atom\">',\n ` <title>${escXml(feed.title)}</title>`,\n ` <link href=\"${escXml(feed.link)}\" rel=\"alternate\"/>`,\n ` <id>${escXml(feed.id)}</id>`,\n ` <updated>${escXml(iso(feed.updated))}</updated>`,\n ]\n for (const e of feed.entries) {\n lines.push(\" <entry>\")\n lines.push(` <title>${escXml(e.title)}</title>`)\n lines.push(` <link href=\"${escXml(e.link)}\" rel=\"alternate\"/>`)\n lines.push(` <id>${escXml(e.id)}</id>`)\n lines.push(` <updated>${escXml(iso(e.updated))}</updated>`)\n if (e.summary) lines.push(` <summary>${escXml(e.summary)}</summary>`)\n lines.push(\" </entry>\")\n }\n lines.push(\"</feed>\")\n return `${lines.join(\"\\n\")}\\n`\n}\n\nexport interface LlmsBlock {\n readonly heading?: string\n readonly lines: readonly string[]\n}\n\n/** Plain **`llms.txt`** body (no leading BOM). Wave 12. */\nexport function renderLlmsTxt(opts: {\n readonly title: string\n readonly summary?: string\n readonly blocks?: readonly LlmsBlock[]\n}): string {\n const parts: string[] = [`# ${opts.title.trim()}`]\n if (opts.summary?.trim()) {\n parts.push(\"\", `> ${opts.summary.trim()}`)\n }\n if (opts.blocks?.length) {\n for (const b of opts.blocks) {\n parts.push(\"\")\n if (b.heading?.trim()) parts.push(`## ${b.heading.trim()}`)\n for (const line of b.lines) {\n const t = line.trim()\n if (t) parts.push(t.startsWith(\"-\") ? t : `- ${t}`)\n }\n }\n }\n return `${parts.join(\"\\n\").trim()}\\n`\n}\n\n/** Sitemap index for multiple urlset documents. */\nexport function renderSitemapIndexXml(sitemapUrls: readonly string[]): string {\n const lines: string[] = [\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>',\n '<sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">',\n ]\n for (const u of sitemapUrls) {\n const t = u.trim()\n if (!t) continue\n lines.push(\" <sitemap>\")\n lines.push(` <loc>${escXml(t)}</loc>`)\n lines.push(\" </sitemap>\")\n }\n lines.push(\"</sitemapindex>\")\n return `${lines.join(\"\\n\")}\\n`\n}\n","import type { SEO } from \"@better-seo/core\"\n\nexport interface RobotsTxtRule {\n readonly userAgent: string\n readonly allow?: readonly string[]\n readonly disallow?: readonly string[]\n}\n\nexport interface RobotsTxtOptions {\n readonly rules?: readonly RobotsTxtRule[]\n readonly sitemap?: string | readonly string[]\n readonly host?: string\n}\n\n/** Plain **robots.txt** body (UTF-8). */\nexport function renderRobotsTxt(opts: RobotsTxtOptions = {}): string {\n const rules = opts.rules?.length ? opts.rules : [{ userAgent: \"*\", allow: [\"/\"] }]\n const lines: string[] = []\n for (const r of rules) {\n lines.push(`User-agent: ${r.userAgent}`)\n if (r.allow?.length) for (const p of r.allow) lines.push(`Allow: ${p}`)\n if (r.disallow?.length) for (const p of r.disallow) lines.push(`Disallow: ${p}`)\n lines.push(\"\")\n }\n if (opts.host?.trim()) {\n lines.push(`Host: ${opts.host.trim()}`)\n lines.push(\"\")\n }\n if (opts.sitemap !== undefined) {\n const list = typeof opts.sitemap === \"string\" ? [opts.sitemap] : opts.sitemap\n for (const u of list) {\n const t = u.trim()\n if (t) lines.push(`Sitemap: ${t}`)\n }\n lines.push(\"\")\n }\n return `${lines.join(\"\\n\").trimEnd()}\\n`\n}\n\nexport interface SitemapUrlEntry {\n readonly loc: string\n readonly lastmod?: string\n readonly changefreq?: \"always\" | \"hourly\" | \"daily\" | \"weekly\" | \"monthly\" | \"yearly\" | \"never\"\n readonly priority?: number\n}\n\nfunction escXml(s: string): string {\n return s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n}\n\n/** Single **urlset** sitemap document. */\nexport function renderSitemapXml(entries: readonly SitemapUrlEntry[]): string {\n const lines: string[] = [\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>',\n '<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">',\n ]\n for (const e of entries) {\n lines.push(\" <url>\")\n lines.push(` <loc>${escXml(e.loc)}</loc>`)\n if (e.lastmod) lines.push(` <lastmod>${escXml(e.lastmod)}</lastmod>`)\n if (e.changefreq) lines.push(` <changefreq>${e.changefreq}</changefreq>`)\n if (e.priority !== undefined) {\n lines.push(` <priority>${String(Math.min(1, Math.max(0, e.priority)))}</priority>`)\n }\n lines.push(\" </url>\")\n }\n lines.push(\"</urlset>\")\n return `${lines.join(\"\\n\")}\\n`\n}\n\nexport type {\n AtomEntry,\n AtomFeedOptions,\n LlmsBlock,\n RssChannelOptions,\n RssItem,\n} from \"./syndication.js\"\nexport {\n renderAtomFeed,\n renderLlmsTxt,\n renderRssXml,\n renderSitemapIndexXml,\n} from \"./syndication.js\"\n\n/** Default **Sitemap:** URL from **`SEO.meta.canonical`** origin + **`/sitemap.xml`** when resolvable. */\nexport function defaultSitemapUrlFromSEO(seo: SEO, baseUrl?: string): string | undefined {\n const c = seo.meta.canonical\n const b = baseUrl?.replace(/\\/$/, \"\")\n if (c?.startsWith(\"http://\") || c?.startsWith(\"https://\")) {\n try {\n return `${new URL(c).origin}/sitemap.xml`\n } catch {\n return undefined\n }\n }\n if (b) return `${b}/sitemap.xml`\n return undefined\n}\n"]}
@@ -0,0 +1,71 @@
1
+ import { SEO } from '@better-seo/core';
2
+
3
+ interface RssItem {
4
+ readonly title: string;
5
+ readonly link: string;
6
+ readonly description?: string;
7
+ readonly pubDate?: string | Date;
8
+ }
9
+ interface RssChannelOptions {
10
+ readonly title: string;
11
+ readonly link: string;
12
+ readonly description?: string;
13
+ readonly language?: string;
14
+ readonly items: readonly RssItem[];
15
+ }
16
+ /** RSS 2.0 feed (UTF-8). Wave 12 / W*. */
17
+ declare function renderRssXml(channel: RssChannelOptions): string;
18
+ interface AtomEntry {
19
+ readonly title: string;
20
+ readonly link: string;
21
+ readonly id: string;
22
+ readonly updated: string | Date;
23
+ readonly summary?: string;
24
+ }
25
+ interface AtomFeedOptions {
26
+ readonly title: string;
27
+ readonly link: string;
28
+ readonly id: string;
29
+ readonly updated: string | Date;
30
+ readonly entries: readonly AtomEntry[];
31
+ }
32
+ /** Atom 1.0 feed. Wave 12. */
33
+ declare function renderAtomFeed(feed: AtomFeedOptions): string;
34
+ interface LlmsBlock {
35
+ readonly heading?: string;
36
+ readonly lines: readonly string[];
37
+ }
38
+ /** Plain **`llms.txt`** body (no leading BOM). Wave 12. */
39
+ declare function renderLlmsTxt(opts: {
40
+ readonly title: string;
41
+ readonly summary?: string;
42
+ readonly blocks?: readonly LlmsBlock[];
43
+ }): string;
44
+ /** Sitemap index for multiple urlset documents. */
45
+ declare function renderSitemapIndexXml(sitemapUrls: readonly string[]): string;
46
+
47
+ interface RobotsTxtRule {
48
+ readonly userAgent: string;
49
+ readonly allow?: readonly string[];
50
+ readonly disallow?: readonly string[];
51
+ }
52
+ interface RobotsTxtOptions {
53
+ readonly rules?: readonly RobotsTxtRule[];
54
+ readonly sitemap?: string | readonly string[];
55
+ readonly host?: string;
56
+ }
57
+ /** Plain **robots.txt** body (UTF-8). */
58
+ declare function renderRobotsTxt(opts?: RobotsTxtOptions): string;
59
+ interface SitemapUrlEntry {
60
+ readonly loc: string;
61
+ readonly lastmod?: string;
62
+ readonly changefreq?: "always" | "hourly" | "daily" | "weekly" | "monthly" | "yearly" | "never";
63
+ readonly priority?: number;
64
+ }
65
+ /** Single **urlset** sitemap document. */
66
+ declare function renderSitemapXml(entries: readonly SitemapUrlEntry[]): string;
67
+
68
+ /** Default **Sitemap:** URL from **`SEO.meta.canonical`** origin + **`/sitemap.xml`** when resolvable. */
69
+ declare function defaultSitemapUrlFromSEO(seo: SEO, baseUrl?: string): string | undefined;
70
+
71
+ export { type AtomEntry, type AtomFeedOptions, type LlmsBlock, type RobotsTxtOptions, type RobotsTxtRule, type RssChannelOptions, type RssItem, type SitemapUrlEntry, defaultSitemapUrlFromSEO, renderAtomFeed, renderLlmsTxt, renderRobotsTxt, renderRssXml, renderSitemapIndexXml, renderSitemapXml };
@@ -0,0 +1,71 @@
1
+ import { SEO } from '@better-seo/core';
2
+
3
+ interface RssItem {
4
+ readonly title: string;
5
+ readonly link: string;
6
+ readonly description?: string;
7
+ readonly pubDate?: string | Date;
8
+ }
9
+ interface RssChannelOptions {
10
+ readonly title: string;
11
+ readonly link: string;
12
+ readonly description?: string;
13
+ readonly language?: string;
14
+ readonly items: readonly RssItem[];
15
+ }
16
+ /** RSS 2.0 feed (UTF-8). Wave 12 / W*. */
17
+ declare function renderRssXml(channel: RssChannelOptions): string;
18
+ interface AtomEntry {
19
+ readonly title: string;
20
+ readonly link: string;
21
+ readonly id: string;
22
+ readonly updated: string | Date;
23
+ readonly summary?: string;
24
+ }
25
+ interface AtomFeedOptions {
26
+ readonly title: string;
27
+ readonly link: string;
28
+ readonly id: string;
29
+ readonly updated: string | Date;
30
+ readonly entries: readonly AtomEntry[];
31
+ }
32
+ /** Atom 1.0 feed. Wave 12. */
33
+ declare function renderAtomFeed(feed: AtomFeedOptions): string;
34
+ interface LlmsBlock {
35
+ readonly heading?: string;
36
+ readonly lines: readonly string[];
37
+ }
38
+ /** Plain **`llms.txt`** body (no leading BOM). Wave 12. */
39
+ declare function renderLlmsTxt(opts: {
40
+ readonly title: string;
41
+ readonly summary?: string;
42
+ readonly blocks?: readonly LlmsBlock[];
43
+ }): string;
44
+ /** Sitemap index for multiple urlset documents. */
45
+ declare function renderSitemapIndexXml(sitemapUrls: readonly string[]): string;
46
+
47
+ interface RobotsTxtRule {
48
+ readonly userAgent: string;
49
+ readonly allow?: readonly string[];
50
+ readonly disallow?: readonly string[];
51
+ }
52
+ interface RobotsTxtOptions {
53
+ readonly rules?: readonly RobotsTxtRule[];
54
+ readonly sitemap?: string | readonly string[];
55
+ readonly host?: string;
56
+ }
57
+ /** Plain **robots.txt** body (UTF-8). */
58
+ declare function renderRobotsTxt(opts?: RobotsTxtOptions): string;
59
+ interface SitemapUrlEntry {
60
+ readonly loc: string;
61
+ readonly lastmod?: string;
62
+ readonly changefreq?: "always" | "hourly" | "daily" | "weekly" | "monthly" | "yearly" | "never";
63
+ readonly priority?: number;
64
+ }
65
+ /** Single **urlset** sitemap document. */
66
+ declare function renderSitemapXml(entries: readonly SitemapUrlEntry[]): string;
67
+
68
+ /** Default **Sitemap:** URL from **`SEO.meta.canonical`** origin + **`/sitemap.xml`** when resolvable. */
69
+ declare function defaultSitemapUrlFromSEO(seo: SEO, baseUrl?: string): string | undefined;
70
+
71
+ export { type AtomEntry, type AtomFeedOptions, type LlmsBlock, type RobotsTxtOptions, type RobotsTxtRule, type RssChannelOptions, type RssItem, type SitemapUrlEntry, defaultSitemapUrlFromSEO, renderAtomFeed, renderLlmsTxt, renderRobotsTxt, renderRssXml, renderSitemapIndexXml, renderSitemapXml };
package/dist/index.js ADDED
@@ -0,0 +1,167 @@
1
+ // src/syndication.ts
2
+ function escXml(s) {
3
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
4
+ }
5
+ function rfc822(d) {
6
+ return d.toUTCString();
7
+ }
8
+ function renderRssXml(channel) {
9
+ const lines = [
10
+ '<?xml version="1.0" encoding="UTF-8"?>',
11
+ '<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">',
12
+ " <channel>",
13
+ ` <title>${escXml(channel.title)}</title>`,
14
+ ` <link>${escXml(channel.link)}</link>`
15
+ ];
16
+ if (channel.description) {
17
+ lines.push(` <description>${escXml(channel.description)}</description>`);
18
+ }
19
+ if (channel.language?.trim()) {
20
+ lines.push(` <language>${escXml(channel.language.trim())}</language>`);
21
+ }
22
+ lines.push(
23
+ ` <atom:link href="${escXml(channel.link)}" rel="self" type="application/rss+xml"/>`
24
+ );
25
+ for (const item of channel.items) {
26
+ lines.push(" <item>");
27
+ lines.push(` <title>${escXml(item.title)}</title>`);
28
+ lines.push(` <link>${escXml(item.link)}</link>`);
29
+ if (item.description) {
30
+ lines.push(` <description>${escXml(item.description)}</description>`);
31
+ }
32
+ if (item.pubDate !== void 0) {
33
+ const d = typeof item.pubDate === "string" ? new Date(item.pubDate) : item.pubDate;
34
+ lines.push(` <pubDate>${escXml(rfc822(d))}</pubDate>`);
35
+ }
36
+ lines.push(` <guid isPermaLink="true">${escXml(item.link)}</guid>`);
37
+ lines.push(" </item>");
38
+ }
39
+ lines.push(" </channel>", "</rss>");
40
+ return `${lines.join("\n")}
41
+ `;
42
+ }
43
+ function iso(d) {
44
+ const x = typeof d === "string" ? new Date(d) : d;
45
+ return x.toISOString();
46
+ }
47
+ function renderAtomFeed(feed) {
48
+ const lines = [
49
+ '<?xml version="1.0" encoding="utf-8"?>',
50
+ '<feed xmlns="http://www.w3.org/2005/Atom">',
51
+ ` <title>${escXml(feed.title)}</title>`,
52
+ ` <link href="${escXml(feed.link)}" rel="alternate"/>`,
53
+ ` <id>${escXml(feed.id)}</id>`,
54
+ ` <updated>${escXml(iso(feed.updated))}</updated>`
55
+ ];
56
+ for (const e of feed.entries) {
57
+ lines.push(" <entry>");
58
+ lines.push(` <title>${escXml(e.title)}</title>`);
59
+ lines.push(` <link href="${escXml(e.link)}" rel="alternate"/>`);
60
+ lines.push(` <id>${escXml(e.id)}</id>`);
61
+ lines.push(` <updated>${escXml(iso(e.updated))}</updated>`);
62
+ if (e.summary) lines.push(` <summary>${escXml(e.summary)}</summary>`);
63
+ lines.push(" </entry>");
64
+ }
65
+ lines.push("</feed>");
66
+ return `${lines.join("\n")}
67
+ `;
68
+ }
69
+ function renderLlmsTxt(opts) {
70
+ const parts = [`# ${opts.title.trim()}`];
71
+ if (opts.summary?.trim()) {
72
+ parts.push("", `> ${opts.summary.trim()}`);
73
+ }
74
+ if (opts.blocks?.length) {
75
+ for (const b of opts.blocks) {
76
+ parts.push("");
77
+ if (b.heading?.trim()) parts.push(`## ${b.heading.trim()}`);
78
+ for (const line of b.lines) {
79
+ const t = line.trim();
80
+ if (t) parts.push(t.startsWith("-") ? t : `- ${t}`);
81
+ }
82
+ }
83
+ }
84
+ return `${parts.join("\n").trim()}
85
+ `;
86
+ }
87
+ function renderSitemapIndexXml(sitemapUrls) {
88
+ const lines = [
89
+ '<?xml version="1.0" encoding="UTF-8"?>',
90
+ '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'
91
+ ];
92
+ for (const u of sitemapUrls) {
93
+ const t = u.trim();
94
+ if (!t) continue;
95
+ lines.push(" <sitemap>");
96
+ lines.push(` <loc>${escXml(t)}</loc>`);
97
+ lines.push(" </sitemap>");
98
+ }
99
+ lines.push("</sitemapindex>");
100
+ return `${lines.join("\n")}
101
+ `;
102
+ }
103
+
104
+ // src/index.ts
105
+ function renderRobotsTxt(opts = {}) {
106
+ const rules = opts.rules?.length ? opts.rules : [{ userAgent: "*", allow: ["/"] }];
107
+ const lines = [];
108
+ for (const r of rules) {
109
+ lines.push(`User-agent: ${r.userAgent}`);
110
+ if (r.allow?.length) for (const p of r.allow) lines.push(`Allow: ${p}`);
111
+ if (r.disallow?.length) for (const p of r.disallow) lines.push(`Disallow: ${p}`);
112
+ lines.push("");
113
+ }
114
+ if (opts.host?.trim()) {
115
+ lines.push(`Host: ${opts.host.trim()}`);
116
+ lines.push("");
117
+ }
118
+ if (opts.sitemap !== void 0) {
119
+ const list = typeof opts.sitemap === "string" ? [opts.sitemap] : opts.sitemap;
120
+ for (const u of list) {
121
+ const t = u.trim();
122
+ if (t) lines.push(`Sitemap: ${t}`);
123
+ }
124
+ lines.push("");
125
+ }
126
+ return `${lines.join("\n").trimEnd()}
127
+ `;
128
+ }
129
+ function escXml2(s) {
130
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
131
+ }
132
+ function renderSitemapXml(entries) {
133
+ const lines = [
134
+ '<?xml version="1.0" encoding="UTF-8"?>',
135
+ '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'
136
+ ];
137
+ for (const e of entries) {
138
+ lines.push(" <url>");
139
+ lines.push(` <loc>${escXml2(e.loc)}</loc>`);
140
+ if (e.lastmod) lines.push(` <lastmod>${escXml2(e.lastmod)}</lastmod>`);
141
+ if (e.changefreq) lines.push(` <changefreq>${e.changefreq}</changefreq>`);
142
+ if (e.priority !== void 0) {
143
+ lines.push(` <priority>${String(Math.min(1, Math.max(0, e.priority)))}</priority>`);
144
+ }
145
+ lines.push(" </url>");
146
+ }
147
+ lines.push("</urlset>");
148
+ return `${lines.join("\n")}
149
+ `;
150
+ }
151
+ function defaultSitemapUrlFromSEO(seo, baseUrl) {
152
+ const c = seo.meta.canonical;
153
+ const b = baseUrl?.replace(/\/$/, "");
154
+ if (c?.startsWith("http://") || c?.startsWith("https://")) {
155
+ try {
156
+ return `${new URL(c).origin}/sitemap.xml`;
157
+ } catch {
158
+ return void 0;
159
+ }
160
+ }
161
+ if (b) return `${b}/sitemap.xml`;
162
+ return void 0;
163
+ }
164
+
165
+ export { defaultSitemapUrlFromSEO, renderAtomFeed, renderLlmsTxt, renderRobotsTxt, renderRssXml, renderSitemapIndexXml, renderSitemapXml };
166
+ //# sourceMappingURL=index.js.map
167
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/syndication.ts","../src/index.ts"],"names":["escXml"],"mappings":"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","file":"index.js","sourcesContent":["function escXml(s: string): string {\n return s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n}\n\nfunction rfc822(d: Date): string {\n return d.toUTCString()\n}\n\nexport interface RssItem {\n readonly title: string\n readonly link: string\n readonly description?: string\n readonly pubDate?: string | Date\n}\n\nexport interface RssChannelOptions {\n readonly title: string\n readonly link: string\n readonly description?: string\n readonly language?: string\n readonly items: readonly RssItem[]\n}\n\n/** RSS 2.0 feed (UTF-8). Wave 12 / W*. */\nexport function renderRssXml(channel: RssChannelOptions): string {\n const lines: string[] = [\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>',\n '<rss version=\"2.0\" xmlns:atom=\"http://www.w3.org/2005/Atom\">',\n \" <channel>\",\n ` <title>${escXml(channel.title)}</title>`,\n ` <link>${escXml(channel.link)}</link>`,\n ]\n if (channel.description) {\n lines.push(` <description>${escXml(channel.description)}</description>`)\n }\n if (channel.language?.trim()) {\n lines.push(` <language>${escXml(channel.language.trim())}</language>`)\n }\n lines.push(\n ` <atom:link href=\"${escXml(channel.link)}\" rel=\"self\" type=\"application/rss+xml\"/>`,\n )\n for (const item of channel.items) {\n lines.push(\" <item>\")\n lines.push(` <title>${escXml(item.title)}</title>`)\n lines.push(` <link>${escXml(item.link)}</link>`)\n if (item.description) {\n lines.push(` <description>${escXml(item.description)}</description>`)\n }\n if (item.pubDate !== undefined) {\n const d = typeof item.pubDate === \"string\" ? new Date(item.pubDate) : item.pubDate\n lines.push(` <pubDate>${escXml(rfc822(d))}</pubDate>`)\n }\n lines.push(` <guid isPermaLink=\"true\">${escXml(item.link)}</guid>`)\n lines.push(\" </item>\")\n }\n lines.push(\" </channel>\", \"</rss>\")\n return `${lines.join(\"\\n\")}\\n`\n}\n\nexport interface AtomEntry {\n readonly title: string\n readonly link: string\n readonly id: string\n readonly updated: string | Date\n readonly summary?: string\n}\n\nexport interface AtomFeedOptions {\n readonly title: string\n readonly link: string\n readonly id: string\n readonly updated: string | Date\n readonly entries: readonly AtomEntry[]\n}\n\nfunction iso(d: string | Date): string {\n const x = typeof d === \"string\" ? new Date(d) : d\n return x.toISOString()\n}\n\n/** Atom 1.0 feed. Wave 12. */\nexport function renderAtomFeed(feed: AtomFeedOptions): string {\n const lines: string[] = [\n '<?xml version=\"1.0\" encoding=\"utf-8\"?>',\n '<feed xmlns=\"http://www.w3.org/2005/Atom\">',\n ` <title>${escXml(feed.title)}</title>`,\n ` <link href=\"${escXml(feed.link)}\" rel=\"alternate\"/>`,\n ` <id>${escXml(feed.id)}</id>`,\n ` <updated>${escXml(iso(feed.updated))}</updated>`,\n ]\n for (const e of feed.entries) {\n lines.push(\" <entry>\")\n lines.push(` <title>${escXml(e.title)}</title>`)\n lines.push(` <link href=\"${escXml(e.link)}\" rel=\"alternate\"/>`)\n lines.push(` <id>${escXml(e.id)}</id>`)\n lines.push(` <updated>${escXml(iso(e.updated))}</updated>`)\n if (e.summary) lines.push(` <summary>${escXml(e.summary)}</summary>`)\n lines.push(\" </entry>\")\n }\n lines.push(\"</feed>\")\n return `${lines.join(\"\\n\")}\\n`\n}\n\nexport interface LlmsBlock {\n readonly heading?: string\n readonly lines: readonly string[]\n}\n\n/** Plain **`llms.txt`** body (no leading BOM). Wave 12. */\nexport function renderLlmsTxt(opts: {\n readonly title: string\n readonly summary?: string\n readonly blocks?: readonly LlmsBlock[]\n}): string {\n const parts: string[] = [`# ${opts.title.trim()}`]\n if (opts.summary?.trim()) {\n parts.push(\"\", `> ${opts.summary.trim()}`)\n }\n if (opts.blocks?.length) {\n for (const b of opts.blocks) {\n parts.push(\"\")\n if (b.heading?.trim()) parts.push(`## ${b.heading.trim()}`)\n for (const line of b.lines) {\n const t = line.trim()\n if (t) parts.push(t.startsWith(\"-\") ? t : `- ${t}`)\n }\n }\n }\n return `${parts.join(\"\\n\").trim()}\\n`\n}\n\n/** Sitemap index for multiple urlset documents. */\nexport function renderSitemapIndexXml(sitemapUrls: readonly string[]): string {\n const lines: string[] = [\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>',\n '<sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">',\n ]\n for (const u of sitemapUrls) {\n const t = u.trim()\n if (!t) continue\n lines.push(\" <sitemap>\")\n lines.push(` <loc>${escXml(t)}</loc>`)\n lines.push(\" </sitemap>\")\n }\n lines.push(\"</sitemapindex>\")\n return `${lines.join(\"\\n\")}\\n`\n}\n","import type { SEO } from \"@better-seo/core\"\n\nexport interface RobotsTxtRule {\n readonly userAgent: string\n readonly allow?: readonly string[]\n readonly disallow?: readonly string[]\n}\n\nexport interface RobotsTxtOptions {\n readonly rules?: readonly RobotsTxtRule[]\n readonly sitemap?: string | readonly string[]\n readonly host?: string\n}\n\n/** Plain **robots.txt** body (UTF-8). */\nexport function renderRobotsTxt(opts: RobotsTxtOptions = {}): string {\n const rules = opts.rules?.length ? opts.rules : [{ userAgent: \"*\", allow: [\"/\"] }]\n const lines: string[] = []\n for (const r of rules) {\n lines.push(`User-agent: ${r.userAgent}`)\n if (r.allow?.length) for (const p of r.allow) lines.push(`Allow: ${p}`)\n if (r.disallow?.length) for (const p of r.disallow) lines.push(`Disallow: ${p}`)\n lines.push(\"\")\n }\n if (opts.host?.trim()) {\n lines.push(`Host: ${opts.host.trim()}`)\n lines.push(\"\")\n }\n if (opts.sitemap !== undefined) {\n const list = typeof opts.sitemap === \"string\" ? [opts.sitemap] : opts.sitemap\n for (const u of list) {\n const t = u.trim()\n if (t) lines.push(`Sitemap: ${t}`)\n }\n lines.push(\"\")\n }\n return `${lines.join(\"\\n\").trimEnd()}\\n`\n}\n\nexport interface SitemapUrlEntry {\n readonly loc: string\n readonly lastmod?: string\n readonly changefreq?: \"always\" | \"hourly\" | \"daily\" | \"weekly\" | \"monthly\" | \"yearly\" | \"never\"\n readonly priority?: number\n}\n\nfunction escXml(s: string): string {\n return s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n}\n\n/** Single **urlset** sitemap document. */\nexport function renderSitemapXml(entries: readonly SitemapUrlEntry[]): string {\n const lines: string[] = [\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>',\n '<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">',\n ]\n for (const e of entries) {\n lines.push(\" <url>\")\n lines.push(` <loc>${escXml(e.loc)}</loc>`)\n if (e.lastmod) lines.push(` <lastmod>${escXml(e.lastmod)}</lastmod>`)\n if (e.changefreq) lines.push(` <changefreq>${e.changefreq}</changefreq>`)\n if (e.priority !== undefined) {\n lines.push(` <priority>${String(Math.min(1, Math.max(0, e.priority)))}</priority>`)\n }\n lines.push(\" </url>\")\n }\n lines.push(\"</urlset>\")\n return `${lines.join(\"\\n\")}\\n`\n}\n\nexport type {\n AtomEntry,\n AtomFeedOptions,\n LlmsBlock,\n RssChannelOptions,\n RssItem,\n} from \"./syndication.js\"\nexport {\n renderAtomFeed,\n renderLlmsTxt,\n renderRssXml,\n renderSitemapIndexXml,\n} from \"./syndication.js\"\n\n/** Default **Sitemap:** URL from **`SEO.meta.canonical`** origin + **`/sitemap.xml`** when resolvable. */\nexport function defaultSitemapUrlFromSEO(seo: SEO, baseUrl?: string): string | undefined {\n const c = seo.meta.canonical\n const b = baseUrl?.replace(/\\/$/, \"\")\n if (c?.startsWith(\"http://\") || c?.startsWith(\"https://\")) {\n try {\n return `${new URL(c).origin}/sitemap.xml`\n } catch {\n return undefined\n }\n }\n if (b) return `${b}/sitemap.xml`\n return undefined\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@better-seo/crawl",
3
+ "version": "0.0.1",
4
+ "description": "npm @better-seo/crawl — crawl/index helpers aligned with @better-seo/core: robots.txt and sitemap XML builders (pure strings, no network). Optional syndication depth in later roadmap waves.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "main": "./dist/index.cjs",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js",
15
+ "require": "./dist/index.cjs"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "dependencies": {
22
+ "@better-seo/core": "0.0.1"
23
+ },
24
+ "scripts": {
25
+ "build": "node ../../scripts/run-tsup.mjs",
26
+ "test": "npm exec -- vitest run",
27
+ "test:coverage": "npm exec -- vitest run --coverage",
28
+ "lint": "npm exec -- eslint .",
29
+ "typecheck": "npm exec -- tsc -p tsconfig.json --noEmit"
30
+ },
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "engines": {
35
+ "node": ">=24.0.0"
36
+ },
37
+ "devDependencies": {
38
+ "@vitest/coverage-v8": "4.1.2",
39
+ "tsup": "8.5.1",
40
+ "typescript": "6.0.2",
41
+ "vitest": "4.1.2"
42
+ }
43
+ }