@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.
- package/.github/workflows/deploy-docmd.yml +2 -2
- package/README.md +3 -1
- package/assets/css/welcome.css +378 -0
- package/assets/images/preview-dark-1.png +0 -0
- package/assets/images/preview-dark-2.png +0 -0
- package/assets/images/preview-dark-3.png +0 -0
- package/assets/images/preview-light-1.png +0 -0
- package/assets/images/preview-light-2.png +0 -0
- package/assets/images/preview-light-3.png +0 -0
- package/config.js +8 -3
- package/docs/cli-commands.md +1 -2
- package/docs/configuration.md +34 -22
- package/docs/content/frontmatter.md +2 -2
- package/docs/content/index.md +5 -4
- package/docs/content/markdown-syntax.md +4 -4
- package/docs/content/no-style-example.md +110 -0
- package/docs/content/no-style-pages.md +202 -0
- package/docs/contributing.md +7 -0
- package/docs/deployment.md +22 -31
- package/docs/getting-started/basic-usage.md +3 -2
- package/docs/getting-started/index.md +3 -3
- package/docs/getting-started/installation.md +1 -1
- package/docs/index.md +137 -53
- package/docs/overview.md +56 -0
- package/docs/plugins/sitemap.md +1 -1
- package/docs/theming/assets-management.md +1 -1
- package/docs/theming/available-themes.md +29 -51
- package/package.json +1 -1
- package/src/assets/css/docmd-main.css +2 -1
- package/src/assets/css/docmd-theme-ruby.css +606 -0
- package/src/commands/build.js +239 -203
- package/src/commands/dev.js +75 -30
- package/src/commands/init.js +2 -0
- package/src/core/file-processor.js +67 -5
- package/src/core/html-generator.js +16 -3
- package/src/plugins/sitemap.js +15 -1
- package/src/templates/layout.ejs +1 -1
- package/src/templates/no-style.ejs +159 -0
package/src/commands/build.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
//
|
|
165
|
-
const
|
|
180
|
+
// Process each Markdown file
|
|
181
|
+
const processedFiles = new Set(); // Track processed files to avoid double processing
|
|
166
182
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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
|
-
//
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
-
//
|
|
202
|
-
|
|
203
|
-
|
|
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
|
-
|
|
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
|
-
|
|
211
|
+
const depth = outputHtmlPath.split(path.sep).length - 1;
|
|
212
|
+
const relativePathToRoot = depth > 0 ? '../'.repeat(depth) : './';
|
|
229
213
|
|
|
230
|
-
|
|
231
|
-
|
|
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
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
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
|
-
//
|
|
248
|
-
|
|
249
|
-
|
|
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
|
-
//
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
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
|
-
|
|
301
|
-
|
|
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
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
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
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
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
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
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 };
|