vaza-content 0.2.0 → 0.2.2
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/adapters/astro/index.cjs +9 -15
- package/dist/adapters/astro/index.cjs.map +1 -1
- package/dist/adapters/astro/index.d.cts +4 -3
- package/dist/adapters/astro/index.d.ts +4 -3
- package/dist/adapters/astro/index.js +6 -12
- package/dist/adapters/astro/index.js.map +1 -1
- package/dist/adapters/next/index.cjs +11 -12
- package/dist/adapters/next/index.cjs.map +1 -1
- package/dist/adapters/next/index.d.cts +5 -3
- package/dist/adapters/next/index.d.ts +5 -3
- package/dist/adapters/next/index.js +8 -9
- package/dist/adapters/next/index.js.map +1 -1
- package/dist/adapters/nuxt/index.cjs +22 -22
- package/dist/adapters/nuxt/index.cjs.map +1 -1
- package/dist/adapters/nuxt/index.d.cts +11 -7
- package/dist/adapters/nuxt/index.d.ts +11 -7
- package/dist/adapters/nuxt/index.js +13 -13
- package/dist/adapters/nuxt/index.js.map +1 -1
- package/dist/adapters/sveltekit/index.cjs +9 -15
- package/dist/adapters/sveltekit/index.cjs.map +1 -1
- package/dist/adapters/sveltekit/index.d.cts +3 -2
- package/dist/adapters/sveltekit/index.d.ts +3 -2
- package/dist/adapters/sveltekit/index.js +5 -11
- package/dist/adapters/sveltekit/index.js.map +1 -1
- package/dist/{blog-7EEJJG26.js → blog-L7HRY3QC.js} +2 -4
- package/dist/{blog-7EEJJG26.js.map → blog-L7HRY3QC.js.map} +1 -1
- package/dist/{blog-Z3R5GOMP.cjs → blog-SEXXJJSV.cjs} +3 -5
- package/dist/blog-SEXXJJSV.cjs.map +1 -0
- package/dist/{chunk-YV2ZYIAD.cjs → chunk-H3D7F4TA.cjs} +544 -503
- package/dist/chunk-H3D7F4TA.cjs.map +1 -0
- package/dist/{chunk-FALSVGPG.js → chunk-OKXBDPYF.js} +511 -470
- package/dist/chunk-OKXBDPYF.js.map +1 -0
- package/dist/cli/index.cjs +30 -24
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +29 -23
- package/dist/cli/index.js.map +1 -1
- package/dist/{dark-EX2GRAYK.cjs → dark-66ZWYLT7.cjs} +2 -4
- package/dist/dark-66ZWYLT7.cjs.map +1 -0
- package/dist/{dark-6E36AKLN.js → dark-SZOURAMM.js} +1 -3
- package/dist/{dark-6E36AKLN.js.map → dark-SZOURAMM.js.map} +1 -1
- package/dist/index.cjs +8 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -29
- package/dist/index.d.ts +29 -29
- package/dist/index.js +3 -6
- package/dist/index.js.map +1 -1
- package/dist/{minimal-D2PRAVG6.js → minimal-CGXF737F.js} +1 -3
- package/dist/{minimal-D2PRAVG6.js.map → minimal-CGXF737F.js.map} +1 -1
- package/dist/{minimal-RHOK4XEZ.cjs → minimal-XTTHXE3T.cjs} +2 -4
- package/dist/minimal-XTTHXE3T.cjs.map +1 -0
- package/dist/process-VXDWM664.cjs +7 -0
- package/dist/process-VXDWM664.cjs.map +1 -0
- package/dist/process-ZQV5M2TB.js +7 -0
- package/dist/{product-OT3XYMWD.cjs → product-BY3GVQGV.cjs} +2 -4
- package/dist/product-BY3GVQGV.cjs.map +1 -0
- package/dist/{product-NCUW3U72.js → product-UQXUI5YL.js} +1 -3
- package/dist/{product-NCUW3U72.js.map → product-UQXUI5YL.js.map} +1 -1
- package/dist/{types-CgaidvaB.d.cts → types-DAfWIHiD.d.cts} +1 -1
- package/dist/{types-CgaidvaB.d.ts → types-DAfWIHiD.d.ts} +1 -1
- package/package.json +6 -4
- package/dist/blog-Z3R5GOMP.cjs.map +0 -1
- package/dist/chunk-DGUM43GV.js +0 -11
- package/dist/chunk-FALSVGPG.js.map +0 -1
- package/dist/chunk-JEQ2X3Z6.cjs +0 -11
- package/dist/chunk-JEQ2X3Z6.cjs.map +0 -1
- package/dist/chunk-PCRQY47G.js +0 -35
- package/dist/chunk-PCRQY47G.js.map +0 -1
- package/dist/chunk-WOCXEBQC.cjs +0 -35
- package/dist/chunk-WOCXEBQC.cjs.map +0 -1
- package/dist/chunk-YV2ZYIAD.cjs.map +0 -1
- package/dist/dark-EX2GRAYK.cjs.map +0 -1
- package/dist/logger-7WBTEDED.cjs +0 -10
- package/dist/logger-7WBTEDED.cjs.map +0 -1
- package/dist/logger-BGP7C274.js +0 -10
- package/dist/logger-BGP7C274.js.map +0 -1
- package/dist/minimal-RHOK4XEZ.cjs.map +0 -1
- package/dist/process-B4PJ6CWC.cjs +0 -9
- package/dist/process-B4PJ6CWC.cjs.map +0 -1
- package/dist/process-KSSXQJE6.js +0 -9
- package/dist/process-KSSXQJE6.js.map +0 -1
- package/dist/product-OT3XYMWD.cjs.map +0 -1
- /package/dist/{chunk-DGUM43GV.js.map → process-ZQV5M2TB.js.map} +0 -0
|
@@ -1,306 +1,6 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var _chunkWOCXEBQCcjs = require('./chunk-WOCXEBQC.cjs');
|
|
5
|
-
|
|
6
|
-
// src/normalize/blur-placeholder.ts
|
|
7
|
-
var _sharp = require('sharp'); var _sharp2 = _interopRequireDefault(_sharp);
|
|
8
|
-
async function generateBlurPlaceholder(imagePath) {
|
|
9
|
-
try {
|
|
10
|
-
const buffer = await _sharp2.default.call(void 0, imagePath).resize(8, 8, { fit: "inside" }).blur().png().toBuffer();
|
|
11
|
-
return `data:image/png;base64,${buffer.toString("base64")}`;
|
|
12
|
-
} catch (e2) {
|
|
13
|
-
return void 0;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// src/constants.ts
|
|
18
|
-
var WORDS_PER_MINUTE = 200;
|
|
19
|
-
var EXCERPT_MAX_LENGTH = 160;
|
|
20
|
-
var DEFAULT_META_TITLE_MAX = 60;
|
|
21
|
-
var DEFAULT_META_DESC_MAX = 120;
|
|
22
|
-
var DEFAULT_FRESHNESS_MAX_AGE = "6m";
|
|
23
|
-
var DEFAULT_RSS_LIMIT = 50;
|
|
24
|
-
var DEFAULT_SITEMAP_PRIORITY = 0.7;
|
|
25
|
-
var DEFAULT_SITEMAP_CHANGE_FREQ = "weekly";
|
|
26
|
-
var OG_IMAGE_WIDTH = 1200;
|
|
27
|
-
var OG_IMAGE_HEIGHT = 630;
|
|
28
|
-
var OG_IMAGE_CONCURRENCY = 5;
|
|
29
|
-
|
|
30
|
-
// src/normalize/excerpt.ts
|
|
31
|
-
function stripMarkdown(text) {
|
|
32
|
-
return text.replace(/```[\s\S]*?```/g, "").replace(/!\[.*?\]\(.*?\)/g, "").replace(/\[([^\]]*)\]\(.*?\)/g, "$1").replace(/^#{1,6}\s+/gm, "").replace(/\*{1,3}(.*?)\*{1,3}/g, "$1").replace(/_{1,3}(.*?)_{1,3}/g, "$1").replace(/`([^`]*)`/g, "$1").replace(/^>\s+/gm, "").replace(/^[-*_]{3,}\s*$/gm, "").replace(/<[^>]+>/g, "").replace(/\s+/g, " ").trim();
|
|
33
|
-
}
|
|
34
|
-
function generateExcerpt(body, maxLength = EXCERPT_MAX_LENGTH) {
|
|
35
|
-
const clean = stripMarkdown(body);
|
|
36
|
-
if (clean.length <= maxLength) {
|
|
37
|
-
return clean;
|
|
38
|
-
}
|
|
39
|
-
const truncated = clean.slice(0, maxLength);
|
|
40
|
-
const lastSpace = truncated.lastIndexOf(" ");
|
|
41
|
-
if (lastSpace === -1) {
|
|
42
|
-
return truncated.slice(0, maxLength);
|
|
43
|
-
}
|
|
44
|
-
return truncated.slice(0, lastSpace);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// src/normalize/description.ts
|
|
48
|
-
function generateDescription(body, excerpt) {
|
|
49
|
-
return _nullishCoalesce(excerpt, () => ( generateExcerpt(body)));
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// src/normalize/image-dimensions.ts
|
|
53
|
-
|
|
54
|
-
async function getImageDimensions(imagePath) {
|
|
55
|
-
try {
|
|
56
|
-
const metadata = await _sharp2.default.call(void 0, imagePath).metadata();
|
|
57
|
-
if (metadata.width && metadata.height) {
|
|
58
|
-
return { width: metadata.width, height: metadata.height };
|
|
59
|
-
}
|
|
60
|
-
return void 0;
|
|
61
|
-
} catch (e3) {
|
|
62
|
-
return void 0;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// src/normalize/word-count.ts
|
|
67
|
-
function calcWordCount(body) {
|
|
68
|
-
return body.trim().split(/\s+/).filter(Boolean).length;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// src/normalize/reading-time.ts
|
|
72
|
-
function calcReadingTime(body) {
|
|
73
|
-
const words = calcWordCount(body);
|
|
74
|
-
return Math.max(1, Math.ceil(words / WORDS_PER_MINUTE));
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// src/normalize/slug.ts
|
|
78
|
-
function generateSlug(title) {
|
|
79
|
-
return title.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// src/normalize/toc.ts
|
|
83
|
-
function toAnchorSlug(text) {
|
|
84
|
-
return text.toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
85
|
-
}
|
|
86
|
-
function extractToc(body) {
|
|
87
|
-
const headingRegex = /^(#{2,3})\s+(.+)$/gm;
|
|
88
|
-
const items = [];
|
|
89
|
-
let match;
|
|
90
|
-
while ((match = headingRegex.exec(body)) !== null) {
|
|
91
|
-
const depth = match[1].length;
|
|
92
|
-
const text = match[2].trim();
|
|
93
|
-
items.push({
|
|
94
|
-
depth,
|
|
95
|
-
text,
|
|
96
|
-
slug: toAnchorSlug(text)
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
return items;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// src/normalize/index.ts
|
|
103
|
-
function toDate(value) {
|
|
104
|
-
if (value === void 0) return void 0;
|
|
105
|
-
if (value instanceof Date) return value;
|
|
106
|
-
return new Date(value);
|
|
107
|
-
}
|
|
108
|
-
async function normalize(partial) {
|
|
109
|
-
const { body, title } = partial;
|
|
110
|
-
const slug = partial.slug || generateSlug(title);
|
|
111
|
-
const wordCount = _nullishCoalesce(partial.wordCount, () => ( calcWordCount(body)));
|
|
112
|
-
const readingTime = _nullishCoalesce(partial.readingTime, () => ( calcReadingTime(body)));
|
|
113
|
-
const excerpt = _nullishCoalesce(partial.excerpt, () => ( generateExcerpt(body)));
|
|
114
|
-
const toc = _nullishCoalesce(partial.toc, () => ( extractToc(body)));
|
|
115
|
-
const description = _nullishCoalesce(partial.description, () => ( generateDescription(body, excerpt)));
|
|
116
|
-
const publishDate = _nullishCoalesce(toDate(partial.publishDate), () => ( /* @__PURE__ */ new Date()));
|
|
117
|
-
const updateDate = toDate(partial.updateDate);
|
|
118
|
-
const eventDate = toDate(partial.eventDate);
|
|
119
|
-
let image = partial.image ? { ...partial.image } : void 0;
|
|
120
|
-
if (_optionalChain([image, 'optionalAccess', _ => _.src])) {
|
|
121
|
-
if (!image.blurDataURL) {
|
|
122
|
-
image.blurDataURL = await generateBlurPlaceholder(image.src);
|
|
123
|
-
}
|
|
124
|
-
if (!image.width || !image.height) {
|
|
125
|
-
const dims = await getImageDimensions(image.src);
|
|
126
|
-
if (dims) {
|
|
127
|
-
image.width = dims.width;
|
|
128
|
-
image.height = dims.height;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
const entry = {
|
|
133
|
-
slug,
|
|
134
|
-
title,
|
|
135
|
-
body,
|
|
136
|
-
description,
|
|
137
|
-
publishDate,
|
|
138
|
-
readingTime,
|
|
139
|
-
wordCount,
|
|
140
|
-
excerpt,
|
|
141
|
-
toc,
|
|
142
|
-
...updateDate && { updateDate },
|
|
143
|
-
...image && { image },
|
|
144
|
-
...partial.tags && { tags: partial.tags },
|
|
145
|
-
...partial.category && { category: partial.category },
|
|
146
|
-
...partial.author && { author: partial.author },
|
|
147
|
-
...partial.relatedEntries && { relatedEntries: partial.relatedEntries },
|
|
148
|
-
...partial.canonical && { canonical: partial.canonical },
|
|
149
|
-
...partial.noindex !== void 0 && { noindex: partial.noindex },
|
|
150
|
-
...partial.jsonLdType && { jsonLdType: partial.jsonLdType },
|
|
151
|
-
...partial.faqs && { faqs: partial.faqs },
|
|
152
|
-
...partial.steps && { steps: partial.steps },
|
|
153
|
-
...partial.price && { price: partial.price },
|
|
154
|
-
...partial.ingredients && { ingredients: partial.ingredients },
|
|
155
|
-
...partial.cookTime && { cookTime: partial.cookTime },
|
|
156
|
-
...eventDate && { eventDate },
|
|
157
|
-
...partial.eventLocation && { eventLocation: partial.eventLocation }
|
|
158
|
-
};
|
|
159
|
-
return entry;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// src/generate/sitemap.ts
|
|
163
|
-
function generateSitemap(entries, config) {
|
|
164
|
-
const siteUrl = config.site.url.replace(/\/$/, "");
|
|
165
|
-
const defaultChangeFreq = _nullishCoalesce(_optionalChain([config, 'access', _2 => _2.sitemap, 'optionalAccess', _3 => _3.changeFrequency]), () => ( DEFAULT_SITEMAP_CHANGE_FREQ));
|
|
166
|
-
const defaultPriority = _nullishCoalesce(_optionalChain([config, 'access', _4 => _4.sitemap, 'optionalAccess', _5 => _5.priority]), () => ( DEFAULT_SITEMAP_PRIORITY));
|
|
167
|
-
const collectionKeys = Object.keys(config.collections);
|
|
168
|
-
const fallbackBasePath = collectionKeys.length > 0 ? config.collections[collectionKeys[0]].basePath : "";
|
|
169
|
-
const sitemapEntries = [];
|
|
170
|
-
for (const entry of entries) {
|
|
171
|
-
if (entry.noindex) continue;
|
|
172
|
-
const basePath = (_nullishCoalesce(entry._basePath, () => ( fallbackBasePath))).replace(/\/$/, "");
|
|
173
|
-
const loc = `${siteUrl}${basePath}/${entry.slug}`;
|
|
174
|
-
const lastmod = (_nullishCoalesce(entry.updateDate, () => ( entry.publishDate))).toISOString();
|
|
175
|
-
const sitemapEntry = {
|
|
176
|
-
loc,
|
|
177
|
-
lastmod,
|
|
178
|
-
changefreq: defaultChangeFreq,
|
|
179
|
-
priority: defaultPriority
|
|
180
|
-
};
|
|
181
|
-
if (entry.image) {
|
|
182
|
-
sitemapEntry.images = [
|
|
183
|
-
{
|
|
184
|
-
loc: entry.image.src.startsWith("http") ? entry.image.src : `${siteUrl}${entry.image.src}`,
|
|
185
|
-
title: entry.image.alt
|
|
186
|
-
}
|
|
187
|
-
];
|
|
188
|
-
}
|
|
189
|
-
sitemapEntries.push(sitemapEntry);
|
|
190
|
-
}
|
|
191
|
-
if (_optionalChain([config, 'access', _6 => _6.sitemap, 'optionalAccess', _7 => _7.additionalPaths])) {
|
|
192
|
-
for (const path of config.sitemap.additionalPaths) {
|
|
193
|
-
sitemapEntries.push({
|
|
194
|
-
loc: `${siteUrl}${path}`,
|
|
195
|
-
changefreq: defaultChangeFreq,
|
|
196
|
-
priority: defaultPriority
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
return sitemapEntries;
|
|
201
|
-
}
|
|
202
|
-
function renderSitemapXml(entries) {
|
|
203
|
-
const hasImages = entries.some((e) => e.images && e.images.length > 0);
|
|
204
|
-
const lines = [
|
|
205
|
-
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
206
|
-
`<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"${hasImages ? ' xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"' : ""}>`
|
|
207
|
-
];
|
|
208
|
-
for (const entry of entries) {
|
|
209
|
-
lines.push(" <url>");
|
|
210
|
-
lines.push(` <loc>${escapeXml(entry.loc)}</loc>`);
|
|
211
|
-
if (entry.lastmod) {
|
|
212
|
-
lines.push(` <lastmod>${entry.lastmod}</lastmod>`);
|
|
213
|
-
}
|
|
214
|
-
if (entry.changefreq) {
|
|
215
|
-
lines.push(` <changefreq>${entry.changefreq}</changefreq>`);
|
|
216
|
-
}
|
|
217
|
-
if (entry.priority !== void 0) {
|
|
218
|
-
lines.push(` <priority>${entry.priority}</priority>`);
|
|
219
|
-
}
|
|
220
|
-
if (entry.images) {
|
|
221
|
-
for (const img of entry.images) {
|
|
222
|
-
lines.push(" <image:image>");
|
|
223
|
-
lines.push(` <image:loc>${escapeXml(img.loc)}</image:loc>`);
|
|
224
|
-
if (img.title) {
|
|
225
|
-
lines.push(
|
|
226
|
-
` <image:title>${escapeXml(img.title)}</image:title>`
|
|
227
|
-
);
|
|
228
|
-
}
|
|
229
|
-
lines.push(" </image:image>");
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
lines.push(" </url>");
|
|
233
|
-
}
|
|
234
|
-
lines.push("</urlset>");
|
|
235
|
-
return lines.join("\n");
|
|
236
|
-
}
|
|
237
|
-
function escapeXml(str) {
|
|
238
|
-
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// src/generate/rss.ts
|
|
242
|
-
function generateRss(entries, config) {
|
|
243
|
-
const siteUrl = config.site.url.replace(/\/$/, "");
|
|
244
|
-
const limit = _nullishCoalesce(_optionalChain([config, 'access', _8 => _8.rss, 'optionalAccess', _9 => _9.limit]), () => ( DEFAULT_RSS_LIMIT));
|
|
245
|
-
const collectionKeys = Object.keys(config.collections);
|
|
246
|
-
const fallbackBasePath = collectionKeys.length > 0 ? config.collections[collectionKeys[0]].basePath : "";
|
|
247
|
-
const sorted = [...entries].filter((e) => !e.noindex).sort((a, b) => b.publishDate.getTime() - a.publishDate.getTime());
|
|
248
|
-
const limited = sorted.slice(0, limit);
|
|
249
|
-
return limited.map((entry) => {
|
|
250
|
-
const basePath = (_nullishCoalesce(entry._basePath, () => ( fallbackBasePath))).replace(/\/$/, "");
|
|
251
|
-
const link = `${siteUrl}${basePath}/${entry.slug}`;
|
|
252
|
-
return {
|
|
253
|
-
title: entry.title,
|
|
254
|
-
link,
|
|
255
|
-
description: entry.description || entry.excerpt,
|
|
256
|
-
pubDate: entry.publishDate.toUTCString(),
|
|
257
|
-
guid: link,
|
|
258
|
-
author: _optionalChain([entry, 'access', _10 => _10.author, 'optionalAccess', _11 => _11.name])
|
|
259
|
-
};
|
|
260
|
-
});
|
|
261
|
-
}
|
|
262
|
-
function renderRssXml(items, config) {
|
|
263
|
-
const siteUrl = config.site.url.replace(/\/$/, "");
|
|
264
|
-
const lines = [
|
|
265
|
-
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
266
|
-
'<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">',
|
|
267
|
-
" <channel>",
|
|
268
|
-
` <title>${escapeXml2(config.site.name)}</title>`,
|
|
269
|
-
` <link>${escapeXml2(siteUrl)}</link>`,
|
|
270
|
-
` <description>${escapeXml2(_nullishCoalesce(config.site.description, () => ( "")))}</description>`,
|
|
271
|
-
` <language>${_nullishCoalesce(config.site.language, () => ( "en"))}</language>`,
|
|
272
|
-
` <lastBuildDate>${(/* @__PURE__ */ new Date()).toUTCString()}</lastBuildDate>`
|
|
273
|
-
];
|
|
274
|
-
if (_optionalChain([config, 'access', _12 => _12.rss, 'optionalAccess', _13 => _13.path])) {
|
|
275
|
-
lines.push(
|
|
276
|
-
` <atom:link href="${escapeXml2(siteUrl + config.rss.path)}" rel="self" type="application/rss+xml" />`
|
|
277
|
-
);
|
|
278
|
-
}
|
|
279
|
-
for (const item of items) {
|
|
280
|
-
lines.push(" <item>");
|
|
281
|
-
lines.push(` <title>${escapeXml2(item.title)}</title>`);
|
|
282
|
-
lines.push(` <link>${escapeXml2(item.link)}</link>`);
|
|
283
|
-
lines.push(
|
|
284
|
-
` <description>${escapeXml2(item.description)}</description>`
|
|
285
|
-
);
|
|
286
|
-
lines.push(` <pubDate>${item.pubDate}</pubDate>`);
|
|
287
|
-
lines.push(` <guid isPermaLink="true">${escapeXml2(item.guid)}</guid>`);
|
|
288
|
-
if (item.author) {
|
|
289
|
-
lines.push(` <author>${escapeXml2(item.author)}</author>`);
|
|
290
|
-
}
|
|
291
|
-
lines.push(" </item>");
|
|
292
|
-
}
|
|
293
|
-
lines.push(" </channel>");
|
|
294
|
-
lines.push("</rss>");
|
|
295
|
-
return lines.join("\n");
|
|
296
|
-
}
|
|
297
|
-
function escapeXml2(str) {
|
|
298
|
-
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
// src/generate/json-ld/article.ts
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/generate/json-ld/article.ts
|
|
302
2
|
function generateArticleSchema(entry, site) {
|
|
303
|
-
if (!entry.title || !entry.publishDate
|
|
3
|
+
if (!entry.title || !entry.publishDate) {
|
|
304
4
|
return null;
|
|
305
5
|
}
|
|
306
6
|
const schema = {
|
|
@@ -309,17 +9,19 @@ function generateArticleSchema(entry, site) {
|
|
|
309
9
|
headline: entry.title,
|
|
310
10
|
description: entry.description || entry.excerpt,
|
|
311
11
|
datePublished: entry.publishDate.toISOString(),
|
|
312
|
-
author: {
|
|
313
|
-
"@type": "Person",
|
|
314
|
-
name: entry.author.name,
|
|
315
|
-
...entry.author.url && { url: entry.author.url }
|
|
316
|
-
},
|
|
317
12
|
publisher: {
|
|
318
13
|
"@type": "Organization",
|
|
319
14
|
name: site.name,
|
|
320
15
|
...site.url && { url: site.url }
|
|
321
16
|
}
|
|
322
17
|
};
|
|
18
|
+
if (entry.author) {
|
|
19
|
+
schema.author = {
|
|
20
|
+
"@type": "Person",
|
|
21
|
+
name: entry.author.name,
|
|
22
|
+
...entry.author.url && { url: entry.author.url }
|
|
23
|
+
};
|
|
24
|
+
}
|
|
323
25
|
if (entry.updateDate) {
|
|
324
26
|
schema.dateModified = entry.updateDate.toISOString();
|
|
325
27
|
}
|
|
@@ -337,25 +39,6 @@ function generateArticleSchema(entry, site) {
|
|
|
337
39
|
return schema;
|
|
338
40
|
}
|
|
339
41
|
|
|
340
|
-
// src/generate/json-ld/faq.ts
|
|
341
|
-
function generateFaqSchema(entry, _site) {
|
|
342
|
-
if (!entry.faqs || entry.faqs.length === 0) {
|
|
343
|
-
return null;
|
|
344
|
-
}
|
|
345
|
-
return {
|
|
346
|
-
"@context": "https://schema.org",
|
|
347
|
-
"@type": "FAQPage",
|
|
348
|
-
mainEntity: entry.faqs.map((faq) => ({
|
|
349
|
-
"@type": "Question",
|
|
350
|
-
name: faq.question,
|
|
351
|
-
acceptedAnswer: {
|
|
352
|
-
"@type": "Answer",
|
|
353
|
-
text: faq.answer
|
|
354
|
-
}
|
|
355
|
-
}))
|
|
356
|
-
};
|
|
357
|
-
}
|
|
358
|
-
|
|
359
42
|
// src/generate/breadcrumbs.ts
|
|
360
43
|
function generateBreadcrumbs(slug, title, siteUrl, basePath) {
|
|
361
44
|
const url = siteUrl.replace(/\/$/, "");
|
|
@@ -391,18 +74,71 @@ function generateBreadcrumbs(slug, title, siteUrl, basePath) {
|
|
|
391
74
|
return items;
|
|
392
75
|
}
|
|
393
76
|
|
|
394
|
-
// src/generate/json-ld/breadcrumb.ts
|
|
395
|
-
function generateBreadcrumbSchema(entry, site, basePath) {
|
|
396
|
-
const siteUrl = site.url.replace(/\/$/, "");
|
|
397
|
-
const crumbs = generateBreadcrumbs(
|
|
77
|
+
// src/generate/json-ld/breadcrumb.ts
|
|
78
|
+
function generateBreadcrumbSchema(entry, site, basePath) {
|
|
79
|
+
const siteUrl = site.url.replace(/\/$/, "");
|
|
80
|
+
const crumbs = generateBreadcrumbs(
|
|
81
|
+
entry.slug,
|
|
82
|
+
entry.title,
|
|
83
|
+
siteUrl,
|
|
84
|
+
basePath
|
|
85
|
+
);
|
|
86
|
+
return {
|
|
87
|
+
"@context": "https://schema.org",
|
|
88
|
+
"@type": "BreadcrumbList",
|
|
89
|
+
itemListElement: crumbs.map((crumb, index) => ({
|
|
90
|
+
"@type": "ListItem",
|
|
91
|
+
position: index + 1,
|
|
92
|
+
name: crumb.name,
|
|
93
|
+
item: crumb.url
|
|
94
|
+
}))
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// src/generate/json-ld/event.ts
|
|
99
|
+
function generateEventSchema(entry, site) {
|
|
100
|
+
if (!entry.eventDate) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
const schema = {
|
|
104
|
+
"@context": "https://schema.org",
|
|
105
|
+
"@type": "Event",
|
|
106
|
+
name: entry.title,
|
|
107
|
+
description: entry.description || entry.excerpt,
|
|
108
|
+
startDate: entry.eventDate.toISOString(),
|
|
109
|
+
organizer: {
|
|
110
|
+
"@type": "Organization",
|
|
111
|
+
name: site.name,
|
|
112
|
+
url: site.url
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
if (entry.eventLocation) {
|
|
116
|
+
schema.location = {
|
|
117
|
+
"@type": "Place",
|
|
118
|
+
name: entry.eventLocation
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
if (entry.image) {
|
|
122
|
+
schema.image = entry.image.src.startsWith("http") ? entry.image.src : `${site.url.replace(/\/$/, "")}${entry.image.src}`;
|
|
123
|
+
}
|
|
124
|
+
return schema;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// src/generate/json-ld/faq.ts
|
|
128
|
+
function generateFaqSchema(entry, _site) {
|
|
129
|
+
if (!entry.faqs || entry.faqs.length === 0) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
398
132
|
return {
|
|
399
133
|
"@context": "https://schema.org",
|
|
400
|
-
"@type": "
|
|
401
|
-
|
|
402
|
-
"@type": "
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
134
|
+
"@type": "FAQPage",
|
|
135
|
+
mainEntity: entry.faqs.map((faq) => ({
|
|
136
|
+
"@type": "Question",
|
|
137
|
+
name: faq.question,
|
|
138
|
+
acceptedAnswer: {
|
|
139
|
+
"@type": "Answer",
|
|
140
|
+
text: faq.answer
|
|
141
|
+
}
|
|
406
142
|
}))
|
|
407
143
|
};
|
|
408
144
|
}
|
|
@@ -450,7 +186,7 @@ function generateProductSchema(entry, site) {
|
|
|
450
186
|
}
|
|
451
187
|
|
|
452
188
|
// src/generate/json-ld/recipe.ts
|
|
453
|
-
function generateRecipeSchema(entry,
|
|
189
|
+
function generateRecipeSchema(entry, site) {
|
|
454
190
|
if (!entry.ingredients || entry.ingredients.length === 0) {
|
|
455
191
|
return null;
|
|
456
192
|
}
|
|
@@ -470,35 +206,6 @@ function generateRecipeSchema(entry, _site) {
|
|
|
470
206
|
name: entry.author.name
|
|
471
207
|
};
|
|
472
208
|
}
|
|
473
|
-
if (entry.image) {
|
|
474
|
-
schema.image = entry.image.src;
|
|
475
|
-
}
|
|
476
|
-
return schema;
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
// src/generate/json-ld/event.ts
|
|
480
|
-
function generateEventSchema(entry, site) {
|
|
481
|
-
if (!entry.eventDate) {
|
|
482
|
-
return null;
|
|
483
|
-
}
|
|
484
|
-
const schema = {
|
|
485
|
-
"@context": "https://schema.org",
|
|
486
|
-
"@type": "Event",
|
|
487
|
-
name: entry.title,
|
|
488
|
-
description: entry.description || entry.excerpt,
|
|
489
|
-
startDate: entry.eventDate.toISOString(),
|
|
490
|
-
organizer: {
|
|
491
|
-
"@type": "Organization",
|
|
492
|
-
name: site.name,
|
|
493
|
-
url: site.url
|
|
494
|
-
}
|
|
495
|
-
};
|
|
496
|
-
if (entry.eventLocation) {
|
|
497
|
-
schema.location = {
|
|
498
|
-
"@type": "Place",
|
|
499
|
-
name: entry.eventLocation
|
|
500
|
-
};
|
|
501
|
-
}
|
|
502
209
|
if (entry.image) {
|
|
503
210
|
schema.image = entry.image.src.startsWith("http") ? entry.image.src : `${site.url.replace(/\/$/, "")}${entry.image.src}`;
|
|
504
211
|
}
|
|
@@ -521,7 +228,7 @@ function generateJsonLd(entries, config) {
|
|
|
521
228
|
const collectionKeys = Object.keys(config.collections);
|
|
522
229
|
const fallbackBasePath = collectionKeys.length > 0 ? config.collections[collectionKeys[0]].basePath : "";
|
|
523
230
|
const customGenerators = [];
|
|
524
|
-
if (_optionalChain([config, 'access',
|
|
231
|
+
if (_optionalChain([config, 'access', _ => _.jsonLd, 'optionalAccess', _2 => _2.customSchemas])) {
|
|
525
232
|
for (const [, generator] of Object.entries(config.jsonLd.customSchemas)) {
|
|
526
233
|
customGenerators.push((entry, s) => generator(entry, s));
|
|
527
234
|
}
|
|
@@ -544,9 +251,58 @@ function generateJsonLd(entries, config) {
|
|
|
544
251
|
}
|
|
545
252
|
|
|
546
253
|
// src/generate/og-images.ts
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
|
|
547
260
|
var _fs = require('fs');
|
|
548
261
|
var _path = require('path');
|
|
549
262
|
|
|
263
|
+
// src/constants.ts
|
|
264
|
+
var WORDS_PER_MINUTE = 200;
|
|
265
|
+
var EXCERPT_MAX_LENGTH = 160;
|
|
266
|
+
var DEFAULT_META_TITLE_MAX = 60;
|
|
267
|
+
var DEFAULT_META_DESC_MAX = 120;
|
|
268
|
+
var DEFAULT_FRESHNESS_MAX_AGE = "6m";
|
|
269
|
+
var DEFAULT_RSS_LIMIT = 50;
|
|
270
|
+
var DEFAULT_SITEMAP_PRIORITY = 0.7;
|
|
271
|
+
var DEFAULT_SITEMAP_CHANGE_FREQ = "weekly";
|
|
272
|
+
var OG_IMAGE_WIDTH = 1200;
|
|
273
|
+
var OG_IMAGE_HEIGHT = 630;
|
|
274
|
+
var OG_IMAGE_CONCURRENCY = 5;
|
|
275
|
+
|
|
276
|
+
// src/logger.ts
|
|
277
|
+
var LEVELS = {
|
|
278
|
+
silent: 0,
|
|
279
|
+
error: 1,
|
|
280
|
+
warn: 2,
|
|
281
|
+
info: 3,
|
|
282
|
+
debug: 4
|
|
283
|
+
};
|
|
284
|
+
var currentLevel = "info";
|
|
285
|
+
function setLogLevel(level) {
|
|
286
|
+
currentLevel = level;
|
|
287
|
+
}
|
|
288
|
+
function shouldLog(level) {
|
|
289
|
+
return LEVELS[level] <= LEVELS[currentLevel];
|
|
290
|
+
}
|
|
291
|
+
var logger = {
|
|
292
|
+
error(...args) {
|
|
293
|
+
if (shouldLog("error")) console.error("[vaza-content]", ...args);
|
|
294
|
+
},
|
|
295
|
+
warn(...args) {
|
|
296
|
+
if (shouldLog("warn")) console.warn("[vaza-content]", ...args);
|
|
297
|
+
},
|
|
298
|
+
info(...args) {
|
|
299
|
+
if (shouldLog("info")) console.log("[vaza-content]", ...args);
|
|
300
|
+
},
|
|
301
|
+
debug(...args) {
|
|
302
|
+
if (shouldLog("debug")) console.log("[vaza-content] [debug]", ...args);
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
|
|
550
306
|
// src/utils/concurrency.ts
|
|
551
307
|
async function pMap(items, fn, concurrency) {
|
|
552
308
|
const results = new Array(items.length);
|
|
@@ -570,7 +326,7 @@ var FONT_CACHE_DIR = ".vaza-content/fonts";
|
|
|
570
326
|
var INTER_FONT_URL = "https://fonts.gstatic.com/s/inter/v18/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuLyfAZ9hiA.woff2";
|
|
571
327
|
async function generateOgImages(entries, config) {
|
|
572
328
|
const ogConfig = config.ogImages;
|
|
573
|
-
if (!_optionalChain([ogConfig, 'optionalAccess',
|
|
329
|
+
if (!_optionalChain([ogConfig, 'optionalAccess', _3 => _3.enabled])) return {};
|
|
574
330
|
const outputDir = _nullishCoalesce(ogConfig.outputDir, () => ( _path.join.call(void 0, process.cwd(), "public", "og")));
|
|
575
331
|
const template = _nullishCoalesce(ogConfig.template, () => ( "minimal"));
|
|
576
332
|
const concurrency = Math.max(1, _nullishCoalesce(ogConfig.concurrency, () => ( OG_IMAGE_CONCURRENCY)));
|
|
@@ -596,10 +352,12 @@ async function generateOgImages(entries, config) {
|
|
|
596
352
|
toGenerate.push(entry);
|
|
597
353
|
}
|
|
598
354
|
if (toGenerate.length === 0) {
|
|
599
|
-
|
|
355
|
+
logger.debug("OG images: all cached, nothing to generate");
|
|
600
356
|
return results;
|
|
601
357
|
}
|
|
602
|
-
|
|
358
|
+
logger.info(
|
|
359
|
+
`Generating ${toGenerate.length} OG images (concurrency: ${concurrency})`
|
|
360
|
+
);
|
|
603
361
|
await pMap(
|
|
604
362
|
toGenerate,
|
|
605
363
|
async (entry) => {
|
|
@@ -623,15 +381,15 @@ async function generateOgImages(entries, config) {
|
|
|
623
381
|
});
|
|
624
382
|
const pngData = resvg.render();
|
|
625
383
|
const pngBuffer = pngData.asPng();
|
|
626
|
-
const parentDir = _path.
|
|
384
|
+
const parentDir = _path.dirname.call(void 0, outputPath);
|
|
627
385
|
if (!_fs.existsSync.call(void 0, parentDir)) {
|
|
628
386
|
_fs.mkdirSync.call(void 0, parentDir, { recursive: true });
|
|
629
387
|
}
|
|
630
388
|
_fs.writeFileSync.call(void 0, outputPath, pngBuffer);
|
|
631
389
|
results[entry.slug] = outputPath;
|
|
632
|
-
|
|
390
|
+
logger.debug(`OG image generated: ${entry.slug}`);
|
|
633
391
|
} catch (err) {
|
|
634
|
-
|
|
392
|
+
logger.error(`Failed to generate OG image for "${entry.slug}":`, err);
|
|
635
393
|
}
|
|
636
394
|
},
|
|
637
395
|
concurrency
|
|
@@ -640,7 +398,7 @@ async function generateOgImages(entries, config) {
|
|
|
640
398
|
}
|
|
641
399
|
async function loadFont(config) {
|
|
642
400
|
if (config.fontPath && _fs.existsSync.call(void 0, config.fontPath)) {
|
|
643
|
-
|
|
401
|
+
logger.debug(`Using custom font: ${config.fontPath}`);
|
|
644
402
|
const buffer = _fs.readFileSync.call(void 0, config.fontPath);
|
|
645
403
|
return buffer.buffer.slice(
|
|
646
404
|
buffer.byteOffset,
|
|
@@ -650,14 +408,14 @@ async function loadFont(config) {
|
|
|
650
408
|
const cacheDir = _path.join.call(void 0, process.cwd(), FONT_CACHE_DIR);
|
|
651
409
|
const cachedPath = _path.join.call(void 0, cacheDir, "inter-regular.woff2");
|
|
652
410
|
if (_fs.existsSync.call(void 0, cachedPath)) {
|
|
653
|
-
|
|
411
|
+
logger.debug("Using cached Inter font");
|
|
654
412
|
const buffer = _fs.readFileSync.call(void 0, cachedPath);
|
|
655
413
|
return buffer.buffer.slice(
|
|
656
414
|
buffer.byteOffset,
|
|
657
415
|
buffer.byteOffset + buffer.byteLength
|
|
658
416
|
);
|
|
659
417
|
}
|
|
660
|
-
|
|
418
|
+
logger.info("Downloading Inter font for OG images...");
|
|
661
419
|
try {
|
|
662
420
|
const response = await fetch(INTER_FONT_URL);
|
|
663
421
|
if (!response.ok) {
|
|
@@ -668,60 +426,34 @@ async function loadFont(config) {
|
|
|
668
426
|
_fs.mkdirSync.call(void 0, cacheDir, { recursive: true });
|
|
669
427
|
}
|
|
670
428
|
_fs.writeFileSync.call(void 0, cachedPath, Buffer.from(arrayBuffer));
|
|
671
|
-
|
|
429
|
+
logger.debug("Inter font cached");
|
|
672
430
|
return arrayBuffer;
|
|
673
431
|
} catch (err) {
|
|
674
|
-
|
|
432
|
+
logger.warn("Could not fetch Inter font, using empty fallback:", err);
|
|
675
433
|
return new ArrayBuffer(0);
|
|
676
434
|
}
|
|
677
435
|
}
|
|
678
436
|
async function loadTemplate(template) {
|
|
679
437
|
switch (template) {
|
|
680
438
|
case "blog": {
|
|
681
|
-
const mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./blog-
|
|
439
|
+
const mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./blog-SEXXJJSV.cjs")));
|
|
682
440
|
return mod.blogTemplate;
|
|
683
441
|
}
|
|
684
442
|
case "product": {
|
|
685
|
-
const mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./product-
|
|
443
|
+
const mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./product-BY3GVQGV.cjs")));
|
|
686
444
|
return mod.productTemplate;
|
|
687
445
|
}
|
|
688
446
|
case "dark": {
|
|
689
|
-
const mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./dark-
|
|
447
|
+
const mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./dark-66ZWYLT7.cjs")));
|
|
690
448
|
return mod.darkTemplate;
|
|
691
449
|
}
|
|
692
|
-
case "minimal":
|
|
693
450
|
default: {
|
|
694
|
-
const mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./minimal-
|
|
451
|
+
const mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./minimal-XTTHXE3T.cjs")));
|
|
695
452
|
return mod.minimalTemplate;
|
|
696
453
|
}
|
|
697
454
|
}
|
|
698
455
|
}
|
|
699
456
|
|
|
700
|
-
// src/generate/taxonomy.ts
|
|
701
|
-
function generateTaxonomy(entries, _config) {
|
|
702
|
-
const tags = {};
|
|
703
|
-
const categories = {};
|
|
704
|
-
for (const entry of entries) {
|
|
705
|
-
if (entry.tags) {
|
|
706
|
-
for (const tag of entry.tags) {
|
|
707
|
-
const normalized = tag.toLowerCase().trim();
|
|
708
|
-
if (!tags[normalized]) {
|
|
709
|
-
tags[normalized] = [];
|
|
710
|
-
}
|
|
711
|
-
tags[normalized].push(entry.slug);
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
if (entry.category) {
|
|
715
|
-
const normalized = entry.category.toLowerCase().trim();
|
|
716
|
-
if (!categories[normalized]) {
|
|
717
|
-
categories[normalized] = [];
|
|
718
|
-
}
|
|
719
|
-
categories[normalized].push(entry.slug);
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
return { tags, categories };
|
|
723
|
-
}
|
|
724
|
-
|
|
725
457
|
// src/generate/redirects.ts
|
|
726
458
|
var _child_process = require('child_process');
|
|
727
459
|
|
|
@@ -759,7 +491,7 @@ var MANIFEST_DIR = ".vaza-content";
|
|
|
759
491
|
var MANIFEST_FILE = "slugs.json";
|
|
760
492
|
var MIN_SIMILARITY = 0.5;
|
|
761
493
|
async function detectRedirects(entries, config) {
|
|
762
|
-
const strategy = _nullishCoalesce(_optionalChain([config, 'access',
|
|
494
|
+
const strategy = _nullishCoalesce(_optionalChain([config, 'access', _4 => _4.redirects, 'optionalAccess', _5 => _5.strategy]), () => ( "both"));
|
|
763
495
|
const redirects = [];
|
|
764
496
|
if (strategy === "git" || strategy === "both") {
|
|
765
497
|
const gitRedirects = detectGitRenames();
|
|
@@ -778,7 +510,7 @@ async function detectRedirects(entries, config) {
|
|
|
778
510
|
}
|
|
779
511
|
}
|
|
780
512
|
if (unique.length > 0) {
|
|
781
|
-
|
|
513
|
+
logger.info(`Detected ${unique.length} redirect(s)`);
|
|
782
514
|
}
|
|
783
515
|
return unique;
|
|
784
516
|
}
|
|
@@ -813,79 +545,245 @@ function detectGitRenames() {
|
|
|
813
545
|
}
|
|
814
546
|
match = renameRegex.exec(output);
|
|
815
547
|
}
|
|
816
|
-
match = simpleRenameRegex.exec(output);
|
|
817
|
-
while (match) {
|
|
818
|
-
const oldPath = match[1].trim();
|
|
819
|
-
const newPath = match[2].trim();
|
|
820
|
-
const oldSlug = extractSlug(oldPath);
|
|
821
|
-
const newSlug = extractSlug(newPath);
|
|
822
|
-
if (oldSlug && newSlug && oldSlug !== newSlug) {
|
|
823
|
-
redirects.push({
|
|
824
|
-
from: oldSlug,
|
|
825
|
-
to: newSlug,
|
|
826
|
-
status: 301
|
|
827
|
-
});
|
|
548
|
+
match = simpleRenameRegex.exec(output);
|
|
549
|
+
while (match) {
|
|
550
|
+
const oldPath = match[1].trim();
|
|
551
|
+
const newPath = match[2].trim();
|
|
552
|
+
const oldSlug = extractSlug(oldPath);
|
|
553
|
+
const newSlug = extractSlug(newPath);
|
|
554
|
+
if (oldSlug && newSlug && oldSlug !== newSlug) {
|
|
555
|
+
redirects.push({
|
|
556
|
+
from: oldSlug,
|
|
557
|
+
to: newSlug,
|
|
558
|
+
status: 301
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
match = simpleRenameRegex.exec(output);
|
|
562
|
+
}
|
|
563
|
+
} catch (e2) {
|
|
564
|
+
logger.debug(
|
|
565
|
+
"Git not available or not a git repo, skipping git rename detection"
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
return redirects;
|
|
569
|
+
}
|
|
570
|
+
function detectManifestChanges(entries) {
|
|
571
|
+
const redirects = [];
|
|
572
|
+
const manifestPath = _path.join.call(void 0, process.cwd(), MANIFEST_DIR, MANIFEST_FILE);
|
|
573
|
+
const currentSlugs = entries.map((e) => e.slug).sort();
|
|
574
|
+
if (_fs.existsSync.call(void 0, manifestPath)) {
|
|
575
|
+
try {
|
|
576
|
+
const raw = _fs.readFileSync.call(void 0, manifestPath, "utf-8");
|
|
577
|
+
const previousSlugs = JSON.parse(raw);
|
|
578
|
+
const currentSet = new Set(currentSlugs);
|
|
579
|
+
const previousSet = new Set(previousSlugs);
|
|
580
|
+
const removedSlugs = previousSlugs.filter((s) => !currentSet.has(s));
|
|
581
|
+
const addedSlugs = currentSlugs.filter((s) => !previousSet.has(s));
|
|
582
|
+
if (removedSlugs.length > 0 && addedSlugs.length > 0) {
|
|
583
|
+
const usedAdded = /* @__PURE__ */ new Set();
|
|
584
|
+
for (const removed of removedSlugs) {
|
|
585
|
+
let bestMatch = "";
|
|
586
|
+
let bestScore = 0;
|
|
587
|
+
for (const added of addedSlugs) {
|
|
588
|
+
if (usedAdded.has(added)) continue;
|
|
589
|
+
const score = similarity(removed, added);
|
|
590
|
+
if (score > bestScore) {
|
|
591
|
+
bestScore = score;
|
|
592
|
+
bestMatch = added;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
if (bestMatch && bestScore >= MIN_SIMILARITY) {
|
|
596
|
+
usedAdded.add(bestMatch);
|
|
597
|
+
redirects.push({
|
|
598
|
+
from: removed,
|
|
599
|
+
to: bestMatch,
|
|
600
|
+
status: 301
|
|
601
|
+
});
|
|
602
|
+
logger.debug(
|
|
603
|
+
`Redirect: ${removed} -> ${bestMatch} (similarity: ${bestScore.toFixed(2)})`
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
} catch (e3) {
|
|
609
|
+
logger.warn("Corrupted slug manifest, will be overwritten");
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
const dir = _path.dirname.call(void 0, manifestPath);
|
|
613
|
+
if (!_fs.existsSync.call(void 0, dir)) {
|
|
614
|
+
_fs.mkdirSync.call(void 0, dir, { recursive: true });
|
|
615
|
+
}
|
|
616
|
+
_fs.writeFileSync.call(void 0, manifestPath, JSON.stringify(currentSlugs, null, 2));
|
|
617
|
+
return redirects;
|
|
618
|
+
}
|
|
619
|
+
function extractSlug(filePath) {
|
|
620
|
+
const name = _path.basename.call(void 0, filePath);
|
|
621
|
+
if (!name) return null;
|
|
622
|
+
return name.replace(/\.(mdx?|tsx?|jsx?)$/, "");
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// src/generate/rss.ts
|
|
626
|
+
function generateRss(entries, config) {
|
|
627
|
+
const siteUrl = config.site.url.replace(/\/$/, "");
|
|
628
|
+
const limit = _nullishCoalesce(_optionalChain([config, 'access', _6 => _6.rss, 'optionalAccess', _7 => _7.limit]), () => ( DEFAULT_RSS_LIMIT));
|
|
629
|
+
const collectionKeys = Object.keys(config.collections);
|
|
630
|
+
const fallbackBasePath = collectionKeys.length > 0 ? config.collections[collectionKeys[0]].basePath : "";
|
|
631
|
+
const sorted = [...entries].filter((e) => !e.noindex).sort((a, b) => b.publishDate.getTime() - a.publishDate.getTime());
|
|
632
|
+
const limited = sorted.slice(0, limit);
|
|
633
|
+
return limited.map((entry) => {
|
|
634
|
+
const basePath = (_nullishCoalesce(entry._basePath, () => ( fallbackBasePath))).replace(/\/$/, "");
|
|
635
|
+
const link = `${siteUrl}${basePath}/${entry.slug}`;
|
|
636
|
+
return {
|
|
637
|
+
title: entry.title,
|
|
638
|
+
link,
|
|
639
|
+
description: entry.description || entry.excerpt,
|
|
640
|
+
pubDate: entry.publishDate.toUTCString(),
|
|
641
|
+
guid: link,
|
|
642
|
+
author: _optionalChain([entry, 'access', _8 => _8.author, 'optionalAccess', _9 => _9.name])
|
|
643
|
+
};
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
function renderRssXml(items, config) {
|
|
647
|
+
const siteUrl = config.site.url.replace(/\/$/, "");
|
|
648
|
+
const lines = [
|
|
649
|
+
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
650
|
+
'<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">',
|
|
651
|
+
" <channel>",
|
|
652
|
+
` <title>${escapeXml(config.site.name)}</title>`,
|
|
653
|
+
` <link>${escapeXml(siteUrl)}</link>`,
|
|
654
|
+
` <description>${escapeXml(_nullishCoalesce(config.site.description, () => ( "")))}</description>`,
|
|
655
|
+
` <language>${_nullishCoalesce(config.site.language, () => ( "en"))}</language>`,
|
|
656
|
+
` <lastBuildDate>${(/* @__PURE__ */ new Date()).toUTCString()}</lastBuildDate>`
|
|
657
|
+
];
|
|
658
|
+
if (_optionalChain([config, 'access', _10 => _10.rss, 'optionalAccess', _11 => _11.path])) {
|
|
659
|
+
lines.push(
|
|
660
|
+
` <atom:link href="${escapeXml(siteUrl + config.rss.path)}" rel="self" type="application/rss+xml" />`
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
for (const item of items) {
|
|
664
|
+
lines.push(" <item>");
|
|
665
|
+
lines.push(` <title>${escapeXml(item.title)}</title>`);
|
|
666
|
+
lines.push(` <link>${escapeXml(item.link)}</link>`);
|
|
667
|
+
lines.push(
|
|
668
|
+
` <description>${escapeXml(item.description)}</description>`
|
|
669
|
+
);
|
|
670
|
+
lines.push(` <pubDate>${item.pubDate}</pubDate>`);
|
|
671
|
+
lines.push(` <guid isPermaLink="true">${escapeXml(item.guid)}</guid>`);
|
|
672
|
+
if (item.author) {
|
|
673
|
+
lines.push(` <author>${escapeXml(item.author)}</author>`);
|
|
674
|
+
}
|
|
675
|
+
lines.push(" </item>");
|
|
676
|
+
}
|
|
677
|
+
lines.push(" </channel>");
|
|
678
|
+
lines.push("</rss>");
|
|
679
|
+
return lines.join("\n");
|
|
680
|
+
}
|
|
681
|
+
function escapeXml(str) {
|
|
682
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// src/generate/sitemap.ts
|
|
686
|
+
function generateSitemap(entries, config) {
|
|
687
|
+
const siteUrl = config.site.url.replace(/\/$/, "");
|
|
688
|
+
const defaultChangeFreq = _nullishCoalesce(_optionalChain([config, 'access', _12 => _12.sitemap, 'optionalAccess', _13 => _13.changeFrequency]), () => ( DEFAULT_SITEMAP_CHANGE_FREQ));
|
|
689
|
+
const defaultPriority = _nullishCoalesce(_optionalChain([config, 'access', _14 => _14.sitemap, 'optionalAccess', _15 => _15.priority]), () => ( DEFAULT_SITEMAP_PRIORITY));
|
|
690
|
+
const collectionKeys = Object.keys(config.collections);
|
|
691
|
+
const fallbackBasePath = collectionKeys.length > 0 ? config.collections[collectionKeys[0]].basePath : "";
|
|
692
|
+
const sitemapEntries = [];
|
|
693
|
+
for (const entry of entries) {
|
|
694
|
+
if (entry.noindex) continue;
|
|
695
|
+
const basePath = (_nullishCoalesce(entry._basePath, () => ( fallbackBasePath))).replace(/\/$/, "");
|
|
696
|
+
const loc = `${siteUrl}${basePath}/${entry.slug}`;
|
|
697
|
+
const lastmod = (_nullishCoalesce(entry.updateDate, () => ( entry.publishDate))).toISOString();
|
|
698
|
+
const sitemapEntry = {
|
|
699
|
+
loc,
|
|
700
|
+
lastmod,
|
|
701
|
+
changefreq: defaultChangeFreq,
|
|
702
|
+
priority: defaultPriority
|
|
703
|
+
};
|
|
704
|
+
if (entry.image) {
|
|
705
|
+
sitemapEntry.images = [
|
|
706
|
+
{
|
|
707
|
+
loc: entry.image.src.startsWith("http") ? entry.image.src : `${siteUrl}${entry.image.src}`,
|
|
708
|
+
title: entry.image.alt
|
|
709
|
+
}
|
|
710
|
+
];
|
|
711
|
+
}
|
|
712
|
+
sitemapEntries.push(sitemapEntry);
|
|
713
|
+
}
|
|
714
|
+
if (_optionalChain([config, 'access', _16 => _16.sitemap, 'optionalAccess', _17 => _17.additionalPaths])) {
|
|
715
|
+
for (const path of config.sitemap.additionalPaths) {
|
|
716
|
+
sitemapEntries.push({
|
|
717
|
+
loc: `${siteUrl}${path}`,
|
|
718
|
+
changefreq: defaultChangeFreq,
|
|
719
|
+
priority: defaultPriority
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
return sitemapEntries;
|
|
724
|
+
}
|
|
725
|
+
function renderSitemapXml(entries) {
|
|
726
|
+
const hasImages = entries.some((e) => e.images && e.images.length > 0);
|
|
727
|
+
const lines = [
|
|
728
|
+
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
729
|
+
`<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"${hasImages ? ' xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"' : ""}>`
|
|
730
|
+
];
|
|
731
|
+
for (const entry of entries) {
|
|
732
|
+
lines.push(" <url>");
|
|
733
|
+
lines.push(` <loc>${escapeXml2(entry.loc)}</loc>`);
|
|
734
|
+
if (entry.lastmod) {
|
|
735
|
+
lines.push(` <lastmod>${entry.lastmod}</lastmod>`);
|
|
736
|
+
}
|
|
737
|
+
if (entry.changefreq) {
|
|
738
|
+
lines.push(` <changefreq>${entry.changefreq}</changefreq>`);
|
|
739
|
+
}
|
|
740
|
+
if (entry.priority !== void 0) {
|
|
741
|
+
lines.push(` <priority>${entry.priority}</priority>`);
|
|
742
|
+
}
|
|
743
|
+
if (entry.images) {
|
|
744
|
+
for (const img of entry.images) {
|
|
745
|
+
lines.push(" <image:image>");
|
|
746
|
+
lines.push(` <image:loc>${escapeXml2(img.loc)}</image:loc>`);
|
|
747
|
+
if (img.title) {
|
|
748
|
+
lines.push(
|
|
749
|
+
` <image:title>${escapeXml2(img.title)}</image:title>`
|
|
750
|
+
);
|
|
751
|
+
}
|
|
752
|
+
lines.push(" </image:image>");
|
|
828
753
|
}
|
|
829
|
-
match = simpleRenameRegex.exec(output);
|
|
830
754
|
}
|
|
831
|
-
|
|
832
|
-
_chunkWOCXEBQCcjs.logger.debug("Git not available or not a git repo, skipping git rename detection");
|
|
755
|
+
lines.push(" </url>");
|
|
833
756
|
}
|
|
834
|
-
|
|
757
|
+
lines.push("</urlset>");
|
|
758
|
+
return lines.join("\n");
|
|
835
759
|
}
|
|
836
|
-
function
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
const
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
for (const removed of removedSlugs) {
|
|
851
|
-
let bestMatch = "";
|
|
852
|
-
let bestScore = 0;
|
|
853
|
-
for (const added of addedSlugs) {
|
|
854
|
-
if (usedAdded.has(added)) continue;
|
|
855
|
-
const score = similarity(removed, added);
|
|
856
|
-
if (score > bestScore) {
|
|
857
|
-
bestScore = score;
|
|
858
|
-
bestMatch = added;
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
if (bestMatch && bestScore >= MIN_SIMILARITY) {
|
|
862
|
-
usedAdded.add(bestMatch);
|
|
863
|
-
redirects.push({
|
|
864
|
-
from: removed,
|
|
865
|
-
to: bestMatch,
|
|
866
|
-
status: 301
|
|
867
|
-
});
|
|
868
|
-
_chunkWOCXEBQCcjs.logger.debug(
|
|
869
|
-
`Redirect: ${removed} -> ${bestMatch} (similarity: ${bestScore.toFixed(2)})`
|
|
870
|
-
);
|
|
871
|
-
}
|
|
760
|
+
function escapeXml2(str) {
|
|
761
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// src/generate/taxonomy.ts
|
|
765
|
+
function generateTaxonomy(entries, _config) {
|
|
766
|
+
const tags = {};
|
|
767
|
+
const categories = {};
|
|
768
|
+
for (const entry of entries) {
|
|
769
|
+
if (entry.tags) {
|
|
770
|
+
for (const tag of entry.tags) {
|
|
771
|
+
const normalized = tag.toLowerCase().trim();
|
|
772
|
+
if (!tags[normalized]) {
|
|
773
|
+
tags[normalized] = [];
|
|
872
774
|
}
|
|
775
|
+
tags[normalized].push(entry.slug);
|
|
873
776
|
}
|
|
874
|
-
}
|
|
875
|
-
|
|
777
|
+
}
|
|
778
|
+
if (entry.category) {
|
|
779
|
+
const normalized = entry.category.toLowerCase().trim();
|
|
780
|
+
if (!categories[normalized]) {
|
|
781
|
+
categories[normalized] = [];
|
|
782
|
+
}
|
|
783
|
+
categories[normalized].push(entry.slug);
|
|
876
784
|
}
|
|
877
785
|
}
|
|
878
|
-
|
|
879
|
-
if (!_fs.existsSync.call(void 0, dir)) {
|
|
880
|
-
_fs.mkdirSync.call(void 0, dir, { recursive: true });
|
|
881
|
-
}
|
|
882
|
-
_fs.writeFileSync.call(void 0, manifestPath, JSON.stringify(currentSlugs, null, 2));
|
|
883
|
-
return redirects;
|
|
884
|
-
}
|
|
885
|
-
function extractSlug(filePath) {
|
|
886
|
-
const name = filePath.split("/").pop();
|
|
887
|
-
if (!name) return null;
|
|
888
|
-
return name.replace(/\.(mdx?|tsx?|jsx?)$/, "");
|
|
786
|
+
return { tags, categories };
|
|
889
787
|
}
|
|
890
788
|
|
|
891
789
|
// src/integrity/alt-text.ts
|
|
@@ -893,7 +791,7 @@ function checkAltText(entries, severity = "warn") {
|
|
|
893
791
|
const issues = [];
|
|
894
792
|
const emptyAltRegex = /!\[\s*\]\([^)]+\)/g;
|
|
895
793
|
for (const entry of entries) {
|
|
896
|
-
if (entry.image && !_optionalChain([entry, 'access',
|
|
794
|
+
if (entry.image && !_optionalChain([entry, 'access', _18 => _18.image, 'access', _19 => _19.alt, 'optionalAccess', _20 => _20.trim, 'call', _21 => _21()])) {
|
|
897
795
|
issues.push({
|
|
898
796
|
type: "missing-alt-text",
|
|
899
797
|
severity,
|
|
@@ -943,14 +841,14 @@ function checkBrokenLinks(entries, severity = "warn") {
|
|
|
943
841
|
}
|
|
944
842
|
|
|
945
843
|
// src/integrity/duplicate-content.ts
|
|
946
|
-
function
|
|
844
|
+
function normalize(title) {
|
|
947
845
|
return title.toLowerCase().replace(/[^\w\s]/g, "").replace(/\s+/g, " ").trim();
|
|
948
846
|
}
|
|
949
847
|
function checkDuplicateContent(entries, severity = "warn") {
|
|
950
848
|
const issues = [];
|
|
951
849
|
const seen = /* @__PURE__ */ new Map();
|
|
952
850
|
for (const entry of entries) {
|
|
953
|
-
const key =
|
|
851
|
+
const key = normalize(entry.title);
|
|
954
852
|
if (!key) continue;
|
|
955
853
|
const existing = seen.get(key);
|
|
956
854
|
if (existing) {
|
|
@@ -1017,8 +915,8 @@ function parseMaxAge(maxAge) {
|
|
|
1017
915
|
}
|
|
1018
916
|
function checkFreshness(entries, config) {
|
|
1019
917
|
const issues = [];
|
|
1020
|
-
const maxAgeStr = _nullishCoalesce(_optionalChain([config, 'access',
|
|
1021
|
-
const severity = _nullishCoalesce(_optionalChain([config, 'access',
|
|
918
|
+
const maxAgeStr = _nullishCoalesce(_optionalChain([config, 'access', _22 => _22.freshness, 'optionalAccess', _23 => _23.maxAge]), () => ( "6m"));
|
|
919
|
+
const severity = _nullishCoalesce(_optionalChain([config, 'access', _24 => _24.freshness, 'optionalAccess', _25 => _25.severity]), () => ( "warn"));
|
|
1022
920
|
if (severity === "off") return issues;
|
|
1023
921
|
const maxAgeMs = parseMaxAge(maxAgeStr);
|
|
1024
922
|
const now = Date.now();
|
|
@@ -1041,10 +939,10 @@ function checkFreshness(entries, config) {
|
|
|
1041
939
|
// src/integrity/meta-length.ts
|
|
1042
940
|
function checkMetaLength(entries, config) {
|
|
1043
941
|
const issues = [];
|
|
1044
|
-
const titleMax = _nullishCoalesce(_optionalChain([config, 'access',
|
|
1045
|
-
const titleSeverity = _nullishCoalesce(_optionalChain([config, 'access',
|
|
1046
|
-
const descMax = _nullishCoalesce(_optionalChain([config, 'access',
|
|
1047
|
-
const descSeverity = _nullishCoalesce(_optionalChain([config, 'access',
|
|
942
|
+
const titleMax = _nullishCoalesce(_optionalChain([config, 'access', _26 => _26.metaTitleLength, 'optionalAccess', _27 => _27.max]), () => ( 60));
|
|
943
|
+
const titleSeverity = _nullishCoalesce(_optionalChain([config, 'access', _28 => _28.metaTitleLength, 'optionalAccess', _29 => _29.severity]), () => ( "warn"));
|
|
944
|
+
const descMax = _nullishCoalesce(_optionalChain([config, 'access', _30 => _30.metaDescriptionLength, 'optionalAccess', _31 => _31.max]), () => ( 120));
|
|
945
|
+
const descSeverity = _nullishCoalesce(_optionalChain([config, 'access', _32 => _32.metaDescriptionLength, 'optionalAccess', _33 => _33.severity]), () => ( "warn"));
|
|
1048
946
|
for (const entry of entries) {
|
|
1049
947
|
if (titleSeverity !== "off" && entry.title.length > titleMax) {
|
|
1050
948
|
issues.push({
|
|
@@ -1105,8 +1003,8 @@ function checkIntegrity(entries, config) {
|
|
|
1105
1003
|
if (ic.brokenLinks !== "off") {
|
|
1106
1004
|
issues.push(...checkBrokenLinks(entries, _nullishCoalesce(ic.brokenLinks, () => ( "warn"))));
|
|
1107
1005
|
}
|
|
1108
|
-
const titleOff = _optionalChain([ic, 'access',
|
|
1109
|
-
const descOff = _optionalChain([ic, 'access',
|
|
1006
|
+
const titleOff = _optionalChain([ic, 'access', _34 => _34.metaTitleLength, 'optionalAccess', _35 => _35.severity]) === "off";
|
|
1007
|
+
const descOff = _optionalChain([ic, 'access', _36 => _36.metaDescriptionLength, 'optionalAccess', _37 => _37.severity]) === "off";
|
|
1110
1008
|
if (!titleOff || !descOff) {
|
|
1111
1009
|
issues.push(...checkMetaLength(entries, ic));
|
|
1112
1010
|
}
|
|
@@ -1124,7 +1022,7 @@ function checkIntegrity(entries, config) {
|
|
|
1124
1022
|
if (ic.orphanPages !== "off") {
|
|
1125
1023
|
issues.push(...checkOrphanPages(entries, _nullishCoalesce(ic.orphanPages, () => ( "warn"))));
|
|
1126
1024
|
}
|
|
1127
|
-
if (_optionalChain([ic, 'access',
|
|
1025
|
+
if (_optionalChain([ic, 'access', _38 => _38.freshness, 'optionalAccess', _39 => _39.severity]) !== "off") {
|
|
1128
1026
|
issues.push(...checkFreshness(entries, ic));
|
|
1129
1027
|
}
|
|
1130
1028
|
let errors = 0;
|
|
@@ -1136,25 +1034,168 @@ function checkIntegrity(entries, config) {
|
|
|
1136
1034
|
return { issues, summary: { errors, warnings } };
|
|
1137
1035
|
}
|
|
1138
1036
|
|
|
1037
|
+
// src/normalize/blur-placeholder.ts
|
|
1038
|
+
var _sharp = require('sharp'); var _sharp2 = _interopRequireDefault(_sharp);
|
|
1039
|
+
async function generateBlurPlaceholder(imagePath) {
|
|
1040
|
+
try {
|
|
1041
|
+
const buffer = await _sharp2.default.call(void 0, imagePath).resize(8, 8, { fit: "inside" }).blur().png().toBuffer();
|
|
1042
|
+
return `data:image/png;base64,${buffer.toString("base64")}`;
|
|
1043
|
+
} catch (e4) {
|
|
1044
|
+
return void 0;
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
// src/normalize/excerpt.ts
|
|
1049
|
+
function stripMarkdown(text) {
|
|
1050
|
+
return text.replace(/```[\s\S]*?```/g, "").replace(/!\[.*?\]\(.*?\)/g, "").replace(/\[([^\]]*)\]\(.*?\)/g, "$1").replace(/^#{1,6}\s+/gm, "").replace(/\*{1,3}(.*?)\*{1,3}/g, "$1").replace(/_{1,3}(.*?)_{1,3}/g, "$1").replace(/`([^`]*)`/g, "$1").replace(/^>\s+/gm, "").replace(/^[-*_]{3,}\s*$/gm, "").replace(/<[^>]+>/g, "").replace(/\s+/g, " ").trim();
|
|
1051
|
+
}
|
|
1052
|
+
function generateExcerpt(body, maxLength = EXCERPT_MAX_LENGTH) {
|
|
1053
|
+
const clean = stripMarkdown(body);
|
|
1054
|
+
if (clean.length <= maxLength) {
|
|
1055
|
+
return clean;
|
|
1056
|
+
}
|
|
1057
|
+
const truncated = clean.slice(0, maxLength);
|
|
1058
|
+
const lastSpace = truncated.lastIndexOf(" ");
|
|
1059
|
+
if (lastSpace === -1) {
|
|
1060
|
+
return truncated.slice(0, maxLength);
|
|
1061
|
+
}
|
|
1062
|
+
return truncated.slice(0, lastSpace);
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
// src/normalize/description.ts
|
|
1066
|
+
function generateDescription(body, excerpt) {
|
|
1067
|
+
return _nullishCoalesce(excerpt, () => ( generateExcerpt(body)));
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
// src/normalize/image-dimensions.ts
|
|
1071
|
+
|
|
1072
|
+
async function getImageDimensions(imagePath) {
|
|
1073
|
+
try {
|
|
1074
|
+
const metadata = await _sharp2.default.call(void 0, imagePath).metadata();
|
|
1075
|
+
if (metadata.width && metadata.height) {
|
|
1076
|
+
return { width: metadata.width, height: metadata.height };
|
|
1077
|
+
}
|
|
1078
|
+
return void 0;
|
|
1079
|
+
} catch (e5) {
|
|
1080
|
+
return void 0;
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
// src/normalize/word-count.ts
|
|
1085
|
+
function calcWordCount(body) {
|
|
1086
|
+
return body.trim().split(/\s+/).filter(Boolean).length;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
// src/normalize/reading-time.ts
|
|
1090
|
+
function calcReadingTime(body) {
|
|
1091
|
+
const words = calcWordCount(body);
|
|
1092
|
+
return Math.max(1, Math.ceil(words / WORDS_PER_MINUTE));
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
// src/normalize/slug.ts
|
|
1096
|
+
function generateSlug(title) {
|
|
1097
|
+
return title.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
// src/normalize/toc.ts
|
|
1101
|
+
function toAnchorSlug(text) {
|
|
1102
|
+
return text.toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
1103
|
+
}
|
|
1104
|
+
function extractToc(body) {
|
|
1105
|
+
const headingRegex = /^(#{2,3})\s+(.+)$/gm;
|
|
1106
|
+
const items = [];
|
|
1107
|
+
let match;
|
|
1108
|
+
while ((match = headingRegex.exec(body)) !== null) {
|
|
1109
|
+
const depth = match[1].length;
|
|
1110
|
+
const text = match[2].trim();
|
|
1111
|
+
items.push({
|
|
1112
|
+
depth,
|
|
1113
|
+
text,
|
|
1114
|
+
slug: toAnchorSlug(text)
|
|
1115
|
+
});
|
|
1116
|
+
}
|
|
1117
|
+
return items;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
// src/normalize/index.ts
|
|
1121
|
+
function toDate(value) {
|
|
1122
|
+
if (value === void 0) return void 0;
|
|
1123
|
+
if (value instanceof Date) return value;
|
|
1124
|
+
return new Date(value);
|
|
1125
|
+
}
|
|
1126
|
+
async function normalize2(partial) {
|
|
1127
|
+
const { body, title } = partial;
|
|
1128
|
+
const slug = partial.slug || generateSlug(title);
|
|
1129
|
+
const wordCount = _nullishCoalesce(partial.wordCount, () => ( calcWordCount(body)));
|
|
1130
|
+
const readingTime = _nullishCoalesce(partial.readingTime, () => ( calcReadingTime(body)));
|
|
1131
|
+
const excerpt = _nullishCoalesce(partial.excerpt, () => ( generateExcerpt(body)));
|
|
1132
|
+
const toc = _nullishCoalesce(partial.toc, () => ( extractToc(body)));
|
|
1133
|
+
const description = _nullishCoalesce(partial.description, () => ( generateDescription(body, excerpt)));
|
|
1134
|
+
const publishDate = _nullishCoalesce(toDate(partial.publishDate), () => ( /* @__PURE__ */ new Date()));
|
|
1135
|
+
const updateDate = toDate(partial.updateDate);
|
|
1136
|
+
const eventDate = toDate(partial.eventDate);
|
|
1137
|
+
const image = partial.image ? { ...partial.image } : void 0;
|
|
1138
|
+
if (_optionalChain([image, 'optionalAccess', _40 => _40.src])) {
|
|
1139
|
+
if (!image.blurDataURL) {
|
|
1140
|
+
image.blurDataURL = await generateBlurPlaceholder(image.src);
|
|
1141
|
+
}
|
|
1142
|
+
if (!image.width || !image.height) {
|
|
1143
|
+
const dims = await getImageDimensions(image.src);
|
|
1144
|
+
if (dims) {
|
|
1145
|
+
image.width = dims.width;
|
|
1146
|
+
image.height = dims.height;
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
const entry = {
|
|
1151
|
+
slug,
|
|
1152
|
+
title,
|
|
1153
|
+
body,
|
|
1154
|
+
description,
|
|
1155
|
+
publishDate,
|
|
1156
|
+
readingTime,
|
|
1157
|
+
wordCount,
|
|
1158
|
+
excerpt,
|
|
1159
|
+
toc,
|
|
1160
|
+
...updateDate && { updateDate },
|
|
1161
|
+
...image && { image },
|
|
1162
|
+
...partial.tags && { tags: partial.tags },
|
|
1163
|
+
...partial.category && { category: partial.category },
|
|
1164
|
+
...partial.author && { author: partial.author },
|
|
1165
|
+
...partial.relatedEntries && { relatedEntries: partial.relatedEntries },
|
|
1166
|
+
...partial.canonical && { canonical: partial.canonical },
|
|
1167
|
+
...partial.noindex !== void 0 && { noindex: partial.noindex },
|
|
1168
|
+
...partial.jsonLdType && { jsonLdType: partial.jsonLdType },
|
|
1169
|
+
...partial.faqs && { faqs: partial.faqs },
|
|
1170
|
+
...partial.steps && { steps: partial.steps },
|
|
1171
|
+
...partial.price && { price: partial.price },
|
|
1172
|
+
...partial.ingredients && { ingredients: partial.ingredients },
|
|
1173
|
+
...partial.cookTime && { cookTime: partial.cookTime },
|
|
1174
|
+
...eventDate && { eventDate },
|
|
1175
|
+
...partial.eventLocation && { eventLocation: partial.eventLocation }
|
|
1176
|
+
};
|
|
1177
|
+
return entry;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1139
1180
|
// src/process.ts
|
|
1140
1181
|
async function processCollections(config) {
|
|
1141
1182
|
if (config.logLevel) {
|
|
1142
|
-
|
|
1183
|
+
setLogLevel(config.logLevel);
|
|
1143
1184
|
}
|
|
1144
1185
|
const allEntries = [];
|
|
1145
1186
|
for (const [name, collection] of Object.entries(config.collections)) {
|
|
1146
|
-
|
|
1187
|
+
logger.debug(`Processing collection: ${name}`);
|
|
1147
1188
|
const rawEntries = await collection.entries();
|
|
1148
1189
|
const partialEntries = rawEntries.map(collection.map);
|
|
1149
1190
|
for (const partial of partialEntries) {
|
|
1150
|
-
const normalized = await
|
|
1191
|
+
const normalized = await normalize2(partial);
|
|
1151
1192
|
normalized._collection = name;
|
|
1152
1193
|
normalized._basePath = collection.basePath;
|
|
1153
1194
|
allEntries.push(normalized);
|
|
1154
1195
|
}
|
|
1155
|
-
|
|
1196
|
+
logger.debug(`Collection "${name}": ${rawEntries.length} entries`);
|
|
1156
1197
|
}
|
|
1157
|
-
|
|
1198
|
+
logger.info(`Normalized ${allEntries.length} entries`);
|
|
1158
1199
|
const [sitemap, rss, jsonLd, ogImagePaths, taxonomy, redirects, integrity] = await Promise.all([
|
|
1159
1200
|
_optionalChain([config, 'access', _41 => _41.sitemap, 'optionalAccess', _42 => _42.enabled]) !== false ? generateSitemap(allEntries, config) : Promise.resolve([]),
|
|
1160
1201
|
_optionalChain([config, 'access', _43 => _43.rss, 'optionalAccess', _44 => _44.enabled]) !== false ? generateRss(allEntries, config) : Promise.resolve([]),
|
|
@@ -1180,21 +1221,19 @@ async function processCollections(config) {
|
|
|
1180
1221
|
}
|
|
1181
1222
|
function printIntegrityReport(report) {
|
|
1182
1223
|
const { issues, summary } = report;
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1224
|
+
logger.info("");
|
|
1225
|
+
logger.info("Integrity Report");
|
|
1226
|
+
logger.info("\u2500".repeat(50));
|
|
1186
1227
|
for (const issue of issues) {
|
|
1187
1228
|
const location = issue.slug ? ` (${issue.slug})` : "";
|
|
1188
1229
|
if (issue.severity === "error") {
|
|
1189
|
-
|
|
1230
|
+
logger.error(`${issue.message}${location}`);
|
|
1190
1231
|
} else {
|
|
1191
|
-
|
|
1232
|
+
logger.warn(`${issue.message}${location}`);
|
|
1192
1233
|
}
|
|
1193
1234
|
}
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
`${summary.errors} error(s), ${summary.warnings} warning(s)`
|
|
1197
|
-
);
|
|
1235
|
+
logger.info("\u2500".repeat(50));
|
|
1236
|
+
logger.info(`${summary.errors} error(s), ${summary.warnings} warning(s)`);
|
|
1198
1237
|
if (summary.errors > 0) {
|
|
1199
1238
|
throw new Error(
|
|
1200
1239
|
`[vaza-content] Build failed: ${summary.errors} integrity error(s) found.`
|
|
@@ -1221,5 +1260,7 @@ function printIntegrityReport(report) {
|
|
|
1221
1260
|
|
|
1222
1261
|
|
|
1223
1262
|
|
|
1224
|
-
|
|
1225
|
-
|
|
1263
|
+
|
|
1264
|
+
|
|
1265
|
+
exports.DEFAULT_META_TITLE_MAX = DEFAULT_META_TITLE_MAX; exports.DEFAULT_META_DESC_MAX = DEFAULT_META_DESC_MAX; exports.DEFAULT_FRESHNESS_MAX_AGE = DEFAULT_FRESHNESS_MAX_AGE; exports.DEFAULT_RSS_LIMIT = DEFAULT_RSS_LIMIT; exports.DEFAULT_SITEMAP_PRIORITY = DEFAULT_SITEMAP_PRIORITY; exports.DEFAULT_SITEMAP_CHANGE_FREQ = DEFAULT_SITEMAP_CHANGE_FREQ; exports.generateBreadcrumbs = generateBreadcrumbs; exports.generateJsonLd = generateJsonLd; exports.setLogLevel = setLogLevel; exports.logger = logger; exports.generateOgImages = generateOgImages; exports.detectRedirects = detectRedirects; exports.generateRss = generateRss; exports.renderRssXml = renderRssXml; exports.generateSitemap = generateSitemap; exports.renderSitemapXml = renderSitemapXml; exports.generateTaxonomy = generateTaxonomy; exports.checkIntegrity = checkIntegrity; exports.normalize = normalize2; exports.processCollections = processCollections;
|
|
1266
|
+
//# sourceMappingURL=chunk-H3D7F4TA.cjs.map
|