folderblog 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/dist/{chunk-24MKFHML.cjs → chunk-2TZSVPNP.cjs} +5 -0
- package/dist/{chunk-HMQIQUPB.cjs → chunk-6TFXNIO6.cjs} +108 -0
- package/dist/{chunk-ZRUBI3GH.js → chunk-B43UAOPC.js} +106 -1
- package/dist/{chunk-XP5J4LFJ.js → chunk-D26H5722.js} +5 -0
- package/dist/chunk-E7PYGJA7.cjs +39 -0
- package/dist/{chunk-QA4KPPTA.cjs → chunk-J3Y3HEBF.cjs} +84 -13
- package/dist/{chunk-PARGDJNY.js → chunk-K76XLEC7.js} +1 -1
- package/dist/{chunk-IXP35S24.js → chunk-LPPBVXJ7.js} +83 -12
- package/dist/chunk-Q6EXKX6K.js +17 -0
- package/dist/{chunk-4ZJGUMHS.cjs → chunk-Q6EYTOTM.cjs} +2 -2
- package/dist/chunk-UCXXH2MP.cjs +20 -0
- package/dist/chunk-XQD3UUL5.js +34 -0
- package/dist/cli/bin.cjs +5 -5
- package/dist/cli/bin.js +4 -4
- package/dist/cli/index.cjs +5 -5
- package/dist/cli/index.js +4 -4
- package/dist/config-ADPY6IQS.d.cts +473 -0
- package/dist/config-Dctsdeo6.d.ts +473 -0
- package/dist/index.cjs +157 -187
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +16 -69
- package/dist/local/index.cjs +785 -0
- package/dist/local/index.d.cts +268 -0
- package/dist/local/index.d.ts +268 -0
- package/dist/local/index.js +772 -0
- package/dist/output-0P0br3Jc.d.cts +452 -0
- package/dist/output-0P0br3Jc.d.ts +452 -0
- package/dist/plugins/embed-cloudflare-ai.cjs +166 -0
- package/dist/plugins/embed-cloudflare-ai.d.cts +73 -0
- package/dist/plugins/embed-cloudflare-ai.d.ts +73 -0
- package/dist/plugins/embed-cloudflare-ai.js +156 -0
- package/dist/plugins/embed-transformers.cjs +121 -0
- package/dist/plugins/embed-transformers.d.cts +55 -0
- package/dist/plugins/embed-transformers.d.ts +55 -0
- package/dist/plugins/embed-transformers.js +113 -0
- package/dist/plugins/similarity.cjs +19 -0
- package/dist/plugins/similarity.d.cts +41 -0
- package/dist/plugins/similarity.d.ts +41 -0
- package/dist/plugins/similarity.js +2 -0
- package/dist/processor/index.cjs +123 -111
- package/dist/processor/index.d.cts +6 -2
- package/dist/processor/index.d.ts +6 -2
- package/dist/processor/index.js +3 -3
- package/dist/processor/plugins.cjs +24 -12
- package/dist/processor/plugins.d.cts +4 -2
- package/dist/processor/plugins.d.ts +4 -2
- package/dist/processor/plugins.js +1 -1
- package/dist/processor/types.cjs +16 -16
- package/dist/processor/types.d.cts +3 -2
- package/dist/processor/types.d.ts +3 -2
- package/dist/processor/types.js +1 -1
- package/dist/seo/index.cjs +289 -0
- package/dist/seo/index.d.cts +95 -0
- package/dist/seo/index.d.ts +95 -0
- package/dist/seo/index.js +274 -0
- package/dist/server/index.cjs +2 -5
- package/dist/server/index.js +2 -5
- package/package.json +36 -1
- package/dist/config-DFr-htlO.d.cts +0 -887
- package/dist/config-DFr-htlO.d.ts +0 -887
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { CopyOnlyImageProcessor, NoOpDatabase, NoOpImageEmbedder, NoOpSimilarity, NoOpTextEmbedder, PassthroughMermaidRenderer, PluginManager, createAllNoOpPlugins, createDefaultPlugins, createPluginManager, topologicalSort } from '../chunk-
|
|
1
|
+
export { CopyOnlyImageProcessor, CosineSimilarityPlugin, NoOpDatabase, NoOpImageEmbedder, NoOpSimilarity, NoOpTextEmbedder, PassthroughMermaidRenderer, PluginManager, cosineSimilarity, createAllNoOpPlugins, createDefaultPlugins, createPluginManager, createSimilarityPlugin, topologicalSort } from '../chunk-B43UAOPC.js';
|
|
2
2
|
import '../chunk-3RG5ZIWI.js';
|
package/dist/processor/types.cjs
CHANGED
|
@@ -1,67 +1,67 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunk2TZSVPNP_cjs = require('../chunk-2TZSVPNP.cjs');
|
|
4
4
|
require('../chunk-OBGZSXTJ.cjs');
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
Object.defineProperty(exports, "DEFAULT_IMAGE_SIZES", {
|
|
9
9
|
enumerable: true,
|
|
10
|
-
get: function () { return
|
|
10
|
+
get: function () { return chunk2TZSVPNP_cjs.DEFAULT_IMAGE_SIZES; }
|
|
11
11
|
});
|
|
12
12
|
Object.defineProperty(exports, "OUTPUT_FILES", {
|
|
13
13
|
enumerable: true,
|
|
14
|
-
get: function () { return
|
|
14
|
+
get: function () { return chunk2TZSVPNP_cjs.OUTPUT_FILES; }
|
|
15
15
|
});
|
|
16
16
|
Object.defineProperty(exports, "buildEmbeddingCacheFromManifest", {
|
|
17
17
|
enumerable: true,
|
|
18
|
-
get: function () { return
|
|
18
|
+
get: function () { return chunk2TZSVPNP_cjs.buildEmbeddingCacheFromManifest; }
|
|
19
19
|
});
|
|
20
20
|
Object.defineProperty(exports, "buildMediaCacheFromManifest", {
|
|
21
21
|
enumerable: true,
|
|
22
|
-
get: function () { return
|
|
22
|
+
get: function () { return chunk2TZSVPNP_cjs.buildMediaCacheFromManifest; }
|
|
23
23
|
});
|
|
24
24
|
Object.defineProperty(exports, "createEmptyCacheStats", {
|
|
25
25
|
enumerable: true,
|
|
26
|
-
get: function () { return
|
|
26
|
+
get: function () { return chunk2TZSVPNP_cjs.createEmptyCacheStats; }
|
|
27
27
|
});
|
|
28
28
|
Object.defineProperty(exports, "getMediaOutputDir", {
|
|
29
29
|
enumerable: true,
|
|
30
|
-
get: function () { return
|
|
30
|
+
get: function () { return chunk2TZSVPNP_cjs.getMediaOutputDir; }
|
|
31
31
|
});
|
|
32
32
|
Object.defineProperty(exports, "getOutputDir", {
|
|
33
33
|
enumerable: true,
|
|
34
|
-
get: function () { return
|
|
34
|
+
get: function () { return chunk2TZSVPNP_cjs.getOutputDir; }
|
|
35
35
|
});
|
|
36
36
|
Object.defineProperty(exports, "isBrokenLinkIssue", {
|
|
37
37
|
enumerable: true,
|
|
38
|
-
get: function () { return
|
|
38
|
+
get: function () { return chunk2TZSVPNP_cjs.isBrokenLinkIssue; }
|
|
39
39
|
});
|
|
40
40
|
Object.defineProperty(exports, "isEmbeddingErrorIssue", {
|
|
41
41
|
enumerable: true,
|
|
42
|
-
get: function () { return
|
|
42
|
+
get: function () { return chunk2TZSVPNP_cjs.isEmbeddingErrorIssue; }
|
|
43
43
|
});
|
|
44
44
|
Object.defineProperty(exports, "isMediaProcessingIssue", {
|
|
45
45
|
enumerable: true,
|
|
46
|
-
get: function () { return
|
|
46
|
+
get: function () { return chunk2TZSVPNP_cjs.isMediaProcessingIssue; }
|
|
47
47
|
});
|
|
48
48
|
Object.defineProperty(exports, "isMermaidErrorIssue", {
|
|
49
49
|
enumerable: true,
|
|
50
|
-
get: function () { return
|
|
50
|
+
get: function () { return chunk2TZSVPNP_cjs.isMermaidErrorIssue; }
|
|
51
51
|
});
|
|
52
52
|
Object.defineProperty(exports, "isMissingMediaIssue", {
|
|
53
53
|
enumerable: true,
|
|
54
|
-
get: function () { return
|
|
54
|
+
get: function () { return chunk2TZSVPNP_cjs.isMissingMediaIssue; }
|
|
55
55
|
});
|
|
56
56
|
Object.defineProperty(exports, "isPluginErrorIssue", {
|
|
57
57
|
enumerable: true,
|
|
58
|
-
get: function () { return
|
|
58
|
+
get: function () { return chunk2TZSVPNP_cjs.isPluginErrorIssue; }
|
|
59
59
|
});
|
|
60
60
|
Object.defineProperty(exports, "isSlugConflictIssue", {
|
|
61
61
|
enumerable: true,
|
|
62
|
-
get: function () { return
|
|
62
|
+
get: function () { return chunk2TZSVPNP_cjs.isSlugConflictIssue; }
|
|
63
63
|
});
|
|
64
64
|
Object.defineProperty(exports, "withDefaults", {
|
|
65
65
|
enumerable: true,
|
|
66
|
-
get: function () { return
|
|
66
|
+
get: function () { return chunk2TZSVPNP_cjs.withDefaults; }
|
|
67
67
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export { C as ContentConfig, D as DEFAULT_IMAGE_SIZES, d as DebugConfig, e as DirectoryConfig, j as ImageSizeConfig, M as MediaConfig, m as MermaidConfig, r as PipelineConfig, w as ProcessConfig, x as ProcessConfigWithDefaults, S as SimilarityConfig, F as getMediaOutputDir, G as getOutputDir, H as withDefaults } from '../config-ADPY6IQS.cjs';
|
|
2
|
+
import { d as ProcessedPost } from '../output-0P0br3Jc.cjs';
|
|
3
|
+
export { B as BrokenLinkIssue, f as BuildReport, C as CacheContext, g as CacheStats, h as CachedMediaMetadata, i as CachedMediaSizeVariant, E as EmbeddingErrorIssue, j as EmbeddingMap, G as GraphData, k as GraphEdge, l as GraphNode, m as IssueCategory, I as IssueFilterOptions, n as IssueModule, b as IssueReport, a as IssueSeverity, c as IssueSummary, M as MediaMetadata, o as MediaPathMap, p as MediaProcessingIssue, q as MediaSizeVariant, r as MermaidErrorIssue, s as MissingMediaIssue, O as OUTPUT_FILES, t as OutputFiles, u as PathHashMap, v as PluginErrorIssue, w as PostCover, x as PostCoverError, y as PostCoverSize, z as PostMetadata, A as ProcessResult, e as ProcessedMedia, P as ProcessingIssue, R as RelationshipType, S as SlugConflictIssue, D as SlugHashMap, T as TocItem, F as buildEmbeddingCacheFromManifest, H as buildMediaCacheFromManifest, J as createEmptyCacheStats, K as isBrokenLinkIssue, L as isEmbeddingErrorIssue, N as isMediaProcessingIssue, Q as isMermaidErrorIssue, U as isMissingMediaIssue, V as isPluginErrorIssue, W as isSlugConflictIssue } from '../output-0P0br3Jc.cjs';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Link resolution types for wiki-link and markdown link processing.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export { C as ContentConfig, D as DEFAULT_IMAGE_SIZES, d as DebugConfig, e as DirectoryConfig, j as ImageSizeConfig, M as MediaConfig, m as MermaidConfig, r as PipelineConfig, w as ProcessConfig, x as ProcessConfigWithDefaults, S as SimilarityConfig, F as getMediaOutputDir, G as getOutputDir, H as withDefaults } from '../config-Dctsdeo6.js';
|
|
2
|
+
import { d as ProcessedPost } from '../output-0P0br3Jc.js';
|
|
3
|
+
export { B as BrokenLinkIssue, f as BuildReport, C as CacheContext, g as CacheStats, h as CachedMediaMetadata, i as CachedMediaSizeVariant, E as EmbeddingErrorIssue, j as EmbeddingMap, G as GraphData, k as GraphEdge, l as GraphNode, m as IssueCategory, I as IssueFilterOptions, n as IssueModule, b as IssueReport, a as IssueSeverity, c as IssueSummary, M as MediaMetadata, o as MediaPathMap, p as MediaProcessingIssue, q as MediaSizeVariant, r as MermaidErrorIssue, s as MissingMediaIssue, O as OUTPUT_FILES, t as OutputFiles, u as PathHashMap, v as PluginErrorIssue, w as PostCover, x as PostCoverError, y as PostCoverSize, z as PostMetadata, A as ProcessResult, e as ProcessedMedia, P as ProcessingIssue, R as RelationshipType, S as SlugConflictIssue, D as SlugHashMap, T as TocItem, F as buildEmbeddingCacheFromManifest, H as buildMediaCacheFromManifest, J as createEmptyCacheStats, K as isBrokenLinkIssue, L as isEmbeddingErrorIssue, N as isMediaProcessingIssue, Q as isMermaidErrorIssue, U as isMissingMediaIssue, V as isPluginErrorIssue, W as isSlugConflictIssue } from '../output-0P0br3Jc.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Link resolution types for wiki-link and markdown link processing.
|
package/dist/processor/types.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { DEFAULT_IMAGE_SIZES, OUTPUT_FILES, buildEmbeddingCacheFromManifest, buildMediaCacheFromManifest, createEmptyCacheStats, getMediaOutputDir, getOutputDir, isBrokenLinkIssue, isEmbeddingErrorIssue, isMediaProcessingIssue, isMermaidErrorIssue, isMissingMediaIssue, isPluginErrorIssue, isSlugConflictIssue, withDefaults } from '../chunk-
|
|
1
|
+
export { DEFAULT_IMAGE_SIZES, OUTPUT_FILES, buildEmbeddingCacheFromManifest, buildMediaCacheFromManifest, createEmptyCacheStats, getMediaOutputDir, getOutputDir, isBrokenLinkIssue, isEmbeddingErrorIssue, isMediaProcessingIssue, isMermaidErrorIssue, isMissingMediaIssue, isPluginErrorIssue, isSlugConflictIssue, withDefaults } from '../chunk-D26H5722.js';
|
|
2
2
|
import '../chunk-3RG5ZIWI.js';
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
require('../chunk-OBGZSXTJ.cjs');
|
|
4
|
+
|
|
5
|
+
// src/seo/index.ts
|
|
6
|
+
function escapeMarkup(str, aposEntity = "'") {
|
|
7
|
+
if (!str) return "";
|
|
8
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, aposEntity);
|
|
9
|
+
}
|
|
10
|
+
function escapeXml(str) {
|
|
11
|
+
return escapeMarkup(str, "'");
|
|
12
|
+
}
|
|
13
|
+
function escapeHtml(str) {
|
|
14
|
+
return escapeMarkup(str, "'");
|
|
15
|
+
}
|
|
16
|
+
function makeAbsoluteUrl(path, siteUrl) {
|
|
17
|
+
if (path.startsWith("http://") || path.startsWith("https://")) return path;
|
|
18
|
+
if (path.startsWith("//")) return `https:${path}`;
|
|
19
|
+
if (path.startsWith("/")) return `${siteUrl}${path}`;
|
|
20
|
+
return `${siteUrl}/${path}`;
|
|
21
|
+
}
|
|
22
|
+
function generateMetaTags(site, options) {
|
|
23
|
+
const title = options.title ?? site.siteName;
|
|
24
|
+
const description = options.description ?? site.siteDescription ?? "";
|
|
25
|
+
const image = options.image ?? site.ogImage ?? "";
|
|
26
|
+
const url = options.url ?? site.siteUrl;
|
|
27
|
+
const type = options.type ?? "website";
|
|
28
|
+
const absoluteImage = image ? makeAbsoluteUrl(image, site.siteUrl) : "";
|
|
29
|
+
const tags = [
|
|
30
|
+
{ title },
|
|
31
|
+
{ name: "description", content: description },
|
|
32
|
+
{ tagName: "link", rel: "canonical", href: url },
|
|
33
|
+
{ property: "og:title", content: title },
|
|
34
|
+
{ property: "og:description", content: description },
|
|
35
|
+
{ property: "og:url", content: url },
|
|
36
|
+
{ property: "og:type", content: type },
|
|
37
|
+
{ property: "og:site_name", content: site.siteName },
|
|
38
|
+
{ name: "twitter:card", content: "summary_large_image" },
|
|
39
|
+
{ name: "twitter:title", content: title },
|
|
40
|
+
{ name: "twitter:description", content: description }
|
|
41
|
+
];
|
|
42
|
+
if (absoluteImage) {
|
|
43
|
+
tags.push(
|
|
44
|
+
{ property: "og:image", content: absoluteImage },
|
|
45
|
+
{ name: "twitter:image", content: absoluteImage }
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
if (type === "article" && options.article) {
|
|
49
|
+
const { article } = options;
|
|
50
|
+
if (article.publishedTime) {
|
|
51
|
+
tags.push({ property: "article:published_time", content: article.publishedTime });
|
|
52
|
+
}
|
|
53
|
+
if (article.modifiedTime) {
|
|
54
|
+
tags.push({ property: "article:modified_time", content: article.modifiedTime });
|
|
55
|
+
}
|
|
56
|
+
if (article.tags) {
|
|
57
|
+
for (const tag of article.tags) {
|
|
58
|
+
tags.push({ property: "article:tag", content: tag });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return tags;
|
|
63
|
+
}
|
|
64
|
+
function generatePostMetaTags(site, post, url) {
|
|
65
|
+
return generateMetaTags(site, {
|
|
66
|
+
title: `${post.title} | ${site.siteName}`,
|
|
67
|
+
description: post.description || post.excerpt,
|
|
68
|
+
image: post.coverImage,
|
|
69
|
+
url,
|
|
70
|
+
type: "article",
|
|
71
|
+
article: {
|
|
72
|
+
publishedTime: post.date,
|
|
73
|
+
author: post.authorName ?? site.author?.name,
|
|
74
|
+
tags: post.tags
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
function generateListMetaTags(site, title, description, url, pageNumber) {
|
|
79
|
+
const pageTitle = pageNumber && pageNumber > 1 ? `${title} - Page ${pageNumber} | ${site.siteName}` : `${title} | ${site.siteName}`;
|
|
80
|
+
const tags = generateMetaTags(site, {
|
|
81
|
+
title: pageTitle,
|
|
82
|
+
description,
|
|
83
|
+
url,
|
|
84
|
+
type: "website"
|
|
85
|
+
});
|
|
86
|
+
if (pageNumber && pageNumber > 1) {
|
|
87
|
+
tags.push({ name: "robots", content: "noindex, follow" });
|
|
88
|
+
}
|
|
89
|
+
return tags;
|
|
90
|
+
}
|
|
91
|
+
function postToArticleJsonLd(site, post, url) {
|
|
92
|
+
return {
|
|
93
|
+
"@context": "https://schema.org",
|
|
94
|
+
"@type": "BlogPosting",
|
|
95
|
+
headline: post.title,
|
|
96
|
+
description: post.description || post.excerpt,
|
|
97
|
+
author: {
|
|
98
|
+
"@type": post.authorName ? "Person" : "Organization",
|
|
99
|
+
name: post.authorName ?? site.author?.name ?? site.siteName
|
|
100
|
+
},
|
|
101
|
+
publisher: {
|
|
102
|
+
"@type": "Organization",
|
|
103
|
+
name: site.siteName
|
|
104
|
+
},
|
|
105
|
+
datePublished: post.date,
|
|
106
|
+
mainEntityOfPage: { "@type": "WebPage", "@id": url },
|
|
107
|
+
keywords: post.tags?.join(", "),
|
|
108
|
+
...post.coverImage ? { image: [makeAbsoluteUrl(post.coverImage, site.siteUrl)] } : {}
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function createItemListJsonLd(posts, listName, listDescription, baseUrl) {
|
|
112
|
+
return {
|
|
113
|
+
"@context": "https://schema.org",
|
|
114
|
+
"@type": "ItemList",
|
|
115
|
+
name: listName,
|
|
116
|
+
description: listDescription,
|
|
117
|
+
numberOfItems: posts.length,
|
|
118
|
+
itemListElement: posts.map((post, index) => ({
|
|
119
|
+
"@type": "ListItem",
|
|
120
|
+
position: index + 1,
|
|
121
|
+
url: baseUrl ? `${baseUrl}/${post.slug}` : `/${post.slug}`,
|
|
122
|
+
name: post.title
|
|
123
|
+
}))
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function createBreadcrumbJsonLd(items) {
|
|
127
|
+
return {
|
|
128
|
+
"@context": "https://schema.org",
|
|
129
|
+
"@type": "BreadcrumbList",
|
|
130
|
+
itemListElement: items.map((item, index) => ({
|
|
131
|
+
"@type": "ListItem",
|
|
132
|
+
position: index + 1,
|
|
133
|
+
name: item.name,
|
|
134
|
+
item: item.url
|
|
135
|
+
}))
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function createOrganizationJsonLd(site) {
|
|
139
|
+
const sameAs = [];
|
|
140
|
+
if (site.social?.twitter) sameAs.push(site.social.twitter);
|
|
141
|
+
if (site.social?.github) sameAs.push(site.social.github);
|
|
142
|
+
return {
|
|
143
|
+
"@context": "https://schema.org",
|
|
144
|
+
"@type": "Organization",
|
|
145
|
+
name: site.siteName,
|
|
146
|
+
url: site.siteUrl,
|
|
147
|
+
description: site.siteDescription,
|
|
148
|
+
...sameAs.length > 0 ? { sameAs } : {}
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function createWebsiteJsonLd(site, searchUrl) {
|
|
152
|
+
const jsonLd = {
|
|
153
|
+
"@context": "https://schema.org",
|
|
154
|
+
"@type": "WebSite",
|
|
155
|
+
name: site.siteName,
|
|
156
|
+
url: site.siteUrl,
|
|
157
|
+
description: site.siteDescription
|
|
158
|
+
};
|
|
159
|
+
if (searchUrl) {
|
|
160
|
+
jsonLd.potentialAction = {
|
|
161
|
+
"@type": "SearchAction",
|
|
162
|
+
target: {
|
|
163
|
+
"@type": "EntryPoint",
|
|
164
|
+
urlTemplate: searchUrl
|
|
165
|
+
},
|
|
166
|
+
"query-input": "required name=search_term_string"
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
return jsonLd;
|
|
170
|
+
}
|
|
171
|
+
function serializeJsonLd(jsonLd) {
|
|
172
|
+
return JSON.stringify(jsonLd, null, 2);
|
|
173
|
+
}
|
|
174
|
+
function generateRssFeed(options) {
|
|
175
|
+
const feedUrl = `${options.baseUrl}/api/feed.xml`;
|
|
176
|
+
const postPath = options.postPath ?? "/posts";
|
|
177
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
178
|
+
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
|
179
|
+
<channel>
|
|
180
|
+
<title>${escapeXml(options.title)}</title>
|
|
181
|
+
<description>${escapeXml(options.description)}</description>
|
|
182
|
+
<link>${escapeXml(options.baseUrl)}</link>
|
|
183
|
+
<atom:link href="${escapeXml(feedUrl)}" rel="self" type="application/rss+xml"/>
|
|
184
|
+
<lastBuildDate>${(/* @__PURE__ */ new Date()).toUTCString()}</lastBuildDate>
|
|
185
|
+
${options.posts.map((post) => {
|
|
186
|
+
const postUrl = `${options.baseUrl}${postPath}/${encodeURIComponent(post.slug)}`;
|
|
187
|
+
return `
|
|
188
|
+
<item>
|
|
189
|
+
<title>${escapeXml(post.title)}</title>
|
|
190
|
+
<link>${escapeXml(postUrl)}</link>
|
|
191
|
+
<guid isPermaLink="true">${escapeXml(postUrl)}</guid>
|
|
192
|
+
<description>${escapeXml(post.description || post.excerpt)}</description>
|
|
193
|
+
${post.date ? `<pubDate>${new Date(post.date).toUTCString()}</pubDate>` : ""}
|
|
194
|
+
${(post.tags ?? []).map((tag) => `<category>${escapeXml(tag)}</category>`).join("\n ")}
|
|
195
|
+
</item>`;
|
|
196
|
+
}).join("")}
|
|
197
|
+
</channel>
|
|
198
|
+
</rss>`;
|
|
199
|
+
}
|
|
200
|
+
function generateJsonFeed(options) {
|
|
201
|
+
const postPath = options.postPath ?? "/posts";
|
|
202
|
+
return {
|
|
203
|
+
version: "https://jsonfeed.org/version/1.1",
|
|
204
|
+
title: options.title,
|
|
205
|
+
description: options.description,
|
|
206
|
+
home_page_url: options.baseUrl,
|
|
207
|
+
feed_url: `${options.baseUrl}/api/feed.json`,
|
|
208
|
+
icon: options.logo,
|
|
209
|
+
items: options.posts.map((post) => {
|
|
210
|
+
const postUrl = `${options.baseUrl}${postPath}/${encodeURIComponent(post.slug)}`;
|
|
211
|
+
return {
|
|
212
|
+
id: postUrl,
|
|
213
|
+
url: postUrl,
|
|
214
|
+
title: post.title,
|
|
215
|
+
summary: post.description || post.excerpt,
|
|
216
|
+
image: post.coverImage,
|
|
217
|
+
date_published: post.date,
|
|
218
|
+
authors: post.authorName ? [{ name: post.authorName }] : [],
|
|
219
|
+
tags: post.tags
|
|
220
|
+
};
|
|
221
|
+
})
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
function generateSitemap(baseUrl, posts, options) {
|
|
225
|
+
const postPath = options?.postPath ?? "/posts";
|
|
226
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
227
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
228
|
+
<url>
|
|
229
|
+
<loc>${escapeXml(baseUrl)}</loc>
|
|
230
|
+
<changefreq>daily</changefreq>
|
|
231
|
+
<priority>1.0</priority>
|
|
232
|
+
</url>
|
|
233
|
+
${posts.map((post) => {
|
|
234
|
+
const postUrl = `${baseUrl}${postPath}/${encodeURIComponent(post.slug)}`;
|
|
235
|
+
return `
|
|
236
|
+
<url>
|
|
237
|
+
<loc>${escapeXml(postUrl)}</loc>
|
|
238
|
+
${post.date ? `<lastmod>${new Date(post.date).toISOString().split("T")[0]}</lastmod>` : ""}
|
|
239
|
+
<changefreq>weekly</changefreq>
|
|
240
|
+
<priority>0.8</priority>
|
|
241
|
+
</url>`;
|
|
242
|
+
}).join("")}
|
|
243
|
+
</urlset>`;
|
|
244
|
+
}
|
|
245
|
+
function generateRobotsTxt(sitemapUrl, options) {
|
|
246
|
+
const lines = ["User-agent: *"];
|
|
247
|
+
if (options?.allowPaths) {
|
|
248
|
+
for (const path of options.allowPaths) {
|
|
249
|
+
lines.push(`Allow: ${path}`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
if (options?.disallowPaths) {
|
|
253
|
+
for (const path of options.disallowPaths) {
|
|
254
|
+
lines.push(`Disallow: ${path}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
lines.push("", `Sitemap: ${sitemapUrl}`);
|
|
258
|
+
return lines.join("\n");
|
|
259
|
+
}
|
|
260
|
+
function metaTagsToHtml(tags) {
|
|
261
|
+
return tags.map((tag) => {
|
|
262
|
+
if (tag.title) return `<title>${escapeHtml(tag.title)}</title>`;
|
|
263
|
+
if (tag.tagName === "link") {
|
|
264
|
+
return `<link rel="${escapeHtml(tag.rel)}" href="${escapeHtml(tag.href)}">`;
|
|
265
|
+
}
|
|
266
|
+
if (tag.property) {
|
|
267
|
+
return `<meta property="${escapeHtml(tag.property)}" content="${escapeHtml(tag.content)}">`;
|
|
268
|
+
}
|
|
269
|
+
if (tag.name) {
|
|
270
|
+
return `<meta name="${escapeHtml(tag.name)}" content="${escapeHtml(tag.content)}">`;
|
|
271
|
+
}
|
|
272
|
+
return "";
|
|
273
|
+
}).filter(Boolean).join("\n");
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
exports.createBreadcrumbJsonLd = createBreadcrumbJsonLd;
|
|
277
|
+
exports.createItemListJsonLd = createItemListJsonLd;
|
|
278
|
+
exports.createOrganizationJsonLd = createOrganizationJsonLd;
|
|
279
|
+
exports.createWebsiteJsonLd = createWebsiteJsonLd;
|
|
280
|
+
exports.generateJsonFeed = generateJsonFeed;
|
|
281
|
+
exports.generateListMetaTags = generateListMetaTags;
|
|
282
|
+
exports.generateMetaTags = generateMetaTags;
|
|
283
|
+
exports.generatePostMetaTags = generatePostMetaTags;
|
|
284
|
+
exports.generateRobotsTxt = generateRobotsTxt;
|
|
285
|
+
exports.generateRssFeed = generateRssFeed;
|
|
286
|
+
exports.generateSitemap = generateSitemap;
|
|
287
|
+
exports.metaTagsToHtml = metaTagsToHtml;
|
|
288
|
+
exports.postToArticleJsonLd = postToArticleJsonLd;
|
|
289
|
+
exports.serializeJsonLd = serializeJsonLd;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SEO utilities for folderblog — meta tags, JSON-LD, sitemap, RSS, JSON Feed, robots.txt.
|
|
3
|
+
*
|
|
4
|
+
* Framework-agnostic pure functions. No dependencies on folderblog/local or processor.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { generateMetaTags, postToArticleJsonLd, generateSitemap } from 'folderblog/seo';
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
interface SeoSiteConfig {
|
|
12
|
+
siteName: string;
|
|
13
|
+
siteUrl: string;
|
|
14
|
+
siteDescription?: string;
|
|
15
|
+
ogImage?: string;
|
|
16
|
+
author?: {
|
|
17
|
+
name: string;
|
|
18
|
+
};
|
|
19
|
+
social?: {
|
|
20
|
+
twitter?: string;
|
|
21
|
+
github?: string;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
interface SeoPost {
|
|
25
|
+
slug: string;
|
|
26
|
+
title: string;
|
|
27
|
+
description?: string;
|
|
28
|
+
excerpt?: string;
|
|
29
|
+
date?: string;
|
|
30
|
+
tags?: string[];
|
|
31
|
+
categories?: string[];
|
|
32
|
+
coverImage?: string;
|
|
33
|
+
authorName?: string;
|
|
34
|
+
}
|
|
35
|
+
interface MetaTag {
|
|
36
|
+
title?: string;
|
|
37
|
+
name?: string;
|
|
38
|
+
property?: string;
|
|
39
|
+
content?: string;
|
|
40
|
+
tagName?: string;
|
|
41
|
+
rel?: string;
|
|
42
|
+
href?: string;
|
|
43
|
+
}
|
|
44
|
+
interface MetaTagOptions {
|
|
45
|
+
title?: string;
|
|
46
|
+
description?: string;
|
|
47
|
+
image?: string;
|
|
48
|
+
url?: string;
|
|
49
|
+
type?: "website" | "article";
|
|
50
|
+
article?: {
|
|
51
|
+
publishedTime?: string;
|
|
52
|
+
modifiedTime?: string;
|
|
53
|
+
author?: string;
|
|
54
|
+
section?: string;
|
|
55
|
+
tags?: string[];
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
declare function generateMetaTags(site: SeoSiteConfig, options: MetaTagOptions): MetaTag[];
|
|
59
|
+
declare function generatePostMetaTags(site: SeoSiteConfig, post: SeoPost, url: string): MetaTag[];
|
|
60
|
+
declare function generateListMetaTags(site: SeoSiteConfig, title: string, description: string, url: string, pageNumber?: number): MetaTag[];
|
|
61
|
+
interface JsonLd {
|
|
62
|
+
"@context": string;
|
|
63
|
+
"@type": string;
|
|
64
|
+
[key: string]: unknown;
|
|
65
|
+
}
|
|
66
|
+
declare function postToArticleJsonLd(site: SeoSiteConfig, post: SeoPost, url: string): JsonLd;
|
|
67
|
+
declare function createItemListJsonLd(posts: SeoPost[], listName: string, listDescription?: string, baseUrl?: string): JsonLd;
|
|
68
|
+
declare function createBreadcrumbJsonLd(items: Array<{
|
|
69
|
+
name: string;
|
|
70
|
+
url?: string;
|
|
71
|
+
}>): JsonLd;
|
|
72
|
+
declare function createOrganizationJsonLd(site: SeoSiteConfig): JsonLd;
|
|
73
|
+
declare function createWebsiteJsonLd(site: SeoSiteConfig, searchUrl?: string): JsonLd;
|
|
74
|
+
declare function serializeJsonLd(jsonLd: JsonLd): string;
|
|
75
|
+
interface FeedOptions {
|
|
76
|
+
title: string;
|
|
77
|
+
description?: string;
|
|
78
|
+
baseUrl: string;
|
|
79
|
+
/** URL path prefix for posts (default: "/posts") */
|
|
80
|
+
postPath?: string;
|
|
81
|
+
logo?: string;
|
|
82
|
+
posts: SeoPost[];
|
|
83
|
+
}
|
|
84
|
+
declare function generateRssFeed(options: FeedOptions): string;
|
|
85
|
+
declare function generateJsonFeed(options: FeedOptions): object;
|
|
86
|
+
declare function generateSitemap(baseUrl: string, posts: SeoPost[], options?: {
|
|
87
|
+
postPath?: string;
|
|
88
|
+
}): string;
|
|
89
|
+
declare function generateRobotsTxt(sitemapUrl: string, options?: {
|
|
90
|
+
disallowPaths?: string[];
|
|
91
|
+
allowPaths?: string[];
|
|
92
|
+
}): string;
|
|
93
|
+
declare function metaTagsToHtml(tags: MetaTag[]): string;
|
|
94
|
+
|
|
95
|
+
export { type FeedOptions, type JsonLd, type MetaTag, type MetaTagOptions, type SeoPost, type SeoSiteConfig, createBreadcrumbJsonLd, createItemListJsonLd, createOrganizationJsonLd, createWebsiteJsonLd, generateJsonFeed, generateListMetaTags, generateMetaTags, generatePostMetaTags, generateRobotsTxt, generateRssFeed, generateSitemap, metaTagsToHtml, postToArticleJsonLd, serializeJsonLd };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SEO utilities for folderblog — meta tags, JSON-LD, sitemap, RSS, JSON Feed, robots.txt.
|
|
3
|
+
*
|
|
4
|
+
* Framework-agnostic pure functions. No dependencies on folderblog/local or processor.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { generateMetaTags, postToArticleJsonLd, generateSitemap } from 'folderblog/seo';
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
interface SeoSiteConfig {
|
|
12
|
+
siteName: string;
|
|
13
|
+
siteUrl: string;
|
|
14
|
+
siteDescription?: string;
|
|
15
|
+
ogImage?: string;
|
|
16
|
+
author?: {
|
|
17
|
+
name: string;
|
|
18
|
+
};
|
|
19
|
+
social?: {
|
|
20
|
+
twitter?: string;
|
|
21
|
+
github?: string;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
interface SeoPost {
|
|
25
|
+
slug: string;
|
|
26
|
+
title: string;
|
|
27
|
+
description?: string;
|
|
28
|
+
excerpt?: string;
|
|
29
|
+
date?: string;
|
|
30
|
+
tags?: string[];
|
|
31
|
+
categories?: string[];
|
|
32
|
+
coverImage?: string;
|
|
33
|
+
authorName?: string;
|
|
34
|
+
}
|
|
35
|
+
interface MetaTag {
|
|
36
|
+
title?: string;
|
|
37
|
+
name?: string;
|
|
38
|
+
property?: string;
|
|
39
|
+
content?: string;
|
|
40
|
+
tagName?: string;
|
|
41
|
+
rel?: string;
|
|
42
|
+
href?: string;
|
|
43
|
+
}
|
|
44
|
+
interface MetaTagOptions {
|
|
45
|
+
title?: string;
|
|
46
|
+
description?: string;
|
|
47
|
+
image?: string;
|
|
48
|
+
url?: string;
|
|
49
|
+
type?: "website" | "article";
|
|
50
|
+
article?: {
|
|
51
|
+
publishedTime?: string;
|
|
52
|
+
modifiedTime?: string;
|
|
53
|
+
author?: string;
|
|
54
|
+
section?: string;
|
|
55
|
+
tags?: string[];
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
declare function generateMetaTags(site: SeoSiteConfig, options: MetaTagOptions): MetaTag[];
|
|
59
|
+
declare function generatePostMetaTags(site: SeoSiteConfig, post: SeoPost, url: string): MetaTag[];
|
|
60
|
+
declare function generateListMetaTags(site: SeoSiteConfig, title: string, description: string, url: string, pageNumber?: number): MetaTag[];
|
|
61
|
+
interface JsonLd {
|
|
62
|
+
"@context": string;
|
|
63
|
+
"@type": string;
|
|
64
|
+
[key: string]: unknown;
|
|
65
|
+
}
|
|
66
|
+
declare function postToArticleJsonLd(site: SeoSiteConfig, post: SeoPost, url: string): JsonLd;
|
|
67
|
+
declare function createItemListJsonLd(posts: SeoPost[], listName: string, listDescription?: string, baseUrl?: string): JsonLd;
|
|
68
|
+
declare function createBreadcrumbJsonLd(items: Array<{
|
|
69
|
+
name: string;
|
|
70
|
+
url?: string;
|
|
71
|
+
}>): JsonLd;
|
|
72
|
+
declare function createOrganizationJsonLd(site: SeoSiteConfig): JsonLd;
|
|
73
|
+
declare function createWebsiteJsonLd(site: SeoSiteConfig, searchUrl?: string): JsonLd;
|
|
74
|
+
declare function serializeJsonLd(jsonLd: JsonLd): string;
|
|
75
|
+
interface FeedOptions {
|
|
76
|
+
title: string;
|
|
77
|
+
description?: string;
|
|
78
|
+
baseUrl: string;
|
|
79
|
+
/** URL path prefix for posts (default: "/posts") */
|
|
80
|
+
postPath?: string;
|
|
81
|
+
logo?: string;
|
|
82
|
+
posts: SeoPost[];
|
|
83
|
+
}
|
|
84
|
+
declare function generateRssFeed(options: FeedOptions): string;
|
|
85
|
+
declare function generateJsonFeed(options: FeedOptions): object;
|
|
86
|
+
declare function generateSitemap(baseUrl: string, posts: SeoPost[], options?: {
|
|
87
|
+
postPath?: string;
|
|
88
|
+
}): string;
|
|
89
|
+
declare function generateRobotsTxt(sitemapUrl: string, options?: {
|
|
90
|
+
disallowPaths?: string[];
|
|
91
|
+
allowPaths?: string[];
|
|
92
|
+
}): string;
|
|
93
|
+
declare function metaTagsToHtml(tags: MetaTag[]): string;
|
|
94
|
+
|
|
95
|
+
export { type FeedOptions, type JsonLd, type MetaTag, type MetaTagOptions, type SeoPost, type SeoSiteConfig, createBreadcrumbJsonLd, createItemListJsonLd, createOrganizationJsonLd, createWebsiteJsonLd, generateJsonFeed, generateListMetaTags, generateMetaTags, generatePostMetaTags, generateRobotsTxt, generateRssFeed, generateSitemap, metaTagsToHtml, postToArticleJsonLd, serializeJsonLd };
|