bunki 0.5.2 → 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/README.md +9 -5
- package/dist/cli/commands/css.d.ts +18 -0
- package/dist/cli/commands/generate.d.ts +17 -0
- package/dist/cli/commands/images-push.d.ts +14 -0
- package/dist/cli/commands/init.d.ts +16 -0
- package/dist/cli/commands/new-post.d.ts +13 -0
- package/dist/cli/commands/serve.d.ts +13 -0
- package/dist/cli.js +1255 -1090
- package/dist/index.js +66 -10
- package/dist/site-generator.d.ts +8 -0
- package/dist/types.d.ts +10 -0
- package/package.json +4 -4
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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bunki",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "An opinionated static site generator built with Bun featuring PostCSS integration and modern web development workflows",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -59,15 +59,15 @@
|
|
|
59
59
|
"slugify": "^1.6.6"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@tailwindcss/postcss": "^4.1.
|
|
62
|
+
"@tailwindcss/postcss": "^4.1.15",
|
|
63
63
|
"@types/nunjucks": "^3.2.6",
|
|
64
64
|
"@types/sanitize-html": "^2.16.0",
|
|
65
65
|
"autoprefixer": "^10.4.20",
|
|
66
66
|
"bun-types": "^1.3.0",
|
|
67
67
|
"husky": "^9.1.7",
|
|
68
|
-
"lint-staged": "^16.2.
|
|
68
|
+
"lint-staged": "^16.2.5",
|
|
69
69
|
"prettier": "^3.6.2",
|
|
70
|
-
"tailwindcss": "^4.1.
|
|
70
|
+
"tailwindcss": "^4.1.15",
|
|
71
71
|
"typescript": "^5.9.3"
|
|
72
72
|
},
|
|
73
73
|
"peerDependencies": {
|