boltdocs 1.0.4 → 1.3.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.
Files changed (41) hide show
  1. package/dist/{SearchDialog-R36WKAQ7.mjs → SearchDialog-5EDRACEG.mjs} +1 -1
  2. package/dist/{SearchDialog-PYF3QMYG.css → SearchDialog-X57WPTNN.css} +54 -126
  3. package/dist/cache-EHR7SXRU.mjs +12 -0
  4. package/dist/chunk-GSYECEZY.mjs +381 -0
  5. package/dist/{chunk-TWSRXUFF.mjs → chunk-NS7WHDYA.mjs} +229 -418
  6. package/dist/client/index.css +54 -126
  7. package/dist/client/index.d.mts +5 -4
  8. package/dist/client/index.d.ts +5 -4
  9. package/dist/client/index.js +555 -580
  10. package/dist/client/index.mjs +304 -16
  11. package/dist/client/ssr.css +54 -126
  12. package/dist/client/ssr.js +257 -580
  13. package/dist/client/ssr.mjs +1 -1
  14. package/dist/{config-D2XmHJYe.d.mts → config-BD5ZHz15.d.mts} +7 -0
  15. package/dist/{config-D2XmHJYe.d.ts → config-BD5ZHz15.d.ts} +7 -0
  16. package/dist/node/index.d.mts +2 -2
  17. package/dist/node/index.d.ts +2 -2
  18. package/dist/node/index.js +457 -118
  19. package/dist/node/index.mjs +93 -136
  20. package/package.json +2 -2
  21. package/src/client/app/index.tsx +25 -54
  22. package/src/client/theme/components/mdx/mdx-components.css +39 -20
  23. package/src/client/theme/styles/markdown.css +1 -1
  24. package/src/client/theme/styles.css +0 -1
  25. package/src/client/theme/ui/Layout/Layout.tsx +2 -13
  26. package/src/client/theme/ui/Layout/responsive.css +0 -4
  27. package/src/client/theme/ui/Link/Link.tsx +52 -0
  28. package/src/client/theme/ui/NotFound/NotFound.tsx +0 -1
  29. package/src/client/theme/ui/OnThisPage/OnThisPage.tsx +45 -2
  30. package/src/client/theme/ui/Sidebar/Sidebar.tsx +44 -40
  31. package/src/client/theme/ui/Sidebar/sidebar.css +25 -58
  32. package/src/node/cache.ts +360 -46
  33. package/src/node/config.ts +7 -0
  34. package/src/node/mdx.ts +83 -4
  35. package/src/node/plugin/index.ts +3 -0
  36. package/src/node/routes/cache.ts +5 -1
  37. package/src/node/routes/index.ts +17 -2
  38. package/src/node/ssg/index.ts +4 -0
  39. package/dist/Playground-B2FA34BC.mjs +0 -6
  40. package/dist/chunk-WPT4MWTQ.mjs +0 -89
  41. package/src/client/theme/styles/home.css +0 -60
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
8
11
  var __export = (target, all) => {
9
12
  for (var name in all)
10
13
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -27,23 +30,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
30
  ));
28
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
32
 
30
- // src/node/index.ts
31
- var node_exports = {};
32
- __export(node_exports, {
33
- default: () => boltdocs,
34
- generateStaticPages: () => generateStaticPages
35
- });
36
- module.exports = __toCommonJS(node_exports);
37
-
38
- // src/node/plugin/index.ts
39
- var import_vite = require("vite");
40
-
41
- // src/node/routes/index.ts
42
- var import_fast_glob = __toESM(require("fast-glob"));
43
-
44
33
  // src/node/utils.ts
45
- var import_fs = __toESM(require("fs"));
46
- var import_gray_matter = __toESM(require("gray-matter"));
47
34
  function normalizePath(p) {
48
35
  return p.replace(/\\/g, "/");
49
36
  }
