bunki 0.5.3 → 0.6.0
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/cli.js +72 -11
- package/dist/index.js +66 -10
- package/dist/site-generator.d.ts +8 -0
- package/dist/types.d.ts +10 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -33263,29 +33263,85 @@ class SiteGenerator {
|
|
|
33263
33263
|
console.log("Copied public files to site (including extensionless & dotfiles)");
|
|
33264
33264
|
}
|
|
33265
33265
|
}
|
|
33266
|
+
extractFirstImageUrl(html) {
|
|
33267
|
+
const imgRegex = /<img[^>]+src=["']([^"']+)["']/;
|
|
33268
|
+
const match = html.match(imgRegex);
|
|
33269
|
+
return match ? match[1] : null;
|
|
33270
|
+
}
|
|
33271
|
+
escapeXml(text) {
|
|
33272
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
33273
|
+
}
|
|
33266
33274
|
async generateRSSFeed() {
|
|
33267
33275
|
const posts = this.site.posts.slice(0, 15);
|
|
33268
33276
|
const config = this.options.config;
|
|
33277
|
+
const now = this.getPacificDate(new Date);
|
|
33278
|
+
const latestPostDate = posts.length > 0 ? posts[0].date : now.toISOString();
|
|
33279
|
+
const lastBuildDate = this.formatRSSDate(latestPostDate);
|
|
33269
33280
|
const rssItems = posts.map((post) => {
|
|
33270
33281
|
const postUrl = `${config.baseUrl}${post.url}`;
|
|
33271
33282
|
const pubDate = this.formatRSSDate(post.date);
|
|
33272
|
-
|
|
33283
|
+
const featuredImage = this.extractFirstImageUrl(post.html);
|
|
33284
|
+
const categoryTags = post.tags.map((tag) => ` <category>${this.escapeXml(tag)}</category>`).join(`
|
|
33285
|
+
`);
|
|
33286
|
+
let itemXml = ` <item>
|
|
33273
33287
|
<title><![CDATA[${post.title}]]></title>
|
|
33274
33288
|
<link>${postUrl}</link>
|
|
33275
|
-
<guid>${postUrl}</guid>
|
|
33276
|
-
<pubDate>${pubDate}</pubDate
|
|
33277
|
-
|
|
33289
|
+
<guid isPermaLink="true">${postUrl}</guid>
|
|
33290
|
+
<pubDate>${pubDate}</pubDate>`;
|
|
33291
|
+
if (config.authorEmail && config.authorName) {
|
|
33292
|
+
itemXml += `
|
|
33293
|
+
<author>${config.authorEmail} (${config.authorName})</author>`;
|
|
33294
|
+
} else if (config.authorEmail) {
|
|
33295
|
+
itemXml += `
|
|
33296
|
+
<author>${config.authorEmail}</author>`;
|
|
33297
|
+
}
|
|
33298
|
+
itemXml += `
|
|
33299
|
+
<description><![CDATA[${post.excerpt}]]></description>`;
|
|
33300
|
+
if (post.tags.length > 0) {
|
|
33301
|
+
itemXml += `
|
|
33302
|
+
${categoryTags}`;
|
|
33303
|
+
}
|
|
33304
|
+
itemXml += `
|
|
33305
|
+
<content:encoded><![CDATA[${post.html}]]></content:encoded>`;
|
|
33306
|
+
if (featuredImage) {
|
|
33307
|
+
const absoluteImageUrl = featuredImage.startsWith("http") ? featuredImage : `${config.baseUrl}${featuredImage}`;
|
|
33308
|
+
itemXml += `
|
|
33309
|
+
<media:thumbnail url="${this.escapeXml(absoluteImageUrl)}" />`;
|
|
33310
|
+
}
|
|
33311
|
+
itemXml += `
|
|
33278
33312
|
</item>`;
|
|
33313
|
+
return itemXml;
|
|
33279
33314
|
}).join(`
|
|
33280
33315
|
`);
|
|
33281
|
-
|
|
33282
|
-
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
|
33283
|
-
<channel>
|
|
33316
|
+
let channelXml = ` <channel>
|
|
33284
33317
|
<title><![CDATA[${config.title}]]></title>
|
|
33285
|
-
<description><![CDATA[${config.description}]]></description>
|
|
33286
33318
|
<link>${config.baseUrl}</link>
|
|
33287
|
-
<
|
|
33288
|
-
|
|
33319
|
+
<description><![CDATA[${config.description}]]></description>`;
|
|
33320
|
+
const language = config.rssLanguage || "en-US";
|
|
33321
|
+
channelXml += `
|
|
33322
|
+
<language>${language}</language>`;
|
|
33323
|
+
if (config.authorEmail && config.authorName) {
|
|
33324
|
+
channelXml += `
|
|
33325
|
+
<managingEditor>${config.authorEmail} (${config.authorName})</managingEditor>`;
|
|
33326
|
+
} else if (config.authorEmail) {
|
|
33327
|
+
channelXml += `
|
|
33328
|
+
<managingEditor>${config.authorEmail}</managingEditor>`;
|
|
33329
|
+
}
|
|
33330
|
+
if (config.webMaster) {
|
|
33331
|
+
channelXml += `
|
|
33332
|
+
<webMaster>${config.webMaster}</webMaster>`;
|
|
33333
|
+
}
|
|
33334
|
+
if (config.copyright) {
|
|
33335
|
+
channelXml += `
|
|
33336
|
+
<copyright><![CDATA[${config.copyright}]]></copyright>`;
|
|
33337
|
+
}
|
|
33338
|
+
channelXml += `
|
|
33339
|
+
<pubDate>${this.formatRSSDate(latestPostDate)}</pubDate>
|
|
33340
|
+
<lastBuildDate>${lastBuildDate}</lastBuildDate>
|
|
33341
|
+
<atom:link href="${config.baseUrl}/feed.xml" rel="self" type="application/rss+xml" />`;
|
|
33342
|
+
const rssContent = `<?xml version="1.0" encoding="UTF-8"?>
|
|
33343
|
+
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/">
|
|
33344
|
+
${channelXml}
|
|
33289
33345
|
${rssItems}
|
|
33290
33346
|
</channel>
|
|
33291
33347
|
</rss>`;
|
|
@@ -33476,7 +33532,12 @@ async function handleGenerateCommand(options2, deps = defaultDeps2) {
|
|
|
33476
33532
|
deps.logger.log(`- Output directory: ${outputDir}`);
|
|
33477
33533
|
deps.logger.log(`- Templates directory: ${templatesDir}`);
|
|
33478
33534
|
const config = await deps.loadConfig(configPath);
|
|
33479
|
-
const generator = deps.createGenerator({
|
|
33535
|
+
const generator = deps.createGenerator({
|
|
33536
|
+
contentDir,
|
|
33537
|
+
outputDir,
|
|
33538
|
+
templatesDir,
|
|
33539
|
+
config
|
|
33540
|
+
});
|
|
33480
33541
|
await generator.initialize();
|
|
33481
33542
|
await generator.generate();
|
|
33482
33543
|
deps.logger.log("Site generation completed successfully!");
|
package/dist/index.js
CHANGED
|
@@ -31210,29 +31210,85 @@ class SiteGenerator {
|
|
|
31210
31210
|
console.log("Copied public files to site (including extensionless & dotfiles)");
|
|
31211
31211
|
}
|
|
31212
31212
|
}
|
|
31213
|
+
extractFirstImageUrl(html) {
|
|
31214
|
+
const imgRegex = /<img[^>]+src=["']([^"']+)["']/;
|
|
31215
|
+
const match = html.match(imgRegex);
|
|
31216
|
+
return match ? match[1] : null;
|
|
31217
|
+
}
|
|
31218
|
+
escapeXml(text) {
|
|
31219
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
31220
|
+
}
|
|
31213
31221
|
async generateRSSFeed() {
|
|
31214
31222
|
const posts = this.site.posts.slice(0, 15);
|
|
31215
31223
|
const config = this.options.config;
|
|
31224
|
+
const now = this.getPacificDate(new Date);
|
|
31225
|
+
const latestPostDate = posts.length > 0 ? posts[0].date : now.toISOString();
|
|
31226
|
+
const lastBuildDate = this.formatRSSDate(latestPostDate);
|
|
31216
31227
|
const rssItems = posts.map((post) => {
|
|
31217
31228
|
const postUrl = `${config.baseUrl}${post.url}`;
|
|
31218
31229
|
const pubDate = this.formatRSSDate(post.date);
|
|
31219
|
-
|
|
31230
|
+
const featuredImage = this.extractFirstImageUrl(post.html);
|
|
31231
|
+
const categoryTags = post.tags.map((tag) => ` <category>${this.escapeXml(tag)}</category>`).join(`
|
|
31232
|
+
`);
|
|
31233
|
+
let itemXml = ` <item>
|
|
31220
31234
|
<title><![CDATA[${post.title}]]></title>
|
|
31221
31235
|
<link>${postUrl}</link>
|
|
31222
|
-
<guid>${postUrl}</guid>
|
|
31223
|
-
<pubDate>${pubDate}</pubDate
|
|
31224
|
-
|
|
31236
|
+
<guid isPermaLink="true">${postUrl}</guid>
|
|
31237
|
+
<pubDate>${pubDate}</pubDate>`;
|
|
31238
|
+
if (config.authorEmail && config.authorName) {
|
|
31239
|
+
itemXml += `
|
|
31240
|
+
<author>${config.authorEmail} (${config.authorName})</author>`;
|
|
31241
|
+
} else if (config.authorEmail) {
|
|
31242
|
+
itemXml += `
|
|
31243
|
+
<author>${config.authorEmail}</author>`;
|
|
31244
|
+
}
|
|
31245
|
+
itemXml += `
|
|
31246
|
+
<description><![CDATA[${post.excerpt}]]></description>`;
|
|
31247
|
+
if (post.tags.length > 0) {
|
|
31248
|
+
itemXml += `
|
|
31249
|
+
${categoryTags}`;
|
|
31250
|
+
}
|
|
31251
|
+
itemXml += `
|
|
31252
|
+
<content:encoded><![CDATA[${post.html}]]></content:encoded>`;
|
|
31253
|
+
if (featuredImage) {
|
|
31254
|
+
const absoluteImageUrl = featuredImage.startsWith("http") ? featuredImage : `${config.baseUrl}${featuredImage}`;
|
|
31255
|
+
itemXml += `
|
|
31256
|
+
<media:thumbnail url="${this.escapeXml(absoluteImageUrl)}" />`;
|
|
31257
|
+
}
|
|
31258
|
+
itemXml += `
|
|
31225
31259
|
</item>`;
|
|
31260
|
+
return itemXml;
|
|
31226
31261
|
}).join(`
|
|
31227
31262
|
`);
|
|
31228
|
-
|
|
31229
|
-
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
|
31230
|
-
<channel>
|
|
31263
|
+
let channelXml = ` <channel>
|
|
31231
31264
|
<title><![CDATA[${config.title}]]></title>
|
|
31232
|
-
<description><![CDATA[${config.description}]]></description>
|
|
31233
31265
|
<link>${config.baseUrl}</link>
|
|
31234
|
-
<
|
|
31235
|
-
|
|
31266
|
+
<description><![CDATA[${config.description}]]></description>`;
|
|
31267
|
+
const language = config.rssLanguage || "en-US";
|
|
31268
|
+
channelXml += `
|
|
31269
|
+
<language>${language}</language>`;
|
|
31270
|
+
if (config.authorEmail && config.authorName) {
|
|
31271
|
+
channelXml += `
|
|
31272
|
+
<managingEditor>${config.authorEmail} (${config.authorName})</managingEditor>`;
|
|
31273
|
+
} else if (config.authorEmail) {
|
|
31274
|
+
channelXml += `
|
|
31275
|
+
<managingEditor>${config.authorEmail}</managingEditor>`;
|
|
31276
|
+
}
|
|
31277
|
+
if (config.webMaster) {
|
|
31278
|
+
channelXml += `
|
|
31279
|
+
<webMaster>${config.webMaster}</webMaster>`;
|
|
31280
|
+
}
|
|
31281
|
+
if (config.copyright) {
|
|
31282
|
+
channelXml += `
|
|
31283
|
+
<copyright><![CDATA[${config.copyright}]]></copyright>`;
|
|
31284
|
+
}
|
|
31285
|
+
channelXml += `
|
|
31286
|
+
<pubDate>${this.formatRSSDate(latestPostDate)}</pubDate>
|
|
31287
|
+
<lastBuildDate>${lastBuildDate}</lastBuildDate>
|
|
31288
|
+
<atom:link href="${config.baseUrl}/feed.xml" rel="self" type="application/rss+xml" />`;
|
|
31289
|
+
const rssContent = `<?xml version="1.0" encoding="UTF-8"?>
|
|
31290
|
+
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/">
|
|
31291
|
+
${channelXml}
|
|
31236
31292
|
${rssItems}
|
|
31237
31293
|
</channel>
|
|
31238
31294
|
</rss>`;
|
package/dist/site-generator.d.ts
CHANGED
|
@@ -16,6 +16,14 @@ export declare class SiteGenerator {
|
|
|
16
16
|
private generateStylesheet;
|
|
17
17
|
private fallbackCSSGeneration;
|
|
18
18
|
private copyStaticAssets;
|
|
19
|
+
/**
|
|
20
|
+
* Extract the first image URL from HTML content
|
|
21
|
+
*/
|
|
22
|
+
private extractFirstImageUrl;
|
|
23
|
+
/**
|
|
24
|
+
* Escape special characters in XML text to prevent CDATA issues
|
|
25
|
+
*/
|
|
26
|
+
private escapeXml;
|
|
19
27
|
private generateRSSFeed;
|
|
20
28
|
private generateSitemap;
|
|
21
29
|
private generateSitemapIndex;
|
package/dist/types.d.ts
CHANGED
|
@@ -58,6 +58,16 @@ export interface SiteConfig {
|
|
|
58
58
|
maxTagsOnHomepage?: number;
|
|
59
59
|
/** Optional list of domains to exclude from nofollow attribute. Links to these domains will have follow attribute. */
|
|
60
60
|
noFollowExceptions?: string[];
|
|
61
|
+
/** RSS feed language code (default: en-US) */
|
|
62
|
+
rssLanguage?: string;
|
|
63
|
+
/** Author name for RSS feed (used in managingEditor field) */
|
|
64
|
+
authorName?: string;
|
|
65
|
+
/** Author email for RSS feed (used in managingEditor field) */
|
|
66
|
+
authorEmail?: string;
|
|
67
|
+
/** Web master email for RSS feed (optional) */
|
|
68
|
+
webMaster?: string;
|
|
69
|
+
/** Copyright statement for RSS feed (e.g., "Copyright © 2025 Your Site Name") */
|
|
70
|
+
copyright?: string;
|
|
61
71
|
/** Additional custom configuration options */
|
|
62
72
|
[key: string]: any;
|
|
63
73
|
}
|
package/package.json
CHANGED