@mgks/docmd 0.1.2 โ†’ 0.1.4

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 (38) hide show
  1. package/.github/workflows/deploy-docmd.yml +2 -2
  2. package/README.md +3 -1
  3. package/assets/css/welcome.css +378 -0
  4. package/assets/images/preview-dark-1.png +0 -0
  5. package/assets/images/preview-dark-2.png +0 -0
  6. package/assets/images/preview-dark-3.png +0 -0
  7. package/assets/images/preview-light-1.png +0 -0
  8. package/assets/images/preview-light-2.png +0 -0
  9. package/assets/images/preview-light-3.png +0 -0
  10. package/config.js +8 -3
  11. package/docs/cli-commands.md +1 -2
  12. package/docs/configuration.md +34 -22
  13. package/docs/content/frontmatter.md +2 -2
  14. package/docs/content/index.md +5 -4
  15. package/docs/content/markdown-syntax.md +4 -4
  16. package/docs/content/no-style-example.md +110 -0
  17. package/docs/content/no-style-pages.md +202 -0
  18. package/docs/contributing.md +7 -0
  19. package/docs/deployment.md +22 -31
  20. package/docs/getting-started/basic-usage.md +3 -2
  21. package/docs/getting-started/index.md +3 -3
  22. package/docs/getting-started/installation.md +1 -1
  23. package/docs/index.md +137 -53
  24. package/docs/overview.md +56 -0
  25. package/docs/plugins/sitemap.md +1 -1
  26. package/docs/theming/assets-management.md +1 -1
  27. package/docs/theming/available-themes.md +29 -51
  28. package/package.json +1 -1
  29. package/src/assets/css/docmd-main.css +2 -1
  30. package/src/assets/css/docmd-theme-ruby.css +606 -0
  31. package/src/commands/build.js +239 -203
  32. package/src/commands/dev.js +75 -30
  33. package/src/commands/init.js +2 -0
  34. package/src/core/file-processor.js +67 -5
  35. package/src/core/html-generator.js +16 -3
  36. package/src/plugins/sitemap.js +15 -1
  37. package/src/templates/layout.ejs +1 -1
  38. package/src/templates/no-style.ejs +159 -0
@@ -2,11 +2,12 @@
2
2
  const fs = require('fs-extra');
3
3
  const path = require('path');
4
4
  const { loadConfig } = require('../core/config-loader');
5
- const { processMarkdownFile } = require('../core/file-processor');
5
+ const { processMarkdownFile, findMarkdownFiles } = require('../core/file-processor');
6
6
  const { generateHtmlPage, generateNavigationHtml } = require('../core/html-generator');
7
7
  const { renderIcon, clearWarnedIcons } = require('../core/icon-renderer'); // Update import
8
8
  const { generateSitemap } = require('../plugins/sitemap'); // Import our sitemap plugin
9
9
  const { version } = require('../../package.json'); // Import package version
10
+ const matter = require('gray-matter'); // Use gray-matter instead of front-matter
10
11
 
11
12
  // Debug function to log navigation information