@@ -89,82 +76,363 @@ function fileToRoutePath(relativePath) {
89
76
  function capitalize(str) {
90
77
  return str.charAt(0).toUpperCase() + str.slice(1);
91
78
  }
79
+ var import_fs, import_gray_matter;
80
+ var init_utils = __esm({
81
+ "src/node/utils.ts"() {
82
+ "use strict";
83
+ import_fs = __toESM(require("fs"));
84
+ import_gray_matter = __toESM(require("gray-matter"));
85
+ }
86
+ });
92
87
 
93
88
  // src/node/cache.ts
94
- var FileCache = class {
95
- entries = /* @__PURE__ */ new Map();
96
- /**
97
- * Retrieves parsed data for a file from the cache.
98
- * Compares the current filesystem mtime with the cached mtime.
99
- *
100
- * @param filePath - The absolute path of the file
101
- * @returns The cached data if valid, or `null` if the file has changed or doesn't exist
102
- */
103
- get(filePath) {
104
- const entry = this.entries.get(filePath);
105
- if (!entry) return null;
106
- const currentMtime = getFileMtime(filePath);
107
- if (currentMtime !== entry.mtime) return null;
108
- return entry.data;
109
- }
110
- /**
111
- * Stores parsed data for a file in the cache, recording its current mtime.
112
- *
113
- * @param filePath - The absolute path to the file
114
- * @param data - The parsed data to store
115
- */
116
- set(filePath, data) {
117
- this.entries.set(filePath, {
118
- data,
119
- mtime: getFileMtime(filePath)
120
- });
121
- }
122
- /**
123
- * Checks if a specific file's cache is still valid (based on its mtime).
124
- *
125
- * @param filePath - The absolute path to the file
126
- * @returns `true` if the cache is valid, `false` otherwise
127
- */
128
- isValid(filePath) {
129
- return this.get(filePath) !== null;
130
- }
131
- /**
132
- * Manually removes a specific file from the cache.
133
- * Useful when forcefully invalidating a single updated file.
134
- *
135
- * @param filePath - The absolute path to the file
136
- */
137
- invalidate(filePath) {
138
- this.entries.delete(filePath);
139
- }
140
- /**
141
- * Clears the entire cache, forcing all files to be re-parsed on the next request.
142
- * Useful when global dependencies (like config) change.
143
- */
144
- invalidateAll() {
145
- this.entries.clear();
146
- }
147
- /**
148
- * Removes cached entries for files that no longer exist on the filesystem.
149
- * Prevents memory leaks from deleted files.
150
- *
151
- * @param currentFiles - A Set of absolute file paths currently discovered on the disk
152
- */
153
- pruneStale(currentFiles) {
154
- for (const key of this.entries.keys()) {
155
- if (!currentFiles.has(key)) {
156
- this.entries.delete(key);
89
+ var cache_exports = {};
90
+ __export(cache_exports, {
91
+ AssetCache: () => AssetCache,
92
+ FileCache: () => FileCache,
93
+ TransformCache: () => TransformCache,
94
+ flushCache: () => flushCache
95
+ });
96
+ async function flushCache() {
97
+ await backgroundQueue.flush();
98
+ }
99
+ var import_fs2, import_path, import_crypto, import_zlib, import_util, writeFile, readFile, mkdir, rename, unlink, CACHE_DIR, ASSETS_DIR, SHARDS_DIR, DEFAULT_LRU_LIMIT, DEFAULT_COMPRESS, LRUCache, BackgroundQueue, backgroundQueue, FileCache, TransformCache, AssetCache;
100
+ var init_cache = __esm({
101
+ "src/node/cache.ts"() {
102
+ "use strict";
103
+ import_fs2 = __toESM(require("fs"));
104
+ import_path = __toESM(require("path"));
105
+ import_crypto = __toESM(require("crypto"));
106
+ import_zlib = __toESM(require("zlib"));
107
+ import_util = require("util");
108
+ init_utils();
109
+ writeFile = (0, import_util.promisify)(import_fs2.default.writeFile);
110
+ readFile = (0, import_util.promisify)(import_fs2.default.readFile);
111
+ mkdir = (0, import_util.promisify)(import_fs2.default.mkdir);
112
+ rename = (0, import_util.promisify)(import_fs2.default.rename);
113
+ unlink = (0, import_util.promisify)(import_fs2.default.unlink);
114
+ CACHE_DIR = process.env.BOLTDOCS_CACHE_DIR || ".boltdocs";
115
+ ASSETS_DIR = "assets";
116
+ SHARDS_DIR = "shards";
117
+ DEFAULT_LRU_LIMIT = parseInt(
118
+ process.env.BOLTDOCS_CACHE_LRU_LIMIT || "2000",
119
+ 10
120
+ );
121
+ DEFAULT_COMPRESS = process.env.BOLTDOCS_CACHE_COMPRESS !== "0";
122
+ LRUCache = class {
123
+ constructor(limit) {
124
+ this.limit = limit;
157
125
  }
158
- }
159
- }
160
- /** Number of cached entries */
161
- get size() {
162
- return this.entries.size;
126
+ cache = /* @__PURE__ */ new Map();
127
+ get(key) {
128
+ const val = this.cache.get(key);
129
+ if (val !== void 0) {
130
+ this.cache.delete(key);
131
+ this.cache.set(key, val);
132
+ }
133
+ return val;
134
+ }
135
+ set(key, value) {
136
+ if (this.cache.has(key)) {
137
+ this.cache.delete(key);
138
+ } else if (this.cache.size >= this.limit) {
139
+ const firstKey = this.cache.keys().next().value;
140
+ if (firstKey !== void 0) {
141
+ this.cache.delete(firstKey);
142
+ }
143
+ }
144
+ this.cache.set(key, value);
145
+ }
146
+ get size() {
147
+ return this.cache.size;
148
+ }
149
+ clear() {
150
+ this.cache.clear();
151
+ }
152
+ };
153
+ BackgroundQueue = class {
154
+ queue = Promise.resolve();
155
+ pendingCount = 0;
156
+ add(task) {
157
+ this.pendingCount++;
158
+ this.queue = this.queue.then(task).finally(() => {
159
+ this.pendingCount--;
160
+ });
161
+ }
162
+ async flush() {
163
+ await this.queue;
164
+ }
165
+ get pending() {
166
+ return this.pendingCount;
167
+ }
168
+ };
169
+ backgroundQueue = new BackgroundQueue();
170
+ FileCache = class {
171
+ entries = /* @__PURE__ */ new Map();
172
+ cachePath = null;
173
+ compress;
174
+ constructor(options = {}) {
175
+ this.compress = options.compress !== void 0 ? options.compress : DEFAULT_COMPRESS;
176
+ if (options.name) {
177
+ const root = options.root || process.cwd();
178
+ const ext = this.compress ? "json.gz" : "json";
179
+ this.cachePath = import_path.default.resolve(root, CACHE_DIR, `${options.name}.${ext}`);
180
+ }
181
+ }
182
+ /**
183
+ * Loads the cache. Synchronous for startup simplicity but uses fast I/O.
184
+ */
185
+ load() {
186
+ if (process.env.BOLTDOCS_NO_CACHE === "1") return;
187
+ if (!this.cachePath || !import_fs2.default.existsSync(this.cachePath)) return;
188
+ try {
189
+ let raw = import_fs2.default.readFileSync(this.cachePath);
190
+ if (this.cachePath.endsWith(".gz")) {
191
+ raw = import_zlib.default.gunzipSync(raw);
192
+ }
193
+ const data = JSON.parse(raw.toString("utf-8"));
194
+ this.entries = new Map(Object.entries(data));
195
+ } catch (e) {
196
+ }
197
+ }
198
+ /**
199
+ * Saves the cache in the background.
200
+ */
201
+ save() {
202
+ if (process.env.BOLTDOCS_NO_CACHE === "1") return;
203
+ if (!this.cachePath) return;
204
+ const data = Object.fromEntries(this.entries);
205
+ const content = JSON.stringify(data);
206
+ const target = this.cachePath;
207
+ const useCompress = this.compress;
208
+ backgroundQueue.add(async () => {
209
+ try {
210
+ await mkdir(import_path.default.dirname(target), { recursive: true });
211
+ let buffer = Buffer.from(content);
212
+ if (useCompress) {
213
+ buffer = import_zlib.default.gzipSync(buffer);
214
+ }
215
+ const tempPath = `${target}.${import_crypto.default.randomBytes(4).toString("hex")}.tmp`;
216
+ await writeFile(tempPath, buffer);
217
+ await rename(tempPath, target);
218
+ } catch (e) {
219
+ }
220
+ });
221
+ }
222
+ get(filePath) {
223
+ const entry = this.entries.get(filePath);
224
+ if (!entry) return null;
225
+ if (getFileMtime(filePath) !== entry.mtime) return null;
226
+ return entry.data;
227
+ }
228
+ set(filePath, data) {
229
+ this.entries.set(filePath, {
230
+ data,
231
+ mtime: getFileMtime(filePath)
232
+ });
233
+ }
234
+ isValid(filePath) {
235
+ const entry = this.entries.get(filePath);
236
+ if (!entry) return false;
237
+ return getFileMtime(filePath) === entry.mtime;
238
+ }
239
+ invalidate(filePath) {
240
+ this.entries.delete(filePath);
241
+ }
242
+ invalidateAll() {
243
+ this.entries.clear();
244
+ }
245
+ pruneStale(currentFiles) {
246
+ for (const key of this.entries.keys()) {
247
+ if (!currentFiles.has(key)) {
248
+ this.entries.delete(key);
249
+ }
250
+ }
251
+ }
252
+ get size() {
253
+ return this.entries.size;
254
+ }
255
+ async flush() {
256
+ await backgroundQueue.flush();
257
+ }
258
+ };
259
+ TransformCache = class {
260
+ index = /* @__PURE__ */ new Map();
261
+ // key -> hash
262
+ memoryCache = new LRUCache(DEFAULT_LRU_LIMIT);
263
+ baseDir;
264
+ shardsDir;
265
+ indexPath;
266
+ constructor(name, root = process.cwd()) {
267
+ this.baseDir = import_path.default.resolve(root, CACHE_DIR, `transform-${name}`);
268
+ this.shardsDir = import_path.default.resolve(this.baseDir, SHARDS_DIR);
269
+ this.indexPath = import_path.default.resolve(this.baseDir, "index.json");
270
+ }
271
+ /**
272
+ * Loads the index into memory.
273
+ */
274
+ load() {
275
+ if (process.env.BOLTDOCS_NO_CACHE === "1") return;
276
+ if (!import_fs2.default.existsSync(this.indexPath)) return;
277
+ try {
278
+ const data = import_fs2.default.readFileSync(this.indexPath, "utf-8");
279
+ this.index = new Map(Object.entries(JSON.parse(data)));
280
+ } catch (e) {
281
+ }
282
+ }
283
+ /**
284
+ * Persists the index in background.
285
+ */
286
+ save() {
287
+ if (process.env.BOLTDOCS_NO_CACHE === "1") return;
288
+ const data = JSON.stringify(Object.fromEntries(this.index));
289
+ const target = this.indexPath;
290
+ backgroundQueue.add(async () => {
291
+ await mkdir(import_path.default.dirname(target), { recursive: true });
292
+ await writeFile(target, data);
293
+ });
294
+ }
295
+ /**
296
+ * Batch Read: Retrieves multiple transformation results concurrently.
297
+ */
298
+ async getMany(keys) {
299
+ const results = /* @__PURE__ */ new Map();
300
+ const toLoad = [];
301
+ for (const key of keys) {
302
+ const mem = this.memoryCache.get(key);
303
+ if (mem) results.set(key, mem);
304
+ else if (this.index.has(key)) toLoad.push(key);
305
+ }
306
+ if (toLoad.length > 0) {
307
+ const shards = await Promise.all(
308
+ toLoad.map(async (key) => {
309
+ const hash = this.index.get(key);
310
+ const shardPath = import_path.default.resolve(this.shardsDir, `${hash}.gz`);
311
+ try {
312
+ const compressed = await readFile(shardPath);
313
+ const decompressed = import_zlib.default.gunzipSync(compressed).toString("utf-8");
314
+ this.memoryCache.set(key, decompressed);
315
+ return { key, val: decompressed };
316
+ } catch (e) {
317
+ return null;
318
+ }
319
+ })
320
+ );
321
+ for (const s of shards) {
322
+ if (s) results.set(s.key, s.val);
323
+ }
324
+ }
325
+ return results;
326
+ }
327
+ /**
328
+ * Retrieves a cached transformation. Fast lookup via index, lazy loading from disk.
329
+ */
330
+ get(key) {
331
+ const mem = this.memoryCache.get(key);
332
+ if (mem) return mem;
333
+ const hash = this.index.get(key);
334
+ if (!hash) return null;
335
+ const shardPath = import_path.default.resolve(this.shardsDir, `${hash}.gz`);
336
+ if (!import_fs2.default.existsSync(shardPath)) return null;
337
+ try {
338
+ const compressed = import_fs2.default.readFileSync(shardPath);
339
+ const decompressed = import_zlib.default.gunzipSync(compressed).toString("utf-8");
340
+ this.memoryCache.set(key, decompressed);
341
+ return decompressed;
342
+ } catch (e) {
343
+ return null;
344
+ }
345
+ }
346
+ /**
347
+ * Stores a transformation result.
348
+ */
349
+ set(key, result) {
350
+ const hash = import_crypto.default.createHash("md5").update(result).digest("hex");
351
+ this.index.set(key, hash);
352
+ this.memoryCache.set(key, result);
353
+ const shardPath = import_path.default.resolve(this.shardsDir, `${hash}.gz`);
354
+ backgroundQueue.add(async () => {
355
+ if (import_fs2.default.existsSync(shardPath)) return;
356
+ await mkdir(this.shardsDir, { recursive: true });
357
+ const compressed = import_zlib.default.gzipSync(Buffer.from(result));
358
+ const tempPath = `${shardPath}.${import_crypto.default.randomBytes(4).toString("hex")}.tmp`;
359
+ await writeFile(tempPath, compressed);
360
+ await rename(tempPath, shardPath);
361
+ });
362
+ }
363
+ get size() {
364
+ return this.index.size;
365
+ }
366
+ async flush() {
367
+ await backgroundQueue.flush();
368
+ }
369
+ };
370
+ AssetCache = class {
371
+ assetsDir;
372
+ constructor(root = process.cwd()) {
373
+ this.assetsDir = import_path.default.resolve(root, CACHE_DIR, ASSETS_DIR);
374
+ }
375
+ getFileHash(filePath) {
376
+ return import_crypto.default.createHash("md5").update(import_fs2.default.readFileSync(filePath)).digest("hex");
377
+ }
378
+ get(sourcePath, cacheKey) {
379
+ if (!import_fs2.default.existsSync(sourcePath)) return null;
380
+ const sourceHash = this.getFileHash(sourcePath);
381
+ const cachedPath = this.getCachedPath(
382
+ sourcePath,
383
+ `${cacheKey}-${sourceHash}`
384
+ );
385
+ return import_fs2.default.existsSync(cachedPath) ? cachedPath : null;
386
+ }
387
+ set(sourcePath, cacheKey, content) {
388
+ const sourceHash = this.getFileHash(sourcePath);
389
+ const cachedPath = this.getCachedPath(
390
+ sourcePath,
391
+ `${cacheKey}-${sourceHash}`
392
+ );
393
+ backgroundQueue.add(async () => {
394
+ await mkdir(this.assetsDir, { recursive: true });
395
+ const tempPath = `${cachedPath}.${import_crypto.default.randomBytes(4).toString("hex")}.tmp`;
396
+ await writeFile(tempPath, content);
397
+ await rename(tempPath, cachedPath);
398
+ });
399
+ }
400
+ getCachedPath(sourcePath, cacheKey) {
401
+ const ext = import_path.default.extname(sourcePath);
402
+ const name = import_path.default.basename(sourcePath, ext);
403
+ const safeKey = cacheKey.replace(/[^a-z0-9]/gi, "-").toLowerCase();
404
+ return import_path.default.join(this.assetsDir, `${name}.${safeKey}${ext}`);
405
+ }
406
+ clear() {
407
+ if (import_fs2.default.existsSync(this.assetsDir)) {
408
+ import_fs2.default.rmSync(this.assetsDir, { recursive: true, force: true });
409
+ }
410
+ }
411
+ async flush() {
412
+ await backgroundQueue.flush();
413
+ }
414
+ };
163
415
  }
164
- };
416
+ });
417
+
418
+ // src/node/index.ts
419
+ var node_exports = {};
420
+ __export(node_exports, {
421
+ default: () => boltdocs,
422
+ generateStaticPages: () => generateStaticPages
423
+ });
424
+ module.exports = __toCommonJS(node_exports);
425
+
426
+ // src/node/plugin/index.ts
427
+ var import_vite = require("vite");
428
+
429
+ // src/node/routes/index.ts
430
+ var import_fast_glob = __toESM(require("fast-glob"));
431
+ init_utils();
165
432
 
166
433
  // src/node/routes/cache.ts
167
- var docCache = new FileCache();
434
+ init_cache();
435
+ var docCache = new FileCache({ name: "routes" });
168
436
  function invalidateRouteCache() {
169
437
  docCache.invalidateAll();
170
438
  }
@@ -173,11 +441,12 @@ function invalidateFile(filePath) {
173
441
  }
174
442
 
175
443
  // src/node/routes/parser.ts
176
- var import_path = __toESM(require("path"));
444
+ var import_path2 = __toESM(require("path"));
177
445
  var import_github_slugger = __toESM(require("github-slugger"));
446
+ init_utils();
178
447
  function parseDocFile(file, docsDir, basePath, config) {
179
448
  const { data, content } = parseFrontmatter(file);
180
- const relativePath = normalizePath(import_path.default.relative(docsDir, file));
449
+ const relativePath = normalizePath(import_path2.default.relative(docsDir, file));
181
450
  let parts = relativePath.split("/");
182
451
  let locale;
183
452
  let version;
@@ -209,7 +478,7 @@ function parseDocFile(file, docsDir, basePath, config) {
209
478
  const rawFileName = parts[parts.length - 1];
210
479
  const cleanFileName = stripNumberPrefix(rawFileName);
211
480
  const inferredTitle = stripNumberPrefix(
212
- import_path.default.basename(file, import_path.default.extname(file))
481
+ import_path2.default.basename(file, import_path2.default.extname(file))
213
482
  );
214
483
  const sidebarPosition = data.sidebarPosition ?? extractNumberPrefix(rawFileName);
215
484
  const rawDirName = parts.length >= 2 ? parts[0] : void 0;
@@ -277,6 +546,7 @@ function compareByGroupPosition(a, b) {
277
546
 
278
547
  // src/node/routes/index.ts
279
548
  async function generateRoutes(docsDir, config, basePath = "/docs") {
549
+ docCache.load();
280
550
  const files = await (0, import_fast_glob.default)(["**/*.md", "**/*.mdx"], {
281
551
  cwd: docsDir,
282
552
  absolute: true
@@ -285,15 +555,25 @@ async function generateRoutes(docsDir, config, basePath = "/docs") {
285
555
  if (config?.i18n) {
286
556
  docCache.invalidateAll();
287
557
  }
558
+ let cacheHits = 0;
288
559
  const parsed = await Promise.all(
289
560
  files.map(async (file) => {
290
561
  const cached = docCache.get(file);
291
- if (cached) return cached;
562
+ if (cached) {
563
+ cacheHits++;
564
+ return cached;
565
+ }
292
566
  const result = parseDocFile(file, docsDir, basePath, config);
293
567
  docCache.set(file, result);
294
568
  return result;
295
569
  })
296
570
  );
571
+ if (files.length > 0) {
572
+ console.log(
573
+ `[boltdocs] Routes generated: ${files.length} files (${cacheHits} from cache, ${files.length - cacheHits} parsed)`
574
+ );
575
+ }
576
+ docCache.save();
297
577
  const groupMeta = /* @__PURE__ */ new Map();
298
578
  for (const p of parsed) {
299
579
  if (p.relativeDir) {
@@ -371,9 +651,9 @@ async function generateRoutes(docsDir, config, basePath = "/docs") {
371
651
  var import_vite_plugin_image_optimizer = require("vite-plugin-image-optimizer");
372
652
 
373
653
  // src/node/config.ts
374
- var import_path2 = __toESM(require("path"));
654
+ var import_path3 = __toESM(require("path"));
375
655
  var import_url = require("url");
376
- var import_fs2 = __toESM(require("fs"));
656
+ var import_fs3 = __toESM(require("fs"));
377
657
  var CONFIG_FILES = [
378
658
  "boltdocs.config.js",
379
659
  "boltdocs.config.mjs",
@@ -382,7 +662,7 @@ var CONFIG_FILES = [
382
662
  async function resolveConfig(docsDir) {
383
663
  const projectRoot = process.cwd();
384
664
  const defaults = {
385
- docsDir: import_path2.default.resolve(docsDir),
665
+ docsDir: import_path3.default.resolve(docsDir),
386
666
  themeConfig: {
387
667
  title: "Boltdocs",
388
668
  description: "A Vite documentation framework",
@@ -393,15 +673,15 @@ async function resolveConfig(docsDir) {
393
673
  }
394
674
  };
395
675
  for (const filename of CONFIG_FILES) {
396
- const configPath = import_path2.default.resolve(projectRoot, filename);
397
- if (import_fs2.default.existsSync(configPath)) {
676
+ const configPath = import_path3.default.resolve(projectRoot, filename);
677
+ if (import_fs3.default.existsSync(configPath)) {
398
678
  try {
399
679
  const fileUrl = (0, import_url.pathToFileURL)(configPath).href + "?t=" + Date.now();
400
680
  const mod = await import(fileUrl);
401
681
  const userConfig = mod.default || mod;
402
682
  const userThemeConfig = userConfig.themeConfig || userConfig;
403
683
  return {
404
- docsDir: import_path2.default.resolve(docsDir),
684
+ docsDir: import_path3.default.resolve(docsDir),
405
685
  themeConfig: {
406
686
  ...defaults.themeConfig,
407
687
  ...userThemeConfig
@@ -420,8 +700,9 @@ async function resolveConfig(docsDir) {
420
700
  }
421
701
 
422
702
  // src/node/ssg/index.ts
423
- var import_fs3 = __toESM(require("fs"));
424
- var import_path3 = __toESM(require("path"));
703
+ var import_fs4 = __toESM(require("fs"));
704
+ var import_path4 = __toESM(require("path"));
705
+ init_utils();
425
706
  var import_url2 = require("url");
426
707
  var import_module = require("module");
427
708
 
@@ -486,15 +767,15 @@ ${entries.map(
486
767
  // src/node/ssg/index.ts
487
768
  var import_meta2 = {};
488
769
  var _filename = (0, import_url2.fileURLToPath)(import_meta2.url);
489
- var _dirname = import_path3.default.dirname(_filename);
770
+ var _dirname = import_path4.default.dirname(_filename);
490
771
  var _require = (0, import_module.createRequire)(import_meta2.url);
491
772
  async function generateStaticPages(options) {
492
773
  const { docsDir, outDir, config } = options;
493
774
  const routes = await generateRoutes(docsDir, config);
494
775
  const siteTitle = config?.themeConfig?.title || "Boltdocs";
495
776
  const siteDescription = config?.themeConfig?.description || "";
496
- const ssrModulePath = import_path3.default.resolve(_dirname, "../client/ssr.js");
497
- if (!import_fs3.default.existsSync(ssrModulePath)) {
777
+ const ssrModulePath = import_path4.default.resolve(_dirname, "../client/ssr.js");
778
+ if (!import_fs4.default.existsSync(ssrModulePath)) {
498
779
  console.error(
499
780
  "[boltdocs] SSR module not found at",
500
781
  ssrModulePath,
@@ -503,12 +784,12 @@ async function generateStaticPages(options) {
503
784
  return;
504
785
  }
505
786
  const { render } = _require(ssrModulePath);
506
- const templatePath = import_path3.default.join(outDir, "index.html");
507
- if (!import_fs3.default.existsSync(templatePath)) {
787
+ const templatePath = import_path4.default.join(outDir, "index.html");
788
+ if (!import_fs4.default.existsSync(templatePath)) {
508
789
  console.warn("[boltdocs] No index.html found in outDir, skipping SSG.");
509
790
  return;
510
791
  }
511
- const template = import_fs3.default.readFileSync(templatePath, "utf-8");
792
+ const template = import_fs4.default.readFileSync(templatePath, "utf-8");
512
793
  let homePageComp;
513
794
  if (config?._homePagePath) {
514
795
  try {
@@ -534,10 +815,10 @@ async function generateStaticPages(options) {
534
815
  title: escapeHtml(pageTitle),
535
816
  description: escapeHtml(pageDescription)
536
817
  }).replace("<!--app-html-->", appHtml).replace(`<div id="root"></div>`, `<div id="root">${appHtml}</div>`);
537
- const routeDir = import_path3.default.join(outDir, route.path);
538
- await import_fs3.default.promises.mkdir(routeDir, { recursive: true });
539
- await import_fs3.default.promises.writeFile(
540
- import_path3.default.join(routeDir, "index.html"),
818
+ const routeDir = import_path4.default.join(outDir, route.path);
819
+ await import_fs4.default.promises.mkdir(routeDir, { recursive: true });
820
+ await import_fs4.default.promises.writeFile(
821
+ import_path4.default.join(routeDir, "index.html"),
541
822
  html,
542
823
  "utf-8"
543
824
  );
@@ -550,16 +831,20 @@ async function generateStaticPages(options) {
550
831
  routes.map((r) => r.path),
551
832
  config
552
833
  );
553
- import_fs3.default.writeFileSync(import_path3.default.join(outDir, "sitemap.xml"), sitemap, "utf-8");
834
+ import_fs4.default.writeFileSync(import_path4.default.join(outDir, "sitemap.xml"), sitemap, "utf-8");
554
835
  console.log(
555
836
  `[boltdocs] Generated ${routes.length} static pages + sitemap.xml`
556
837
  );
838
+ const { flushCache: flushCache2 } = await Promise.resolve().then(() => (init_cache(), cache_exports));
839
+ await flushCache2();
557
840
  }
558
841
 
559
842
  // src/node/plugin/index.ts
560
- var import_path4 = __toESM(require("path"));
843
+ init_utils();
844
+ var import_path5 = __toESM(require("path"));
561
845
 
562
846
  // src/node/plugin/entry.ts
847
+ init_utils();
563
848
  function generateEntryCode(options, config) {
564
849
  const homeImport = options.homePage ? `import HomePage from '${normalizePath(options.homePage)}';` : "";
565
850
  const homeOption = options.homePage ? "homePage: HomePage," : "";
@@ -568,8 +853,8 @@ function generateEntryCode(options, config) {
568
853
  const componentImports = pluginComponents.map(
569
854
  ([
570
855
  name,
571
- path5
572
- ]) => `import * as _comp_${name} from '${normalizePath(path5)}';
856
+ path6
857
+ ]) => `import * as _comp_${name} from '${normalizePath(path6)}';
573
858
  const ${name} = _comp_${name}.default || _comp_${name}['${name}'] || _comp_${name};`
574
859
  ).join("\n");
575
860
  const componentMap = pluginComponents.map(([name]) => name).join(", ");
@@ -639,7 +924,7 @@ ${themeScript} </head>`);
639
924
 
640
925
  // src/node/plugin/index.ts
641
926
  function boltdocsPlugin(options = {}, passedConfig) {
642
- const docsDir = import_path4.default.resolve(process.cwd(), options.docsDir || "docs");
927
+ const docsDir = import_path5.default.resolve(process.cwd(), options.docsDir || "docs");
643
928
  const normalizedDocsDir = normalizePath(docsDir);
644
929
  let config = passedConfig;
645
930
  let viteConfig;
@@ -669,7 +954,7 @@ function boltdocsPlugin(options = {}, passedConfig) {
669
954
  },
670
955
  configureServer(server) {
671
956
  const configPaths = CONFIG_FILES.map(
672
- (c) => import_path4.default.resolve(process.cwd(), c)
957
+ (c) => import_path5.default.resolve(process.cwd(), c)
673
958
  );
674
959
  server.watcher.add(configPaths);
675
960
  const handleFileEvent = async (file, type) => {
@@ -732,8 +1017,10 @@ function boltdocsPlugin(options = {}, passedConfig) {
732
1017
  },
733
1018
  async closeBundle() {
734
1019
  if (!isBuild) return;
735
- const outDir = viteConfig?.build?.outDir ? import_path4.default.resolve(viteConfig.root, viteConfig.build.outDir) : import_path4.default.resolve(process.cwd(), "dist");
1020
+ const outDir = viteConfig?.build?.outDir ? import_path5.default.resolve(viteConfig.root, viteConfig.build.outDir) : import_path5.default.resolve(process.cwd(), "dist");
736
1021
  await generateStaticPages({ docsDir, outDir, config });
1022
+ const { flushCache: flushCache2 } = await Promise.resolve().then(() => (init_cache(), cache_exports));
1023
+ await flushCache2();
737
1024
  }
738
1025
  },
739
1026
  (0, import_vite_plugin_image_optimizer.ViteImageOptimizer)({
@@ -763,10 +1050,14 @@ var import_remark_gfm = __toESM(require("remark-gfm"));
763
1050
  var import_remark_frontmatter = __toESM(require("remark-frontmatter"));
764
1051
  var import_rehype_slug = __toESM(require("rehype-slug"));
765
1052
  var import_rehype_pretty_code = __toESM(require("rehype-pretty-code"));
1053
+ var import_crypto2 = __toESM(require("crypto"));
1054
+ init_cache();
1055
+ var mdxCache = new TransformCache("mdx");
1056
+ var mdxCacheLoaded = false;
766
1057
  function boltdocsMdxPlugin(config) {
767
1058
  const extraRemarkPlugins = config?.plugins?.flatMap((p) => p.remarkPlugins || []) || [];
768
1059
  const extraRehypePlugins = config?.plugins?.flatMap((p) => p.rehypePlugins || []) || [];
769
- return (0, import_rollup.default)({
1060
+ const baseMdxPlugin = (0, import_rollup.default)({
770
1061
  remarkPlugins: [import_remark_gfm.default, import_remark_frontmatter.default, ...extraRemarkPlugins],
771
1062
  rehypePlugins: [
772
1063
  import_rehype_slug.default,
@@ -774,16 +1065,64 @@ function boltdocsMdxPlugin(config) {
774
1065
  [
775
1066
  import_rehype_pretty_code.default,
776
1067
  {
777
- theme: "one-dark-pro",
1068
+ theme: config?.themeConfig?.codeTheme || "one-dark-pro",
778
1069
  keepBackground: false
779
1070
  }
780
1071
  ]
781
1072
  ],
782
- // Provide React as default for JSX
783
1073
  jsxRuntime: "automatic",
784
1074
  providerImportSource: "@mdx-js/react"
785
1075
  });
1076
+ return {
1077
+ ...baseMdxPlugin,
1078
+ name: "vite-plugin-boltdocs-mdx",
1079
+ async buildStart() {
1080
+ hits = 0;
1081
+ total = 0;
1082
+ if (!mdxCacheLoaded) {
1083
+ mdxCache.load();
1084
+ mdxCacheLoaded = true;
1085
+ }
1086
+ if (baseMdxPlugin.buildStart) {
1087
+ await baseMdxPlugin.buildStart.call(this);
1088
+ }
1089
+ },
1090
+ async transform(code, id, options) {
1091
+ if (!id.endsWith(".md") && !id.endsWith(".mdx")) {
1092
+ return baseMdxPlugin.transform?.call(this, code, id, options);
1093
+ }
1094
+ total++;
1095
+ const contentHash = import_crypto2.default.createHash("md5").update(code).digest("hex");
1096
+ const cacheKey = `${id}:${contentHash}`;
1097
+ const cached = mdxCache.get(cacheKey);
1098
+ if (cached) {
1099
+ hits++;
1100
+ return { code: cached, map: null };
1101
+ }
1102
+ const result = await baseMdxPlugin.transform.call(
1103
+ this,
1104
+ code,
1105
+ id,
1106
+ options
1107
+ );
1108
+ if (result && typeof result === "object" && result.code) {
1109
+ mdxCache.set(cacheKey, result.code);
1110
+ } else if (typeof result === "string") {
1111
+ mdxCache.set(cacheKey, result);
1112
+ }
1113
+ return result;
1114
+ },
1115
+ async buildEnd() {
1116
+ mdxCache.save();
1117
+ await mdxCache.flush();
1118
+ if (baseMdxPlugin.buildEnd) {
1119
+ await baseMdxPlugin.buildEnd.call(this);
1120
+ }
1121
+ }
1122
+ };
786
1123
  }
1124
+ var hits = 0;
1125
+ var total = 0;
787
1126
 
788
1127
  // src/node/index.ts
789
1128
  async function boltdocs(options) {