boltdocs 1.4.0 → 1.4.1

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.
@@ -3,7 +3,7 @@ import {
3
3
  FileCache,
4
4
  TransformCache,
5
5
  flushCache
6
- } from "./chunk-CYBWLFOG.mjs";
6
+ } from "./chunk-FFBNU6IJ.mjs";
7
7
  export {
8
8
  AssetCache,
9
9
  FileCache,
@@ -41,7 +41,8 @@ function escapeXml(str) {
41
41
  }
42
42
  function fileToRoutePath(relativePath) {
43
43
  let cleanedPath = relativePath.split("/").map(stripNumberPrefix).join("/");
44
- let routePath = cleanedPath.replace(/\.mdx?$/, "");
44
+ let routePath = cleanedPath.replace(/\/$/, "");
45
+ routePath = routePath.replace(/\.mdx?$/, "");
45
46
  if (routePath === "index" || routePath.endsWith("/index")) {
46
47
  routePath = routePath.replace(/index$/, "");
47
48
  }
@@ -64,7 +64,8 @@ function escapeXml(str) {
64
64
  }
65
65
  function fileToRoutePath(relativePath) {
66
66
  let cleanedPath = relativePath.split("/").map(stripNumberPrefix).join("/");
67
- let routePath = cleanedPath.replace(/\.mdx?$/, "");
67
+ let routePath = cleanedPath.replace(/\/$/, "");
68
+ routePath = routePath.replace(/\.mdx?$/, "");
68
69
  if (routePath === "index" || routePath.endsWith("/index")) {
69
70
  routePath = routePath.replace(/index$/, "");
70
71
  }
@@ -478,7 +479,12 @@ function parseDocFile(file, docsDir, basePath, config) {
478
479
  }
479
480
  }
480
481
  const cleanRelativePath = parts.join("/");
481
- const cleanRoutePath = fileToRoutePath(cleanRelativePath || "index.md");
482
+ let cleanRoutePath;
483
+ if (data.permalink) {
484
+ cleanRoutePath = data.permalink.startsWith("/") ? data.permalink : `/${data.permalink}`;
485
+ } else {
486
+ cleanRoutePath = fileToRoutePath(cleanRelativePath || "index.md");
487
+ }
482
488
  let finalPath = basePath;
483
489
  if (version) {
484
490
  finalPath += "/" + version;
@@ -677,8 +683,8 @@ var CONFIG_FILES = [
677
683
  "boltdocs.config.mjs",
678
684
  "boltdocs.config.ts"
679
685
  ];
680
- async function resolveConfig(docsDir) {
681
- const projectRoot = process.cwd();
686
+ async function resolveConfig(docsDir, root = process.cwd()) {
687
+ const projectRoot = root;
682
688
  const defaults = {
683
689
  docsDir: import_path3.default.resolve(docsDir),
684
690
  themeConfig: {
@@ -694,7 +700,8 @@ async function resolveConfig(docsDir) {
694
700
  const configPath = import_path3.default.resolve(projectRoot, filename);
695
701
  if (import_fs3.default.existsSync(configPath)) {
696
702
  try {
697
- const fileUrl = (0, import_url.pathToFileURL)(configPath).href + "?t=" + Date.now();
703
+ const isTest = process.env.NODE_ENV === "test" || global.__vitest_worker__;
704
+ const fileUrl = (0, import_url.pathToFileURL)(configPath).href + (isTest ? "" : "?t=" + Date.now());
698
705
  const mod = await import(fileUrl);
699
706
  const userConfig = mod.default || mod;
700
707
  const userThemeConfig = userConfig.themeConfig || userConfig;
@@ -806,12 +813,6 @@ async function generateStaticPages(options) {
806
813
  return;
807
814
  }
808
815
  const template = import_fs4.default.readFileSync(templatePath, "utf-8");
809
- let homePageComp;
810
- if (config?._homePagePath) {
811
- try {
812
- } catch (e) {
813
- }
814
- }
815
816
  await Promise.all(
816
817
  routes.map(async (route) => {
817
818
  const pageTitle = `${route.title} | ${siteTitle}`;
@@ -825,7 +826,8 @@ async function generateStaticPages(options) {
825
826
  routes,
826
827
  config: config || {},
827
828
  modules: fakeModules,
828
- homePage: homePageComp
829
+ homePage: void 0
830
+ // No custom home page for now
829
831
  });
830
832
  const html = replaceMetaTags(template, {
831
833
  title: escapeHtml(pageTitle),
@@ -1070,10 +1072,10 @@ var import_crypto2 = __toESM(require("crypto"));
1070
1072
  init_cache();
1071
1073
  var mdxCache = new TransformCache("mdx");
1072
1074
  var mdxCacheLoaded = false;
1073
- function boltdocsMdxPlugin(config) {
1075
+ function boltdocsMdxPlugin(config, compiler = import_rollup.default) {
1074
1076
  const extraRemarkPlugins = config?.plugins?.flatMap((p) => p.remarkPlugins || []) || [];
1075
1077
  const extraRehypePlugins = config?.plugins?.flatMap((p) => p.rehypePlugins || []) || [];
1076
- const baseMdxPlugin = (0, import_rollup.default)({
1078
+ const baseMdxPlugin = compiler({
1077
1079
  remarkPlugins: [import_remark_gfm.default, import_remark_frontmatter.default, ...extraRemarkPlugins],
1078
1080
  rehypePlugins: [
1079
1081
  import_rehype_slug.default,
@@ -1089,6 +1091,9 @@ function boltdocsMdxPlugin(config) {
1089
1091
  jsxRuntime: "automatic",
1090
1092
  providerImportSource: "@mdx-js/react"
1091
1093
  });
1094
+ if (baseMdxPlugin.isMock) {
1095
+ console.log("MDX PLUGIN IS MOCKED");
1096
+ }
1092
1097
  return {
1093
1098
  ...baseMdxPlugin,
1094
1099
  name: "vite-plugin-boltdocs-mdx",
@@ -1123,8 +1128,6 @@ function boltdocsMdxPlugin(config) {
1123
1128
  );
1124
1129
  if (result && typeof result === "object" && result.code) {
1125
1130
  mdxCache.set(cacheKey, result.code);
1126
- } else if (typeof result === "string") {
1127
- mdxCache.set(cacheKey, result);
1128
1131
  }
1129
1132
  return result;
1130
1133
  },
@@ -10,7 +10,7 @@ import {
10
10
  normalizePath,
11
11
  parseFrontmatter,
12
12
  stripNumberPrefix
13
- } from "../chunk-CYBWLFOG.mjs";
13
+ } from "../chunk-FFBNU6IJ.mjs";
14
14
 
15
15
  // src/node/plugin/index.ts
16
16
  import { loadEnv } from "vite";
@@ -61,7 +61,12 @@ function parseDocFile(file, docsDir, basePath, config) {
61
61
  }
62
62
  }
63
63
  const cleanRelativePath = parts.join("/");
64
- const cleanRoutePath = fileToRoutePath(cleanRelativePath || "index.md");
64
+ let cleanRoutePath;
65
+ if (data.permalink) {
66
+ cleanRoutePath = data.permalink.startsWith("/") ? data.permalink : `/${data.permalink}`;
67
+ } else {
68
+ cleanRoutePath = fileToRoutePath(cleanRelativePath || "index.md");
69
+ }
65
70
  let finalPath = basePath;
66
71
  if (version) {
67
72
  finalPath += "/" + version;
@@ -260,8 +265,8 @@ var CONFIG_FILES = [
260
265
  "boltdocs.config.mjs",
261
266
  "boltdocs.config.ts"
262
267
  ];
263
- async function resolveConfig(docsDir) {
264
- const projectRoot = process.cwd();
268
+ async function resolveConfig(docsDir, root = process.cwd()) {
269
+ const projectRoot = root;
265
270
  const defaults = {
266
271
  docsDir: path2.resolve(docsDir),
267
272
  themeConfig: {
@@ -277,7 +282,8 @@ async function resolveConfig(docsDir) {
277
282
  const configPath = path2.resolve(projectRoot, filename);
278
283
  if (fs.existsSync(configPath)) {
279
284
  try {
280
- const fileUrl = pathToFileURL(configPath).href + "?t=" + Date.now();
285
+ const isTest = process.env.NODE_ENV === "test" || global.__vitest_worker__;
286
+ const fileUrl = pathToFileURL(configPath).href + (isTest ? "" : "?t=" + Date.now());
281
287
  const mod = await import(fileUrl);
282
288
  const userConfig = mod.default || mod;
283
289
  const userThemeConfig = userConfig.themeConfig || userConfig;
@@ -385,12 +391,6 @@ async function generateStaticPages(options) {
385
391
  return;
386
392
  }
387
393
  const template = fs2.readFileSync(templatePath, "utf-8");
388
- let homePageComp;
389
- if (config?._homePagePath) {
390
- try {
391
- } catch (e) {
392
- }
393
- }
394
394
  await Promise.all(
395
395
  routes.map(async (route) => {
396
396
  const pageTitle = `${route.title} | ${siteTitle}`;
@@ -404,7 +404,8 @@ async function generateStaticPages(options) {
404
404
  routes,
405
405
  config: config || {},
406
406
  modules: fakeModules,
407
- homePage: homePageComp
407
+ homePage: void 0
408
+ // No custom home page for now
408
409
  });
409
410
  const html = replaceMetaTags(template, {
410
411
  title: escapeHtml(pageTitle),
@@ -430,7 +431,7 @@ async function generateStaticPages(options) {
430
431
  console.log(
431
432
  `[boltdocs] Generated ${routes.length} static pages + sitemap.xml`
432
433
  );
433
- const { flushCache } = await import("../cache-GQHF6BXI.mjs");
434
+ const { flushCache } = await import("../cache-KNL5B4EE.mjs");
434
435
  await flushCache();
435
436
  }
436
437
 
@@ -612,7 +613,7 @@ function boltdocsPlugin(options = {}, passedConfig) {
612
613
  if (!isBuild) return;
613
614
  const outDir = viteConfig?.build?.outDir ? path4.resolve(viteConfig.root, viteConfig.build.outDir) : path4.resolve(process.cwd(), "dist");
614
615
  await generateStaticPages({ docsDir, outDir, config });
615
- const { flushCache } = await import("../cache-GQHF6BXI.mjs");
616
+ const { flushCache } = await import("../cache-KNL5B4EE.mjs");
616
617
  await flushCache();
617
618
  }
618
619
  },
@@ -646,10 +647,10 @@ import rehypePrettyCode from "rehype-pretty-code";
646
647
  import crypto from "crypto";
647
648
  var mdxCache = new TransformCache("mdx");
648
649
  var mdxCacheLoaded = false;
649
- function boltdocsMdxPlugin(config) {
650
+ function boltdocsMdxPlugin(config, compiler = mdxPlugin) {
650
651
  const extraRemarkPlugins = config?.plugins?.flatMap((p) => p.remarkPlugins || []) || [];
651
652
  const extraRehypePlugins = config?.plugins?.flatMap((p) => p.rehypePlugins || []) || [];
652
- const baseMdxPlugin = mdxPlugin({
653
+ const baseMdxPlugin = compiler({
653
654
  remarkPlugins: [remarkGfm, remarkFrontmatter, ...extraRemarkPlugins],
654
655
  rehypePlugins: [
655
656
  rehypeSlug,
@@ -665,6 +666,9 @@ function boltdocsMdxPlugin(config) {
665
666
  jsxRuntime: "automatic",
666
667
  providerImportSource: "@mdx-js/react"
667
668
  });
669
+ if (baseMdxPlugin.isMock) {
670
+ console.log("MDX PLUGIN IS MOCKED");
671
+ }
668
672
  return {
669
673
  ...baseMdxPlugin,
670
674
  name: "vite-plugin-boltdocs-mdx",
@@ -699,8 +703,6 @@ function boltdocsMdxPlugin(config) {
699
703
  );
700
704
  if (result && typeof result === "object" && result.code) {
701
705
  mdxCache.set(cacheKey, result.code);
702
- } else if (typeof result === "string") {
703
- mdxCache.set(cacheKey, result);
704
706
  }
705
707
  return result;
706
708
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "boltdocs",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "description": "A lightweight documentation generator for React projects.",
5
5
  "main": "dist/node/index.js",
6
6
  "module": "dist/node/index.mjs",
@@ -139,11 +139,15 @@ export const CONFIG_FILES = [
139
139
  * Loads user's configuration file (e.g., `boltdocs.config.js` or `boltdocs.config.ts`) if it exists,
140
140
  * merges it with the default configuration, and returns the final `BoltdocsConfig`.
141
141
  *
142
- * @param docsDir - The fallback/default documentation directory
143
- * @returns A promise resolving to the final merged configuration object
142
+ * @param docsDir - The directory containing the documentation files
143
+ * @param root - The project root directory (defaults to process.cwd())
144
+ * @returns The merged configuration object
144
145
  */
145
- export async function resolveConfig(docsDir: string): Promise<BoltdocsConfig> {
146
- const projectRoot = process.cwd();
146
+ export async function resolveConfig(
147
+ docsDir: string,
148
+ root: string = process.cwd(),
149
+ ): Promise<BoltdocsConfig> {
150
+ const projectRoot = root;
147
151
 
148
152
  const defaults: BoltdocsConfig = {
149
153
  docsDir: path.resolve(docsDir),
@@ -162,8 +166,11 @@ export async function resolveConfig(docsDir: string): Promise<BoltdocsConfig> {
162
166
  const configPath = path.resolve(projectRoot, filename);
163
167
  if (fs.existsSync(configPath)) {
164
168
  try {
165
- // Add a timestamp query parameter to bust the ESM cache
166
- const fileUrl = pathToFileURL(configPath).href + "?t=" + Date.now();
169
+ // Add a timestamp query parameter to bust the ESM cache in dev
170
+ const isTest =
171
+ process.env.NODE_ENV === "test" || (global as any).__vitest_worker__;
172
+ const fileUrl =
173
+ pathToFileURL(configPath).href + (isTest ? "" : "?t=" + Date.now());
167
174
  const mod = await import(fileUrl);
168
175
  const userConfig = mod.default || mod;
169
176
 
package/src/node/mdx.ts CHANGED
@@ -24,15 +24,19 @@ let mdxCacheLoaded = false;
24
24
  * Also wraps the plugin with a persistent cache to avoid re-compiling unchanged MDX files.
25
25
  *
26
26
  * @param config - The Boltdocs configuration containing custom plugins
27
+ * @param compiler - The MDX compiler plugin (for testing)
27
28
  * @returns A Vite plugin configured for MDX parsing with caching
28
29
  */
29
- export function boltdocsMdxPlugin(config?: BoltdocsConfig): Plugin {
30
+ export function boltdocsMdxPlugin(
31
+ config?: BoltdocsConfig,
32
+ compiler = mdxPlugin,
33
+ ): Plugin {
30
34
  const extraRemarkPlugins =
31
35
  config?.plugins?.flatMap((p) => p.remarkPlugins || []) || [];
32
36
  const extraRehypePlugins =
33
37
  config?.plugins?.flatMap((p) => p.rehypePlugins || []) || [];
34
38
 
35
- const baseMdxPlugin = mdxPlugin({
39
+ const baseMdxPlugin = compiler({
36
40
  remarkPlugins: [remarkGfm, remarkFrontmatter, ...extraRemarkPlugins],
37
41
  rehypePlugins: [
38
42
  rehypeSlug,
@@ -49,6 +53,11 @@ export function boltdocsMdxPlugin(config?: BoltdocsConfig): Plugin {
49
53
  providerImportSource: "@mdx-js/react",
50
54
  }) as Plugin;
51
55
 
56
+ // @ts-ignore
57
+ if (baseMdxPlugin.isMock) {
58
+ console.log("MDX PLUGIN IS MOCKED");
59
+ }
60
+
52
61
  return {
53
62
  ...baseMdxPlugin,
54
63
  name: "vite-plugin-boltdocs-mdx",
@@ -90,8 +99,6 @@ export function boltdocsMdxPlugin(config?: BoltdocsConfig): Plugin {
90
99
 
91
100
  if (result && typeof result === "object" && result.code) {
92
101
  mdxCache.set(cacheKey, result.code);
93
- } else if (typeof result === "string") {
94
- mdxCache.set(cacheKey, result);
95
102
  }
96
103
 
97
104
  return result;
@@ -70,7 +70,16 @@ export function parseDocFile(
70
70
  }
71
71
 
72
72
  const cleanRelativePath = parts.join("/");
73
- const cleanRoutePath = fileToRoutePath(cleanRelativePath || "index.md");
73
+
74
+ let cleanRoutePath: string;
75
+ if (data.permalink) {
76
+ // If a permalink is specified, ensure it starts with a slash
77
+ cleanRoutePath = data.permalink.startsWith("/")
78
+ ? data.permalink
79
+ : `/${data.permalink}`;
80
+ } else {
81
+ cleanRoutePath = fileToRoutePath(cleanRelativePath || "index.md");
82
+ }
74
83
 
75
84
  let finalPath = basePath;
76
85
  if (version) {
@@ -49,15 +49,6 @@ export async function generateStaticPages(options: SSGOptions): Promise<void> {
49
49
  }
50
50
  const template = fs.readFileSync(templatePath, "utf-8");
51
51
 
52
- // Load user's homePage if configured
53
- let homePageComp;
54
- if ((config as any)?._homePagePath) {
55
- try {
56
- // Simplistic: if there's a custom home page compiled, we'd need it available to SSR.
57
- // In a full framework this is complex, but for Boltdocs we assume it's bundled if needed.
58
- } catch (e) {}
59
- }
60
-
61
52
  // Generate an HTML file for each route concurrently
62
53
  await Promise.all(
63
54
  routes.map(async (route) => {
@@ -74,7 +65,7 @@ export async function generateStaticPages(options: SSGOptions): Promise<void> {
74
65
  routes: routes,
75
66
  config: config || {},
76
67
  modules: fakeModules,
77
- homePage: homePageComp,
68
+ homePage: undefined, // No custom home page for now
78
69
  });
79
70
 
80
71
  const html = replaceMetaTags(template, {
package/src/node/utils.ts CHANGED
@@ -113,7 +113,10 @@ export function fileToRoutePath(relativePath: string): string {
113
113
  // Strip number prefixes from every segment
114
114
  let cleanedPath = relativePath.split("/").map(stripNumberPrefix).join("/");
115
115
 
116
- let routePath = cleanedPath.replace(/\.mdx?$/, "");
116
+ // Remove trailing slash if present
117
+ let routePath = cleanedPath.replace(/\/$/, "");
118
+
119
+ routePath = routePath.replace(/\.mdx?$/, "");
117
120
 
118
121
  // Handle index files → directory root
119
122
  if (routePath === "index" || routePath.endsWith("/index")) {