12
13
  function logNavigationPaths(pagePath, navPath, normalizedPath) {
@@ -28,7 +29,26 @@ const ASSET_VERSIONS = {
28
29
  // Add other assets here with their versions
29
30
  };
30
31
 
31
- async function buildSite(configPath, options = { isDev: false, preserve: false }) {
32
+ /**
33
+ * Format paths for display to make them relative to CWD
34
+ * @param {string} absolutePath - The absolute path to format
35
+ * @param {string} cwd - Current working directory
36
+ * @returns {string} - Formatted relative path
37
+ */
38
+ function formatPathForDisplay(absolutePath, cwd) {
39
+ // Get the relative path from CWD
40
+ const relativePath = path.relative(cwd, absolutePath);
41
+
42
+ // If it's not a subdirectory, prefix with ./ for clarity
43
+ if (!relativePath.startsWith('..') && !path.isAbsolute(relativePath)) {
44
+ return `./${relativePath}`;
45
+ }
46
+
47
+ // Return the relative path
48
+ return relativePath;
49
+ }
50
+
51
+ async function buildSite(configPath, options = { isDev: false, preserve: false, noDoubleProcessing: false }) {
32
52
  clearWarnedIcons(); // Clear warnings at the start of every build
33
53
 
34
54
  const config = await loadConfig(configPath);
@@ -38,7 +58,7 @@ async function buildSite(configPath, options = { isDev: false, preserve: false }
38
58
  const USER_ASSETS_DIR = path.resolve(CWD, 'assets'); // User's custom assets directory
39
59
 
40
60
  if (!await fs.pathExists(SRC_DIR)) {
41
- throw new Error(`Source directory not found: ${SRC_DIR}`);
61
+ throw new Error(`Source directory not found: ${formatPathForDisplay(SRC_DIR, CWD)}`);
42
62
  }
43
63
 
44
64
  // Create output directory if it doesn't exist
@@ -52,7 +72,7 @@ async function buildSite(configPath, options = { isDev: false, preserve: false }
52
72
  await fs.remove(file);
53
73
  }
54
74
  if (!options.isDev) {
55
- console.log(`๐Ÿงน Cleaned HTML files from output directory: ${OUTPUT_DIR}`);
75
+ console.log(`๐Ÿงน Cleaned HTML files from output directory: ${formatPathForDisplay(OUTPUT_DIR, CWD)}`);
56
76
  }
57
77
  }
58
78
 
@@ -66,7 +86,7 @@ async function buildSite(configPath, options = { isDev: false, preserve: false }
66
86
  await fs.ensureDir(assetsDestDir);
67
87
 
68
88
  if (!options.isDev) {
69
- console.log(`๐Ÿ“‚ Copying user assets from ${USER_ASSETS_DIR} to ${assetsDestDir}...`);
89
+ console.log(`๐Ÿ“‚ Copying user assets from ${formatPathForDisplay(USER_ASSETS_DIR, CWD)} to ${formatPathForDisplay(assetsDestDir, CWD)}...`);
70
90
  }
71
91
 
72
92
  const userAssetFiles = await getAllFiles(USER_ASSETS_DIR);
@@ -92,7 +112,7 @@ async function buildSite(configPath, options = { isDev: false, preserve: false }
92
112
 
93
113
  if (await fs.pathExists(assetsSrcDir)) {
94
114
  if (!options.isDev) {
95
- console.log(`๐Ÿ“‚ Copying docmd assets to ${assetsDestDir}...`);
115
+ console.log(`๐Ÿ“‚ Copying docmd assets to ${formatPathForDisplay(assetsDestDir, CWD)}...`);
96
116
  }
97
117
 
98
118
  // Create destination directory if it doesn't exist
@@ -125,7 +145,7 @@ async function buildSite(configPath, options = { isDev: false, preserve: false }
125
145
  }
126
146
  }
127
147
  } else {
128
- console.warn(`โš ๏ธ Assets source directory not found: ${assetsSrcDir}`);
148
+ console.warn(`โš ๏ธ Assets source directory not found: ${formatPathForDisplay(assetsSrcDir, CWD)}`);
129
149
  }
130
150
 
131
151
  // Check for Highlight.js themes
@@ -139,8 +159,8 @@ async function buildSite(configPath, options = { isDev: false, preserve: false }
139
159
  // For 'docmd dev', show only once per session if not already shown.
140
160
  if (!options.isDev || (options.isDev && !highlightWarningShown)) {
141
161
  console.warn(`โš ๏ธ Highlight.js themes not found in assets. Please ensure these files exist:
142
- - ${lightThemePath}
143
- - ${darkThemePath}
162
+ - ${path.relative(CWD, lightThemePath)}
163
+ - ${path.relative(CWD, darkThemePath)}
144
164
  Syntax highlighting may not work correctly.`);
145
165
  if (options.isDev) {
146
166
  highlightWarningShown = true; // Mark as shown for this dev session
@@ -148,211 +168,236 @@ async function buildSite(configPath, options = { isDev: false, preserve: false }
148
168
  }
149
169
  }
150
170
 
171
+ // Array to collect information about all processed pages for sitemap
172
+ const processedPages = [];
151
173
 
174
+ // Find all Markdown files in the source directory
152
175
  const markdownFiles = await findMarkdownFiles(SRC_DIR);
153
- if (markdownFiles.length === 0) {
154
- console.warn(`โš ๏ธ No Markdown files found in ${SRC_DIR}. Nothing to build.`);
155
- return;
156
- }
157
176
  if (!options.isDev) {
158
177
  console.log(`๐Ÿ“„ Found ${markdownFiles.length} markdown files.`);
159
178
  }
160
-
161
- // Array to collect information about all processed pages for sitemap
162
- const processedPages = [];
163
179
 
164
- // Extract a flattened navigation array for prev/next links
165
- const flatNavigation = [];
180
+ // Process each Markdown file
181
+ const processedFiles = new Set(); // Track processed files to avoid double processing
166
182
 
167
- // Helper function to create a normalized path for navigation matching
168
- function createNormalizedPath(item) {
169
- if (!item.path) return null;
170
- return item.path.startsWith('/') ? item.path : '/' + item.path;
171
- }
172
-
173
- function extractNavigationItems(items, parentPath = '') {
174
- if (!items || !Array.isArray(items)) return;
175
-
176
- for (const item of items) {
177
- if (item.external) continue; // Skip external links
183
+ for (const filePath of markdownFiles) {
184
+ try {
185
+ const fileContent = await fs.readFile(filePath, 'utf8');
186
+ const { data: frontmatter, content } = matter(fileContent);
178
187
 
179
- // Only include items with paths (not section headers without links)
180
- if (item.path) {
181
- // Normalize path - ensure leading slash
182
- let normalizedPath = createNormalizedPath(item);
183
-
184
- // For parent items with children, ensure path ends with / (folders)
185
- // This helps with matching in the navigation template
186
- if (item.children && item.children.length > 0) {
187
- // If path from config doesn't end with slash, add it
188
- if (!item.path.endsWith('/') && !normalizedPath.endsWith('/')) {
189
- normalizedPath += '/';
190
- }
191
- }
192
-
193
- flatNavigation.push({
194
- title: item.title,
195
- path: normalizedPath,
196
- fullPath: item.path, // Original path as defined in config
197
- isParent: item.children && item.children.length > 0 // Mark if it's a parent with children
198
- });
188
+ // Skip this file if it's already been processed and noDoubleProcessing is true
189
+ const relativePath = path.relative(SRC_DIR, filePath);
190
+ if (options.noDoubleProcessing && processedFiles.has(relativePath)) {
191
+ continue;
199
192
  }
193
+ processedFiles.add(relativePath);
200
194
 
201
- // Process children (depth first to maintain document outline order)
202
- if (item.children && Array.isArray(item.children)) {
203
- extractNavigationItems(item.children, item.path || parentPath);
195
+ // Pretty URL handling - properly handle index.md files in subfolders
196
+ let outputHtmlPath;
197
+ const fileName = path.basename(relativePath);
198
+ const isIndexFile = fileName === 'index.md';
199
+
200
+ if (isIndexFile) {
201
+ // For any index.md file (in root or subfolder), convert to index.html in the same folder
202
+ const dirPath = path.dirname(relativePath);
203
+ outputHtmlPath = path.join(dirPath, 'index.html');
204
+ } else {
205
+ // For non-index files, create a folder with index.html
206
+ outputHtmlPath = relativePath.replace(/\.md$/, '/index.html');
204
207
  }
205
- }
206
- }
207
-
208
- // Extract navigation items into flat array
209
- extractNavigationItems(config.navigation);
210
208
 
211
- for (const mdFilePath of markdownFiles) {
212
- const relativeMdPath = path.relative(SRC_DIR, mdFilePath);
213
-
214
- // Pretty URL handling - properly handle index.md files in subfolders
215
- let outputHtmlPath;
216
- const fileName = path.basename(relativeMdPath);
217
- const isIndexFile = fileName === 'index.md';
218
-
219
- if (isIndexFile) {
220
- // For any index.md file (in root or subfolder), convert to index.html in the same folder
221
- const dirPath = path.dirname(relativeMdPath);
222
- outputHtmlPath = path.join(dirPath, 'index.html');
223
- } else {
224
- // For non-index files, create a folder with index.html
225
- outputHtmlPath = relativeMdPath.replace(/\.md$/, '/index.html');
226
- }
209
+ const finalOutputHtmlPath = path.join(OUTPUT_DIR, outputHtmlPath);
227
210
 
228
- const finalOutputHtmlPath = path.join(OUTPUT_DIR, outputHtmlPath);
211
+ const depth = outputHtmlPath.split(path.sep).length - 1;
212
+ const relativePathToRoot = depth > 0 ? '../'.repeat(depth) : './';
229
213
 
230
- const depth = outputHtmlPath.split(path.sep).length - 1;
231
- const relativePathToRoot = depth > 0 ? '../'.repeat(depth) : './';
214
+ const { frontmatter: pageFrontmatter, htmlContent, headings } = await processMarkdownFile(filePath, { isDev: options.isDev });
215
+
216
+ // Special handling for no-style pages
217
+ let finalHtmlContent = htmlContent;
218
+ if (pageFrontmatter.noStyle === true) {
219
+ // For no-style pages, ensure the HTML content is not escaped
220
+ // This is critical for the landing page and custom pages
221
+ finalHtmlContent = htmlContent;
222
+
223
+ // Log a message for debugging - but only for non-dev mode or verbose logging
224
+ if (!options.isDev) {
225
+ console.log(`๐Ÿ“„ Processing no-style page: ${path.relative(CWD, filePath)}`);
226
+ }
227
+ }
232
228
 
233
- const { frontmatter, htmlContent, headings } = await processMarkdownFile(mdFilePath);
234
-
235
- // Get the URL path for navigation
236
- let currentPagePathForNav;
237
- let normalizedPath;
238
-
239
- if (isIndexFile) {
240
- // For index.md files, the nav path should be the directory itself with trailing slash
241
- const dirPath = path.dirname(relativeMdPath);
242
- if (dirPath === '.') {
243
- // Root index.md
244
- currentPagePathForNav = 'index.html';
245
- normalizedPath = '/';
229
+ // Get the URL path for navigation
230
+ let currentPagePathForNav;
231
+ let normalizedPath;
232
+
233
+ if (isIndexFile) {
234
+ // For index.md files, the nav path should be the directory itself with trailing slash
235
+ const dirPath = path.dirname(relativePath);
236
+ if (dirPath === '.') {
237
+ // Root index.md
238
+ currentPagePathForNav = 'index.html';
239
+ normalizedPath = '/';
240
+ } else {
241
+ // Subfolder index.md - simple format: directory-name/
242
+ currentPagePathForNav = dirPath + '/';
243
+ normalizedPath = '/' + dirPath;
244
+ }
246
245
  } else {
247
- // Subfolder index.md - simple format: directory-name/
248
- currentPagePathForNav = dirPath + '/';
249
- normalizedPath = '/' + dirPath;
250
- }
251
- } else {
252
- // For non-index files, the path should be the file name with trailing slash
253
- const pathWithoutExt = relativeMdPath.replace(/\.md$/, '');
254
- currentPagePathForNav = pathWithoutExt + '/';
255
- normalizedPath = '/' + pathWithoutExt;
256
- }
257
-
258
- // Convert Windows backslashes to forward slashes for web paths
259
- currentPagePathForNav = currentPagePathForNav.replace(/\\/g, '/');
260
-
261
- // Log navigation paths for debugging
262
- // Uncomment this line when debugging:
263
- // logNavigationPaths(mdFilePath, currentPagePathForNav, normalizedPath);
264
-
265
- const navigationHtml = await generateNavigationHtml(
266
- config.navigation,
267
- currentPagePathForNav,
268
- relativePathToRoot,
269
- config
270
- );
271
-
272
- // Find current page in navigation for prev/next links
273
- let prevPage = null;
274
- let nextPage = null;
275
- let currentPageIndex = -1;
276
-
277
- // Find the current page in flatNavigation
278
- currentPageIndex = flatNavigation.findIndex(item => {
279
- // Direct path match
280
- if (item.path === normalizedPath) {
281
- return true;
246
+ // For non-index files, the path should be the file name with trailing slash
247
+ const pathWithoutExt = relativePath.replace(/\.md$/, '');
248
+ currentPagePathForNav = pathWithoutExt + '/';
249
+ normalizedPath = '/' + pathWithoutExt;
282
250
  }
283
251
 
284
- // Special handling for parent folders
285
- if (isIndexFile && item.path.endsWith('/')) {
286
- // Remove trailing slash for comparison
287
- const itemPathWithoutSlash = item.path.slice(0, -1);
288
- return itemPathWithoutSlash === normalizedPath;
252
+ // Convert Windows backslashes to forward slashes for web paths
253
+ currentPagePathForNav = currentPagePathForNav.replace(/\\/g, '/');
254
+
255
+ // Log navigation paths for debugging
256
+ // Uncomment this line when debugging:
257
+ // logNavigationPaths(filePath, currentPagePathForNav, normalizedPath);
258
+
259
+ const navigationHtml = await generateNavigationHtml(
260
+ config.navigation,
261
+ currentPagePathForNav,
262
+ relativePathToRoot,
263
+ config
264
+ );
265
+
266
+ // Find current page in navigation for prev/next links
267
+ let prevPage = null;
268
+ let nextPage = null;
269
+ let currentPageIndex = -1;
270
+
271
+ // Extract a flattened navigation array for prev/next links
272
+ const flatNavigation = [];
273
+
274
+ // Helper function to create a normalized path for navigation matching
275
+ function createNormalizedPath(item) {
276
+ if (!item.path) return null;
277
+ return item.path.startsWith('/') ? item.path : '/' + item.path;
289
278
  }
290
279
 
291
- return false;
292
- });
293
-
294
- if (currentPageIndex >= 0) {
295
- // Get previous and next pages if they exist
296
- if (currentPageIndex > 0) {
297
- prevPage = flatNavigation[currentPageIndex - 1];
280
+ function extractNavigationItems(items, parentPath = '') {
281
+ if (!items || !Array.isArray(items)) return;
282
+
283
+ for (const item of items) {
284
+ if (item.external) continue; // Skip external links
285
+
286
+ // Only include items with paths (not section headers without links)
287
+ if (item.path) {
288
+ // Normalize path - ensure leading slash
289
+ let normalizedPath = createNormalizedPath(item);
290
+
291
+ // For parent items with children, ensure path ends with / (folders)
292
+ // This helps with matching in the navigation template
293
+ if (item.children && item.children.length > 0) {
294
+ // If path from config doesn't end with slash, add it
295
+ if (!item.path.endsWith('/') && !normalizedPath.endsWith('/')) {
296
+ normalizedPath += '/';
297
+ }
298
+ }
299
+
300
+ flatNavigation.push({
301
+ title: item.title,
302
+ path: normalizedPath,
303
+ fullPath: item.path, // Original path as defined in config
304
+ isParent: item.children && item.children.length > 0 // Mark if it's a parent with children
305
+ });
306
+ }
307
+
308
+ // Process children (depth first to maintain document outline order)
309
+ if (item.children && Array.isArray(item.children)) {
310
+ extractNavigationItems(item.children, item.path || parentPath);
311
+ }
312
+ }
298
313
  }
299
314
 
300
- if (currentPageIndex < flatNavigation.length - 1) {
301
- nextPage = flatNavigation[currentPageIndex + 1];
315
+ // Extract navigation items into flat array
316
+ extractNavigationItems(config.navigation);
317
+
318
+ // Find the current page in flatNavigation
319
+ currentPageIndex = flatNavigation.findIndex(item => {
320
+ // Direct path match
321
+ if (item.path === normalizedPath) {
322
+ return true;
323
+ }
324
+
325
+ // Special handling for parent folders
326
+ if (isIndexFile && item.path.endsWith('/')) {
327
+ // Remove trailing slash for comparison
328
+ const itemPathWithoutSlash = item.path.slice(0, -1);
329
+ return itemPathWithoutSlash === normalizedPath;
330
+ }
331
+
332
+ return false;
333
+ });
334
+
335
+ if (currentPageIndex >= 0) {
336
+ // Get previous and next pages if they exist
337
+ if (currentPageIndex > 0) {
338
+ prevPage = flatNavigation[currentPageIndex - 1];
339
+ }
340
+
341
+ if (currentPageIndex < flatNavigation.length - 1) {
342
+ nextPage = flatNavigation[currentPageIndex + 1];
343
+ }
302
344
  }
303
- }
304
-
305
- // Convert page paths to proper URLs for links
306
- if (prevPage) {
307
- // Format the previous page URL, avoiding double slashes
308
- if (prevPage.path === '/') {
309
- prevPage.url = relativePathToRoot + 'index.html';
310
- } else {
311
- // Remove leading slash and ensure clean path
312
- const cleanPath = prevPage.path.substring(1).replace(/\/+$/, '');
313
- prevPage.url = relativePathToRoot + cleanPath + '/';
345
+
346
+ // Convert page paths to proper URLs for links
347
+ if (prevPage) {
348
+ // Format the previous page URL, avoiding double slashes
349
+ if (prevPage.path === '/') {
350
+ prevPage.url = relativePathToRoot + 'index.html';
351
+ } else {
352
+ // Remove leading slash and ensure clean path
353
+ const cleanPath = prevPage.path.substring(1).replace(/\/+$/, '');
354
+ prevPage.url = relativePathToRoot + cleanPath + '/';
355
+ }
314
356
  }
315
- }
316
-
317
- if (nextPage) {
318
- // Format the next page URL, avoiding double slashes
319
- if (nextPage.path === '/') {
320
- nextPage.url = relativePathToRoot + 'index.html';
321
- } else {
322
- // Remove leading slash and ensure clean path
323
- const cleanPath = nextPage.path.substring(1).replace(/\/+$/, '');
324
- nextPage.url = relativePathToRoot + cleanPath + '/';
357
+
358
+ if (nextPage) {
359
+ // Format the next page URL, avoiding double slashes
360
+ if (nextPage.path === '/') {
361
+ nextPage.url = relativePathToRoot + 'index.html';
362
+ } else {
363
+ // Remove leading slash and ensure clean path
364
+ const cleanPath = nextPage.path.substring(1).replace(/\/+$/, '');
365
+ nextPage.url = relativePathToRoot + cleanPath + '/';
366
+ }
325
367
  }
326
- }
327
368
 
328
- const pageDataForTemplate = {
329
- content: htmlContent,
330
- pageTitle: frontmatter.title || 'Untitled',
331
- siteTitle: config.siteTitle,
332
- navigationHtml,
333
- relativePathToRoot: relativePathToRoot,
334
- config: config, // Pass full config
335
- frontmatter: frontmatter,
336
- outputPath: outputHtmlPath, // Relative path from outputDir root
337
- prettyUrl: true, // Flag to indicate we're using pretty URLs
338
- prevPage: prevPage, // Previous page in navigation
339
- nextPage: nextPage, // Next page in navigation
340
- currentPagePath: normalizedPath, // Pass the normalized path for active state detection
341
- headings: headings || [], // Pass headings for TOC
342
- };
343
-
344
- const pageHtml = await generateHtmlPage(pageDataForTemplate);
345
-
346
- await fs.ensureDir(path.dirname(finalOutputHtmlPath));
347
- await fs.writeFile(finalOutputHtmlPath, pageHtml);
348
-
349
- // Add to processed pages for sitemap
350
- processedPages.push({
351
- outputPath: isIndexFile
352
- ? (path.dirname(relativeMdPath) === '.' ? 'index.html' : path.dirname(relativeMdPath) + '/')
353
- : outputHtmlPath.replace(/\\/g, '/').replace(/\/index\.html$/, '/'),
354
- frontmatter: frontmatter
355
- });
369
+ const pageDataForTemplate = {
370
+ content: finalHtmlContent,
371
+ pageTitle: pageFrontmatter.title || 'Untitled',
372
+ siteTitle: config.siteTitle,
373
+ navigationHtml,
374
+ relativePathToRoot: relativePathToRoot,
375
+ config: config, // Pass full config
376
+ frontmatter: pageFrontmatter,
377
+ outputPath: outputHtmlPath, // Relative path from outputDir root
378
+ prettyUrl: true, // Flag to indicate we're using pretty URLs
379
+ prevPage: prevPage, // Previous page in navigation
380
+ nextPage: nextPage, // Next page in navigation
381
+ currentPagePath: normalizedPath, // Pass the normalized path for active state detection
382
+ headings: headings || [], // Pass headings for TOC
383
+ };
384
+
385
+ const pageHtml = await generateHtmlPage(pageDataForTemplate);
386
+
387
+ await fs.ensureDir(path.dirname(finalOutputHtmlPath));
388
+ await fs.writeFile(finalOutputHtmlPath, pageHtml);
389
+
390
+ // Add to processed pages for sitemap
391
+ const processedPage = {
392
+ outputPath: isIndexFile
393
+ ? (path.dirname(relativePath) === '.' ? 'index.html' : path.dirname(relativePath) + '/')
394
+ : outputHtmlPath.replace(/\\/g, '/').replace(/\/index\.html$/, '/'),
395
+ frontmatter: pageFrontmatter
396
+ };
397
+ processedPages.push(processedPage);
398
+ } catch (error) {
399
+ console.error(`Error processing file ${path.relative(CWD, filePath)}:`, error);
400
+ }
356
401
  }
357
402
 
358
403
  // Generate sitemap if enabled in config
@@ -380,6 +425,12 @@ async function buildSite(configPath, options = { isDev: false, preserve: false }
380
425
  console.log(` - ... and ${userAssetsCopied.length - 5} more files`);
381
426
  }
382
427
  }
428
+
429
+ return {
430
+ config,
431
+ processedPages,
432
+ markdownFiles,
433
+ };
383
434
  }
384
435
 
385
436
  // Helper function to find HTML files and sitemap.xml to clean up
@@ -424,19 +475,4 @@ async function getAllFiles(dir) {
424
475
  return files;
425
476
  }
426
477
 
427
- // findMarkdownFiles function remains the same
428
- async function findMarkdownFiles(dir) {
429
- let files = [];
430
- const items = await fs.readdir(dir, { withFileTypes: true });
431
- for (const item of items) {
432
- const fullPath = path.join(dir, item.name);
433
- if (item.isDirectory()) {
434
- files = files.concat(await findMarkdownFiles(fullPath));
435
- } else if (item.isFile() && (item.name.endsWith('.md') || item.name.endsWith('.markdown'))) {
436
- files.push(fullPath);
437
- }
438
- }
439
- return files;
440
- }
441
-
442
478
  module.exports = { buildSite };