bunki 0.15.0 → 0.16.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 +28 -10
- package/dist/index.js +28 -10
- package/dist/parser.d.ts +2 -2
- package/dist/types.d.ts +13 -0
- package/dist/utils/markdown-utils.d.ts +3 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -32902,7 +32902,15 @@ core_default.registerLanguage("python", python);
|
|
|
32902
32902
|
core_default.registerLanguage("json", json);
|
|
32903
32903
|
core_default.registerLanguage("swift", swift);
|
|
32904
32904
|
var noFollowExceptions = new Set;
|
|
32905
|
-
function
|
|
32905
|
+
function transformImagePath(relativePath, config) {
|
|
32906
|
+
const match = relativePath.match(/^\.\.\/\.\.\/assets\/(\d{4})\/([^/]+)\/(.+)$/);
|
|
32907
|
+
if (!match)
|
|
32908
|
+
return null;
|
|
32909
|
+
const [, year, slug, filename] = match;
|
|
32910
|
+
const path5 = config.pathPattern.replace("{year}", year).replace("{slug}", slug).replace("{filename}", filename);
|
|
32911
|
+
return `${config.baseUrl}/${path5}`;
|
|
32912
|
+
}
|
|
32913
|
+
function createMarked(cdnConfig) {
|
|
32906
32914
|
const marked = new B(markedHighlight({
|
|
32907
32915
|
emptyLangClass: "hljs",
|
|
32908
32916
|
langPrefix: "hljs language-",
|
|
@@ -32951,6 +32959,15 @@ function createMarked() {
|
|
|
32951
32959
|
}
|
|
32952
32960
|
}
|
|
32953
32961
|
}
|
|
32962
|
+
if (token.type === "image" && cdnConfig?.enabled) {
|
|
32963
|
+
const href = token.href || "";
|
|
32964
|
+
if (href.startsWith("../../assets/")) {
|
|
32965
|
+
const transformed = transformImagePath(href, cdnConfig);
|
|
32966
|
+
if (transformed) {
|
|
32967
|
+
token.href = transformed;
|
|
32968
|
+
}
|
|
32969
|
+
}
|
|
32970
|
+
}
|
|
32954
32971
|
},
|
|
32955
32972
|
hooks: {
|
|
32956
32973
|
preprocess(markdown2) {
|
|
@@ -32993,8 +33010,9 @@ function extractExcerpt(content, maxLength = 200) {
|
|
|
32993
33010
|
const lastSpace = truncated.lastIndexOf(" ");
|
|
32994
33011
|
return truncated.substring(0, lastSpace) + "...";
|
|
32995
33012
|
}
|
|
32996
|
-
function convertMarkdownToHtml(markdownContent) {
|
|
32997
|
-
const
|
|
33013
|
+
function convertMarkdownToHtml(markdownContent, cdnConfig) {
|
|
33014
|
+
const markedInstance = cdnConfig ? createMarked(cdnConfig) : marked;
|
|
33015
|
+
const html = markedInstance.parse(markdownContent, { async: false });
|
|
32998
33016
|
let sanitized = import_sanitize_html.default(html, {
|
|
32999
33017
|
allowedTags: import_sanitize_html.default.defaults.allowedTags.concat([
|
|
33000
33018
|
"img",
|
|
@@ -33146,7 +33164,7 @@ function validateBusinessLocation(business, filePath) {
|
|
|
33146
33164
|
}
|
|
33147
33165
|
return null;
|
|
33148
33166
|
}
|
|
33149
|
-
async function parseMarkdownFile(filePath) {
|
|
33167
|
+
async function parseMarkdownFile(filePath, cdnConfig) {
|
|
33150
33168
|
try {
|
|
33151
33169
|
const fileContent = await readFileAsText(filePath);
|
|
33152
33170
|
if (fileContent === null) {
|
|
@@ -33196,8 +33214,8 @@ async function parseMarkdownFile(filePath) {
|
|
|
33196
33214
|
};
|
|
33197
33215
|
}
|
|
33198
33216
|
}
|
|
33199
|
-
let slug =
|
|
33200
|
-
const sanitizedHtml = convertMarkdownToHtml(content);
|
|
33217
|
+
let slug = getBaseFilename(filePath);
|
|
33218
|
+
const sanitizedHtml = convertMarkdownToHtml(content, cdnConfig);
|
|
33201
33219
|
const pacificDate = toPacificTime(data.date);
|
|
33202
33220
|
const postYear = getPacificYear(data.date);
|
|
33203
33221
|
const post = {
|
|
@@ -33259,11 +33277,11 @@ async function parseMarkdownFile(filePath) {
|
|
|
33259
33277
|
}
|
|
33260
33278
|
|
|
33261
33279
|
// src/parser.ts
|
|
33262
|
-
async function parseMarkdownDirectory(contentDir, strictMode = false) {
|
|
33280
|
+
async function parseMarkdownDirectory(contentDir, strictMode = false, cdnConfig) {
|
|
33263
33281
|
try {
|
|
33264
33282
|
const markdownFiles = await findFilesByPattern("**/*.md", contentDir, true);
|
|
33265
33283
|
console.log(`Found ${markdownFiles.length} markdown files`);
|
|
33266
|
-
const resultsPromises = markdownFiles.map((filePath) => parseMarkdownFile(filePath));
|
|
33284
|
+
const resultsPromises = markdownFiles.map((filePath) => parseMarkdownFile(filePath, cdnConfig));
|
|
33267
33285
|
const results = await Promise.all(resultsPromises);
|
|
33268
33286
|
const posts = [];
|
|
33269
33287
|
const errors = [];
|
|
@@ -33611,7 +33629,7 @@ class SiteGenerator {
|
|
|
33611
33629
|
}
|
|
33612
33630
|
}
|
|
33613
33631
|
const strictMode = this.options.config.strictMode ?? false;
|
|
33614
|
-
const posts = await parseMarkdownDirectory(this.options.contentDir, strictMode);
|
|
33632
|
+
const posts = await parseMarkdownDirectory(this.options.contentDir, strictMode, this.options.config.cdn);
|
|
33615
33633
|
const tags = {};
|
|
33616
33634
|
posts.forEach((post) => {
|
|
33617
33635
|
post.tagSlugs = {};
|
|
@@ -34410,7 +34428,7 @@ function createUploader(config) {
|
|
|
34410
34428
|
}
|
|
34411
34429
|
|
|
34412
34430
|
// src/utils/image-uploader.ts
|
|
34413
|
-
var DEFAULT_IMAGES_DIR = path8.join(process.cwd(), "
|
|
34431
|
+
var DEFAULT_IMAGES_DIR = path8.join(process.cwd(), "assets");
|
|
34414
34432
|
async function uploadImages(options2 = {}) {
|
|
34415
34433
|
try {
|
|
34416
34434
|
const imagesDir = path8.resolve(options2.images || DEFAULT_IMAGES_DIR);
|
package/dist/index.js
CHANGED
|
@@ -30520,7 +30520,15 @@ core_default.registerLanguage("python", python);
|
|
|
30520
30520
|
core_default.registerLanguage("json", json);
|
|
30521
30521
|
core_default.registerLanguage("swift", swift);
|
|
30522
30522
|
var noFollowExceptions = new Set;
|
|
30523
|
-
function
|
|
30523
|
+
function transformImagePath(relativePath, config) {
|
|
30524
|
+
const match = relativePath.match(/^\.\.\/\.\.\/assets\/(\d{4})\/([^/]+)\/(.+)$/);
|
|
30525
|
+
if (!match)
|
|
30526
|
+
return null;
|
|
30527
|
+
const [, year, slug, filename] = match;
|
|
30528
|
+
const path2 = config.pathPattern.replace("{year}", year).replace("{slug}", slug).replace("{filename}", filename);
|
|
30529
|
+
return `${config.baseUrl}/${path2}`;
|
|
30530
|
+
}
|
|
30531
|
+
function createMarked(cdnConfig) {
|
|
30524
30532
|
const marked = new B(markedHighlight({
|
|
30525
30533
|
emptyLangClass: "hljs",
|
|
30526
30534
|
langPrefix: "hljs language-",
|
|
@@ -30569,6 +30577,15 @@ function createMarked() {
|
|
|
30569
30577
|
}
|
|
30570
30578
|
}
|
|
30571
30579
|
}
|
|
30580
|
+
if (token.type === "image" && cdnConfig?.enabled) {
|
|
30581
|
+
const href = token.href || "";
|
|
30582
|
+
if (href.startsWith("../../assets/")) {
|
|
30583
|
+
const transformed = transformImagePath(href, cdnConfig);
|
|
30584
|
+
if (transformed) {
|
|
30585
|
+
token.href = transformed;
|
|
30586
|
+
}
|
|
30587
|
+
}
|
|
30588
|
+
}
|
|
30572
30589
|
},
|
|
30573
30590
|
hooks: {
|
|
30574
30591
|
preprocess(markdown2) {
|
|
@@ -30611,8 +30628,9 @@ function extractExcerpt(content, maxLength = 200) {
|
|
|
30611
30628
|
const lastSpace = truncated.lastIndexOf(" ");
|
|
30612
30629
|
return truncated.substring(0, lastSpace) + "...";
|
|
30613
30630
|
}
|
|
30614
|
-
function convertMarkdownToHtml(markdownContent) {
|
|
30615
|
-
const
|
|
30631
|
+
function convertMarkdownToHtml(markdownContent, cdnConfig) {
|
|
30632
|
+
const markedInstance = cdnConfig ? createMarked(cdnConfig) : marked;
|
|
30633
|
+
const html = markedInstance.parse(markdownContent, { async: false });
|
|
30616
30634
|
let sanitized = import_sanitize_html.default(html, {
|
|
30617
30635
|
allowedTags: import_sanitize_html.default.defaults.allowedTags.concat([
|
|
30618
30636
|
"img",
|
|
@@ -30764,7 +30782,7 @@ function validateBusinessLocation(business, filePath) {
|
|
|
30764
30782
|
}
|
|
30765
30783
|
return null;
|
|
30766
30784
|
}
|
|
30767
|
-
async function parseMarkdownFile(filePath) {
|
|
30785
|
+
async function parseMarkdownFile(filePath, cdnConfig) {
|
|
30768
30786
|
try {
|
|
30769
30787
|
const fileContent = await readFileAsText(filePath);
|
|
30770
30788
|
if (fileContent === null) {
|
|
@@ -30814,8 +30832,8 @@ async function parseMarkdownFile(filePath) {
|
|
|
30814
30832
|
};
|
|
30815
30833
|
}
|
|
30816
30834
|
}
|
|
30817
|
-
let slug =
|
|
30818
|
-
const sanitizedHtml = convertMarkdownToHtml(content);
|
|
30835
|
+
let slug = getBaseFilename(filePath);
|
|
30836
|
+
const sanitizedHtml = convertMarkdownToHtml(content, cdnConfig);
|
|
30819
30837
|
const pacificDate = toPacificTime(data.date);
|
|
30820
30838
|
const postYear = getPacificYear(data.date);
|
|
30821
30839
|
const post = {
|
|
@@ -30877,11 +30895,11 @@ async function parseMarkdownFile(filePath) {
|
|
|
30877
30895
|
}
|
|
30878
30896
|
|
|
30879
30897
|
// src/parser.ts
|
|
30880
|
-
async function parseMarkdownDirectory(contentDir, strictMode = false) {
|
|
30898
|
+
async function parseMarkdownDirectory(contentDir, strictMode = false, cdnConfig) {
|
|
30881
30899
|
try {
|
|
30882
30900
|
const markdownFiles = await findFilesByPattern("**/*.md", contentDir, true);
|
|
30883
30901
|
console.log(`Found ${markdownFiles.length} markdown files`);
|
|
30884
|
-
const resultsPromises = markdownFiles.map((filePath) => parseMarkdownFile(filePath));
|
|
30902
|
+
const resultsPromises = markdownFiles.map((filePath) => parseMarkdownFile(filePath, cdnConfig));
|
|
30885
30903
|
const results = await Promise.all(resultsPromises);
|
|
30886
30904
|
const posts = [];
|
|
30887
30905
|
const errors = [];
|
|
@@ -31558,7 +31576,7 @@ class SiteGenerator {
|
|
|
31558
31576
|
}
|
|
31559
31577
|
}
|
|
31560
31578
|
const strictMode = this.options.config.strictMode ?? false;
|
|
31561
|
-
const posts = await parseMarkdownDirectory(this.options.contentDir, strictMode);
|
|
31579
|
+
const posts = await parseMarkdownDirectory(this.options.contentDir, strictMode, this.options.config.cdn);
|
|
31562
31580
|
const tags = {};
|
|
31563
31581
|
posts.forEach((post) => {
|
|
31564
31582
|
post.tagSlugs = {};
|
|
@@ -32317,7 +32335,7 @@ function createUploader(config) {
|
|
|
32317
32335
|
}
|
|
32318
32336
|
|
|
32319
32337
|
// src/utils/image-uploader.ts
|
|
32320
|
-
var DEFAULT_IMAGES_DIR = path7.join(process.cwd(), "
|
|
32338
|
+
var DEFAULT_IMAGES_DIR = path7.join(process.cwd(), "assets");
|
|
32321
32339
|
async function uploadImages(options2 = {}) {
|
|
32322
32340
|
try {
|
|
32323
32341
|
const imagesDir = path7.resolve(options2.images || DEFAULT_IMAGES_DIR);
|
package/dist/parser.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Post } from "./types";
|
|
1
|
+
import { Post, CDNConfig } from "./types";
|
|
2
2
|
import { type ParseError } from "./utils/markdown-utils";
|
|
3
3
|
export interface ParseResult {
|
|
4
4
|
posts: Post[];
|
|
5
5
|
errors: ParseError[];
|
|
6
6
|
}
|
|
7
|
-
export declare function parseMarkdownDirectory(contentDir: string, strictMode?: boolean): Promise<Post[]>;
|
|
7
|
+
export declare function parseMarkdownDirectory(contentDir: string, strictMode?: boolean, cdnConfig?: CDNConfig): Promise<Post[]>;
|
package/dist/types.d.ts
CHANGED
|
@@ -80,6 +80,17 @@ export interface CSSConfig {
|
|
|
80
80
|
/** Whether to watch for changes in development */
|
|
81
81
|
watch?: boolean;
|
|
82
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Configuration for CDN URL transformation
|
|
85
|
+
*/
|
|
86
|
+
export interface CDNConfig {
|
|
87
|
+
/** Base URL for CDN (e.g., "https://img.beconfused.com") */
|
|
88
|
+
baseUrl: string;
|
|
89
|
+
/** Path pattern for CDN URLs (e.g., "{year}/{slug}/{filename}") */
|
|
90
|
+
pathPattern: string;
|
|
91
|
+
/** Whether CDN transformation is enabled */
|
|
92
|
+
enabled: boolean;
|
|
93
|
+
}
|
|
83
94
|
/**
|
|
84
95
|
* Configuration for the site
|
|
85
96
|
*/
|
|
@@ -98,6 +109,8 @@ export interface SiteConfig {
|
|
|
98
109
|
s3?: S3Config;
|
|
99
110
|
/** CSS processing configuration */
|
|
100
111
|
css?: CSSConfig;
|
|
112
|
+
/** CDN URL transformation configuration */
|
|
113
|
+
cdn?: CDNConfig;
|
|
101
114
|
/** Optional number of tags to display on homepage (sorted by count). If not set, all tags are shown */
|
|
102
115
|
maxTagsOnHomepage?: number;
|
|
103
116
|
/** Optional list of domains to exclude from nofollow attribute. Links to these domains will have follow attribute. */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Post } from "../types";
|
|
1
|
+
import { Post, CDNConfig } from "../types";
|
|
2
2
|
export declare function setNoFollowExceptions(exceptions: string[]): void;
|
|
3
3
|
export declare function extractExcerpt(content: string, maxLength?: number): string;
|
|
4
|
-
export declare function convertMarkdownToHtml(markdownContent: string): string;
|
|
4
|
+
export declare function convertMarkdownToHtml(markdownContent: string, cdnConfig?: CDNConfig): string;
|
|
5
5
|
export interface ParseError {
|
|
6
6
|
file: string;
|
|
7
7
|
type: "yaml" | "missing_field" | "file_not_found" | "unknown" | "validation";
|
|
@@ -12,4 +12,4 @@ export interface ParseMarkdownResult {
|
|
|
12
12
|
post: Post | null;
|
|
13
13
|
error: ParseError | null;
|
|
14
14
|
}
|
|
15
|
-
export declare function parseMarkdownFile(filePath: string): Promise<ParseMarkdownResult>;
|
|
15
|
+
export declare function parseMarkdownFile(filePath: string, cdnConfig?: CDNConfig): Promise<ParseMarkdownResult>;
|
package/package.json
CHANGED