@mgks/docmd 0.3.7 → 0.3.8

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 (73) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +61 -63
  3. package/bin/docmd.js +13 -16
  4. package/bin/postinstall.js +4 -4
  5. package/package.json +12 -10
  6. package/src/assets/css/docmd-highlight-dark.css +86 -1
  7. package/src/assets/css/docmd-highlight-light.css +86 -1
  8. package/src/assets/css/docmd-main.css +544 -464
  9. package/src/assets/css/docmd-theme-retro.css +105 -106
  10. package/src/assets/css/docmd-theme-ruby.css +92 -92
  11. package/src/assets/css/docmd-theme-sky.css +63 -64
  12. package/src/assets/favicon.ico +0 -0
  13. package/src/assets/images/docmd-logo-dark.png +0 -0
  14. package/src/assets/images/docmd-logo-light.png +0 -0
  15. package/src/assets/js/docmd-image-lightbox.js +2 -2
  16. package/src/assets/js/docmd-main.js +1 -1
  17. package/src/assets/js/docmd-mermaid.js +1 -1
  18. package/src/assets/js/docmd-search.js +1 -1
  19. package/src/commands/build.js +71 -370
  20. package/src/commands/dev.js +141 -80
  21. package/src/commands/init.js +107 -132
  22. package/src/commands/live.js +145 -0
  23. package/src/core/asset-manager.js +72 -0
  24. package/src/core/config-loader.js +2 -2
  25. package/src/core/config-validator.js +1 -1
  26. package/src/core/file-processor.js +13 -9
  27. package/src/core/fs-utils.js +40 -0
  28. package/src/core/html-formatter.js +97 -0
  29. package/src/core/html-generator.js +61 -65
  30. package/src/core/icon-renderer.js +1 -1
  31. package/src/core/logger.js +1 -1
  32. package/src/core/markdown/containers.js +1 -1
  33. package/src/core/markdown/renderers.js +1 -1
  34. package/src/core/markdown/rules.js +1 -2
  35. package/src/core/markdown/setup.js +1 -1
  36. package/src/core/navigation-helper.js +1 -1
  37. package/src/index.js +12 -0
  38. package/src/live/core.js +5 -1
  39. package/src/live/index.html +16 -1
  40. package/src/live/live.css +157 -68
  41. package/src/plugins/analytics.js +1 -1
  42. package/src/plugins/seo.js +26 -36
  43. package/src/plugins/sitemap.js +2 -2
  44. package/src/templates/layout.ejs +50 -81
  45. package/src/templates/navigation.ejs +23 -76
  46. package/src/templates/no-style.ejs +115 -129
  47. package/src/templates/partials/theme-init.js +1 -1
  48. package/src/templates/toc.ejs +6 -35
  49. package/dist/assets/css/docmd-highlight-dark.css +0 -1
  50. package/dist/assets/css/docmd-highlight-light.css +0 -1
  51. package/dist/assets/css/docmd-main.css +0 -1627
  52. package/dist/assets/css/docmd-theme-retro.css +0 -868
  53. package/dist/assets/css/docmd-theme-ruby.css +0 -629
  54. package/dist/assets/css/docmd-theme-sky.css +0 -618
  55. package/dist/assets/favicon.ico +0 -0
  56. package/dist/assets/images/docmd-logo-dark.png +0 -0
  57. package/dist/assets/images/docmd-logo-light.png +0 -0
  58. package/dist/assets/images/docmd-logo.png +0 -0
  59. package/dist/assets/js/docmd-image-lightbox.js +0 -74
  60. package/dist/assets/js/docmd-main.js +0 -222
  61. package/dist/assets/js/docmd-mermaid.js +0 -205
  62. package/dist/assets/js/docmd-search.js +0 -218
  63. package/dist/assets/js/mermaid.min.js +0 -2811
  64. package/dist/assets/js/minisearch.js +0 -2013
  65. package/dist/docmd-live.js +0 -30748
  66. package/dist/index.html +0 -201
  67. package/dist/live.css +0 -167
  68. package/docmd.config.js +0 -175
  69. package/scripts/build-live.js +0 -157
  70. package/scripts/failsafe.js +0 -37
  71. package/scripts/test-live.js +0 -54
  72. package/src/assets/images/docmd-logo.png +0 -0
  73. package/src/live/templates.js +0 -9
@@ -1,4 +1,4 @@
1
- // Source file from the docmd project — https://github.com/mgks/docmd
1
+ // Source file from the docmd project — https://github.com/docmd-io/docmd
2
2
 
3
3
  const chalk = require('chalk');
4
4
 
@@ -1,4 +1,4 @@
1
- // Source file from the docmd project — https://github.com/mgks/docmd
1
+ // Source file from the docmd project — https://github.com/docmd-io/docmd
2
2
 
3
3
  const containers = {
4
4
  card: {
@@ -1,4 +1,4 @@
1
- // Source file from the docmd project — https://github.com/mgks/docmd
1
+ // Source file from the docmd project — https://github.com/docmd-io/docmd
2
2
 
3
3
  const customOrderedListOpenRenderer = function(tokens, idx, options, env, self) {
4
4
  const token = tokens[idx];
@@ -1,4 +1,4 @@
1
- // Source file from the docmd project — https://github.com/mgks/docmd
1
+ // Source file from the docmd project — https://github.com/docmd-io/docmd
2
2
 
3
3
  const MarkdownIt = require('markdown-it'); // Required for inner rendering fallback logic
4
4
  const { containers } = require('./containers');
@@ -160,7 +160,6 @@ function changelogTimelineRule(state, startLine, endLine, silent) {
160
160
  <div class="changelog-meta"><span class="changelog-date">${entry.meta}</span></div>
161
161
  <div class="changelog-body">`;
162
162
 
163
- // --- FIX: Use parent parser to render inner content ---
164
163
  // This ensures callouts/cards inside changelogs are parsed
165
164
  entryOpen.content += state.md.render(entry.content, state.env);
166
165
 
@@ -1,4 +1,4 @@
1
- // Source file from the docmd project — https://github.com/mgks/docmd
1
+ // Source file from the docmd project — https://github.com/docmd-io/docmd
2
2
 
3
3
  const MarkdownIt = require('markdown-it');
4
4
  const hljs = require('highlight.js');
@@ -1,4 +1,4 @@
1
- // Source file from the docmd project — https://github.com/mgks/docmd
1
+ // Source file from the docmd project — https://github.com/docmd-io/docmd
2
2
 
3
3
  /**
4
4
  * Flattens the navigation tree and finds the previous and next pages relative to the current page.
package/src/index.js ADDED
@@ -0,0 +1,12 @@
1
+ // Source file from the docmd project — https://github.com/docmd-io/docmd
2
+
3
+ // Core build function (Node.js environment)
4
+ const { buildSite } = require('./commands/build');
5
+
6
+ // Live Editor bundler
7
+ const { build: buildLive } = require('./commands/live');
8
+
9
+ module.exports = {
10
+ build: buildSite,
11
+ buildLive
12
+ };
package/src/live/core.js CHANGED
@@ -1,6 +1,10 @@
1
+ // Source file from the docmd project — https://github.com/docmd-io/docmd
2
+
1
3
  const { processMarkdownContent, createMarkdownItInstance } = require('../core/file-processor');
2
4
  const { renderHtmlPage } = require('../core/html-generator');
3
- const templates = require('./templates');
5
+
6
+ // Virtual import of templates for the live editor bundler
7
+ const templates = require('virtual:docmd-templates');
4
8
 
5
9
  function compile(markdown, config = {}, options = {}) {
6
10
  // Default config values for the browser
@@ -1,11 +1,26 @@
1
+ <!-- Source file from the docmd project — https://github.com/docmd-io/docmd -->
2
+
1
3
  <!DOCTYPE html>
2
4
  <html lang="en">
3
5
  <head>
4
6
  <meta charset="UTF-8">
5
7
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Docmd Live</title>
8
+ <title>Docmd Live Editor</title>
9
+ <meta name="description" content="Real-time Markdown preview and editor powered by docmd.">
10
+
11
+ <link rel="icon" href="favicon.ico" type="image/x-icon" sizes="any">
12
+ <link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
13
+
7
14
  <link rel="stylesheet" href="live.css">
8
15
  <script src="docmd-live.js"></script>
16
+
17
+ <script async src="https://www.googletagmanager.com/gtag/js?id=G-VCMQ0MCSHN"></script>
18
+ <script>
19
+ window.dataLayer = window.dataLayer || [];
20
+ function gtag(){dataLayer.push(arguments);}
21
+ gtag('js', new Date());
22
+ gtag('config', 'G-VCMQ0MCSHN');
23
+ </script>
9
24
  </head>
10
25
  <body class="mode-split mobile-tab-editor">
11
26
 
package/src/live/live.css CHANGED
@@ -1,9 +1,11 @@
1
+ /* Source file from the docmd project — https://github.com/docmd-io/docmd */
2
+
1
3
  :root {
2
4
  --header-height: 50px;
3
5
  --border-color: #e0e0e0;
4
6
  --bg-color: #f9fafb;
5
7
  --primary-color: #007bff;
6
- --resizer-width: 8px;
8
+ --resizer-width: 8px
7
9
  }
8
10
 
9
11
  body {
@@ -12,10 +14,9 @@ body {
12
14
  display: flex;
13
15
  flex-direction: column;
14
16
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
15
- overflow: hidden;
17
+ overflow: hidden
16
18
  }
17
19
 
18
- /* --- Top Bar --- */
19
20
  .top-bar {
20
21
  height: var(--header-height);
21
22
  background: #fff;
@@ -24,24 +25,24 @@ body {
24
25
  align-items: center;
25
26
  justify-content: space-between;
26
27
  padding: 0 1rem;
27
- flex-shrink: 0;
28
+ flex-shrink: 0
28
29
  }
29
30
 
30
- .logo {
31
- font-weight: 700;
32
- font-size: 1.1rem;
33
- display: flex;
34
- align-items: center;
35
- gap: 12px;
31
+ .logo {
32
+ font-weight: 700;
33
+ font-size: 1.1rem;
34
+ display: flex;
35
+ align-items: center;
36
+ gap: 12px
36
37
  }
37
38
 
38
- .logo span {
39
- background: var(--primary-color);
40
- color: white;
41
- padding: 2px 6px;
42
- border-radius: 4px;
43
- font-size: 0.75rem;
44
- text-transform: uppercase;
39
+ .logo span {
40
+ background: var(--primary-color);
41
+ color: #fff;
42
+ padding: 2px 6px;
43
+ border-radius: 4px;
44
+ font-size: .75rem;
45
+ text-transform: uppercase
45
46
  }
46
47
 
47
48
  .back-link {
@@ -49,51 +50,73 @@ body {
49
50
  align-items: center;
50
51
  justify-content: center;
51
52
  color: #666;
52
- transition: color 0.2s, transform 0.2s;
53
+ transition: color 0.2s, transform .2s;
53
54
  text-decoration: none;
54
55
  padding: 4px;
55
- border-radius: 4px;
56
+ border-radius: 4px
56
57
  }
57
58
 
58
59
  .back-link:hover {
59
60
  color: var(--primary-color);
60
61
  background: #f0f0f0;
61
- transform: translateX(-2px);
62
+ transform: translateX(-2px)
62
63
  }
63
64
 
64
- .view-controls { display: flex; gap: 8px; background: #f0f0f0; padding: 3px; border-radius: 6px; }
65
- .view-btn { border: none; background: transparent; padding: 6px 10px; border-radius: 4px; cursor: pointer; font-size: 0.85rem; color: #666; font-weight: 500; }
66
- .view-btn.active { background: white; color: black; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
65
+ .view-controls {
66
+ display: flex;
67
+ gap: 8px;
68
+ background: #f0f0f0;
69
+ padding: 3px;
70
+ border-radius: 6px
71
+ }
72
+
73
+ .view-btn {
74
+ border: none;
75
+ background: transparent;
76
+ padding: 6px 10px;
77
+ border-radius: 4px;
78
+ cursor: pointer;
79
+ font-size: .85rem;
80
+ color: #666;
81
+ font-weight: 500
82
+ }
83
+
84
+ .view-btn.active {
85
+ background: #fff;
86
+ color: #000;
87
+ box-shadow: 0 1px 3px #0000001a
88
+ }
67
89
 
68
- /* --- Main Layout --- */
69
90
  .workspace {
70
91
  flex: 1;
71
92
  display: flex;
72
93
  position: relative;
73
- overflow: hidden;
94
+ overflow: hidden
74
95
  }
75
96
 
76
97
  .pane {
77
98
  height: 100%;
78
99
  display: flex;
79
100
  flex-direction: column;
80
- min-width: 300px; /* Minimum width constraint */
81
- background: white;
101
+ min-width: 300px;
102
+ background: #fff
82
103
  }
83
104
 
84
105
  .pane-header {
85
106
  padding: 8px 16px;
86
- font-size: 0.75rem;
107
+ font-size: .75rem;
87
108
  font-weight: 600;
88
109
  text-transform: uppercase;
89
110
  color: #888;
90
111
  background: var(--bg-color);
91
112
  border-bottom: 1px solid var(--border-color);
92
- flex-shrink: 0;
113
+ flex-shrink: 0
114
+ }
115
+
116
+ .editor-pane {
117
+ width: 50%
93
118
  }
94
119
 
95
- /* Editor Pane */
96
- .editor-pane { width: 50%; }
97
120
  textarea#input {
98
121
  flex: 1;
99
122
  border: none;
@@ -103,14 +126,21 @@ textarea#input {
103
126
  font-size: 14px;
104
127
  line-height: 1.6;
105
128
  outline: none;
106
- background: var(--bg-color);
129
+ background: var(--bg-color)
107
130
  }
108
131
 
109
- /* Preview Pane */
110
- .preview-pane { flex: 1; background: white; }
111
- iframe#preview { width: 100%; height: 100%; border: none; display: block; }
132
+ .preview-pane {
133
+ flex: 1;
134
+ background: #fff
135
+ }
136
+
137
+ iframe#preview {
138
+ width: 100%;
139
+ height: 100%;
140
+ border: none;
141
+ display: block
142
+ }
112
143
 
113
- /* --- Resizer Handle --- */
114
144
  .resizer {
115
145
  width: var(--resizer-width);
116
146
  background: var(--bg-color);
@@ -120,48 +150,107 @@ iframe#preview { width: 100%; height: 100%; border: none; display: block; }
120
150
  display: flex;
121
151
  align-items: center;
122
152
  justify-content: center;
123
- transition: background 0.2s;
124
- z-index: 10;
153
+ transition: background .2s;
154
+ z-index: 10
125
155
  }
126
- .resizer:hover, .resizer.resizing { background: #e0e0e0; }
127
- .resizer::after { content: "||"; color: #aaa; font-size: 10px; letter-spacing: 1px; }
128
156
 
129
- /* --- View Modes (Single vs Split) --- */
157
+ .resizer:hover,
158
+ .resizer.resizing {
159
+ background: #e0e0e0
160
+ }
130
161
 
131
- /* Single Mode (Mobile style on Desktop) */
132
- body.mode-single .resizer { display: none; }
133
- body.mode-single .pane { width: 100% !important; min-width: 0; }
134
- body.mode-single .editor-pane { display: none; }
135
- body.mode-single .preview-pane { display: none; }
136
- body.mode-single.show-editor .editor-pane { display: flex; }
137
- body.mode-single.show-preview .preview-pane { display: flex; }
162
+ .resizer::after {
163
+ content: "||";
164
+ color: #aaa;
165
+ font-size: 10px;
166
+ letter-spacing: 1px
167
+ }
168
+
169
+ body.mode-single .resizer {
170
+ display: none
171
+ }
172
+
173
+ body.mode-single .pane {
174
+ width: 100% !important;
175
+ min-width: 0
176
+ }
177
+
178
+ body.mode-single .editor-pane {
179
+ display: none
180
+ }
181
+
182
+ body.mode-single .preview-pane {
183
+ display: none
184
+ }
185
+
186
+ body.mode-single.show-editor .editor-pane {
187
+ display: flex
188
+ }
189
+
190
+ body.mode-single.show-preview .preview-pane {
191
+ display: flex
192
+ }
138
193
 
139
- /* --- Mobile Responsive Overrides --- */
140
194
  @media (max-width: 768px) {
141
- /* Force single mode on mobile, hide desktop view controls */
142
- .desktop-only { display: none !important; }
143
- .resizer { display: none !important; }
144
-
145
- .pane { width: 100% !important; }
146
- .editor-pane { display: none; }
147
- .preview-pane { display: none; }
148
-
149
- body.mobile-tab-editor .editor-pane { display: flex; }
150
- body.mobile-tab-preview .preview-pane { display: flex; }
151
-
195
+ .desktop-only {
196
+ display: none !important
197
+ }
198
+
199
+ .resizer {
200
+ display: none !important
201
+ }
202
+
203
+ .pane {
204
+ width: 100% !important
205
+ }
206
+
207
+ .editor-pane {
208
+ display: none
209
+ }
210
+
211
+ .preview-pane {
212
+ display: none
213
+ }
214
+
215
+ body.mobile-tab-editor .editor-pane {
216
+ display: flex
217
+ }
218
+
219
+ body.mobile-tab-preview .preview-pane {
220
+ display: flex
221
+ }
222
+
152
223
  .mobile-tabs {
153
224
  display: flex !important;
154
225
  position: fixed;
155
- bottom: 0; left: 0; right: 0;
226
+ bottom: 0;
227
+ left: 0;
228
+ right: 0;
156
229
  height: 50px;
157
- background: white;
230
+ background: #fff;
158
231
  border-top: 1px solid var(--border-color);
159
- z-index: 100;
232
+ z-index: 100
233
+ }
234
+
235
+ .mobile-tab-btn {
236
+ flex: 1;
237
+ border: none;
238
+ background: transparent;
239
+ font-weight: 600;
240
+ color: #888;
241
+ cursor: pointer
242
+ }
243
+
244
+ .mobile-tab-btn.active {
245
+ color: var(--primary-color);
246
+ border-top: 2px solid var(--primary-color)
247
+ }
248
+
249
+ .workspace {
250
+ padding-bottom: 50px
160
251
  }
161
- .mobile-tab-btn { flex: 1; border: none; background: transparent; font-weight: 600; color: #888; cursor: pointer; }
162
- .mobile-tab-btn.active { color: var(--primary-color); border-top: 2px solid var(--primary-color); }
163
-
164
- .workspace { padding-bottom: 50px; } /* Space for tabs */
165
252
  }
166
253
 
167
- .mobile-tabs { display: none; } /* Hidden on desktop */
254
+ .mobile-tabs {
255
+ display: none
256
+ }
@@ -1,4 +1,4 @@
1
- // Source file from the docmd project — https://github.com/mgks/docmd
1
+ // Source file from the docmd project — https://github.com/docmd-io/docmd
2
2
 
3
3
  /*
4
4
  * Generate analytics scripts for a page
@@ -1,4 +1,4 @@
1
- // Source file from the docmd project — https://github.com/mgks/docmd
1
+ // Source file from the docmd project — https://github.com/docmd-io/docmd
2
2
 
3
3
  /*
4
4
  * Generate SEO meta tags for a page
@@ -7,11 +7,11 @@
7
7
  function generateSeoMetaTags(config, pageData, relativePathToRoot) {
8
8
  let metaTagsHtml = '';
9
9
  const { frontmatter, outputPath } = pageData;
10
- const seoFrontmatter = frontmatter.seo || {}; // Use nested seo object, fallback to empty
10
+ const seoFrontmatter = frontmatter.seo || {};
11
11
 
12
12
  if (frontmatter.noindex || seoFrontmatter.noindex) {
13
- metaTagsHtml += ' <meta name="robots" content="noindex">\n';
14
- return metaTagsHtml; // No other SEO tags if noindex
13
+ metaTagsHtml += '<meta name="robots" content="noindex">\n';
14
+ return metaTagsHtml;
15
15
  }
16
16
 
17
17
  const siteTitle = config.siteTitle;
@@ -22,46 +22,46 @@ function generateSeoMetaTags(config, pageData, relativePathToRoot) {
22
22
  const pageSegment = outputPath.replace(/index\.html$/, '').replace(/\.html$/, '');
23
23
  const pageUrl = `${siteUrl}${pageSegment.startsWith('/') ? pageSegment : '/' + pageSegment}`;
24
24
 
25
- metaTagsHtml += ` <meta name="description" content="${description}">\n`;
25
+ metaTagsHtml += `<meta name="description" content="${description}">\n`;
26
26
 
27
27
  const canonicalUrl = seoFrontmatter.permalink || frontmatter.permalink || seoFrontmatter.canonicalUrl || frontmatter.canonicalUrl || pageUrl;
28
- metaTagsHtml += ` <link rel="canonical" href="${canonicalUrl}">\n`;
28
+ metaTagsHtml += `<link rel="canonical" href="${canonicalUrl}">\n`;
29
29
 
30
30
  // Open Graph
31
- metaTagsHtml += ` <meta property="og:title" content="${pageTitle} : ${siteTitle}">\n`;
32
- metaTagsHtml += ` <meta property="og:description" content="${description}">\n`;
33
- metaTagsHtml += ` <meta property="og:url" content="${pageUrl}">\n`;
34
- metaTagsHtml += ` <meta property="og:site_name" content="${config.plugins?.seo?.openGraph?.siteName || siteTitle}">\n`;
31
+ metaTagsHtml += `<meta property="og:title" content="${pageTitle} : ${siteTitle}">\n`;
32
+ metaTagsHtml += `<meta property="og:description" content="${description}">\n`;
33
+ metaTagsHtml += `<meta property="og:url" content="${pageUrl}">\n`;
34
+ metaTagsHtml += `<meta property="og:site_name" content="${config.plugins?.seo?.openGraph?.siteName || siteTitle}">\n`;
35
35
 
36
36
  const ogImage = seoFrontmatter.image || frontmatter.image || seoFrontmatter.ogImage || frontmatter.ogImage || config.plugins?.seo?.openGraph?.defaultImage;
37
37
  if (ogImage) {
38
38
  const ogImageUrl = ogImage.startsWith('http') ? ogImage : `${siteUrl}${ogImage.startsWith('/') ? ogImage : '/' + ogImage}`;
39
- metaTagsHtml += ` <meta property="og:image" content="${ogImageUrl}">\n`;
39
+ metaTagsHtml += `<meta property="og:image" content="${ogImageUrl}">\n`;
40
40
  }
41
- metaTagsHtml += ` <meta property="og:type" content="${seoFrontmatter.ogType || frontmatter.ogType || 'website'}">\n`;
41
+ metaTagsHtml += `<meta property="og:type" content="${seoFrontmatter.ogType || frontmatter.ogType || 'website'}">\n`;
42
42
 
43
43
  // Twitter Card
44
44
  const twitterCardType = seoFrontmatter.twitterCard || frontmatter.twitterCard || config.plugins?.seo?.twitter?.cardType || 'summary';
45
- metaTagsHtml += ` <meta name="twitter:card" content="${twitterCardType}">\n`;
45
+ metaTagsHtml += `<meta name="twitter:card" content="${twitterCardType}">\n`;
46
46
  if (config.plugins?.seo?.twitter?.siteUsername) {
47
- metaTagsHtml += ` <meta name="twitter:site" content="${config.plugins.seo.twitter.siteUsername}">\n`;
47
+ metaTagsHtml += `<meta name="twitter:site" content="${config.plugins.seo.twitter.siteUsername}">\n`;
48
48
  }
49
49
  const twitterCreator = seoFrontmatter.twitterCreator || frontmatter.twitterCreator || config.plugins?.seo?.twitter?.creatorUsername;
50
50
  if (twitterCreator) {
51
- metaTagsHtml += ` <meta name="twitter:creator" content="${twitterCreator}">\n`;
51
+ metaTagsHtml += `<meta name="twitter:creator" content="${twitterCreator}">\n`;
52
52
  }
53
- metaTagsHtml += ` <meta name="twitter:title" content="${pageTitle} : ${siteTitle}">\n`;
54
- metaTagsHtml += ` <meta name="twitter:description" content="${description}">\n`;
53
+ metaTagsHtml += `<meta name="twitter:title" content="${pageTitle} : ${siteTitle}">\n`;
54
+ metaTagsHtml += `<meta name="twitter:description" content="${description}">\n`;
55
55
  if (ogImage) {
56
56
  const twitterImageUrl = ogImage.startsWith('http') ? ogImage : `${siteUrl}${ogImage.startsWith('/') ? ogImage : '/' + ogImage}`;
57
- metaTagsHtml += ` <meta name="twitter:image" content="${twitterImageUrl}">\n`;
57
+ metaTagsHtml += `<meta name="twitter:image" content="${twitterImageUrl}">\n`;
58
58
  }
59
59
 
60
60
  // Keywords
61
61
  const keywords = seoFrontmatter.keywords || frontmatter.keywords;
62
62
  if (keywords) {
63
63
  const keywordsString = Array.isArray(keywords) ? keywords.join(', ') : keywords;
64
- metaTagsHtml += ` <meta name="keywords" content="${keywordsString}">\n`;
64
+ metaTagsHtml += `<meta name="keywords" content="${keywordsString}">\n`;
65
65
  }
66
66
 
67
67
  // LD+JSON Structured Data
@@ -71,20 +71,14 @@ function generateSeoMetaTags(config, pageData, relativePathToRoot) {
71
71
  const baseLdJson = {
72
72
  '@context': 'https://schema.org',
73
73
  '@type': 'Article',
74
- mainEntityOfPage: {
75
- '@type': 'WebPage',
76
- '@id': canonicalUrl,
77
- },
74
+ mainEntityOfPage: { '@type': 'WebPage', '@id': canonicalUrl },
78
75
  headline: pageTitle,
79
76
  description: description,
80
77
  url: canonicalUrl,
81
78
  };
82
79
 
83
80
  if (config.siteTitle) {
84
- baseLdJson.publisher = {
85
- '@type': 'Organization',
86
- name: config.siteTitle,
87
- };
81
+ baseLdJson.publisher = { '@type': 'Organization', name: config.siteTitle };
88
82
  if (config.logo?.light) {
89
83
  baseLdJson.publisher.logo = {
90
84
  '@type': 'ImageObject',
@@ -97,17 +91,13 @@ function generateSeoMetaTags(config, pageData, relativePathToRoot) {
97
91
  baseLdJson.image = `${siteUrl}${ogImage.startsWith('/') ? ogImage : '/' + ogImage}`;
98
92
  }
99
93
 
100
- const finalLdJson = typeof ldJsonConfig === 'object'
101
- ? { ...baseLdJson, ...ldJsonConfig }
102
- : baseLdJson;
94
+ const finalLdJson = typeof ldJsonConfig === 'object' ? { ...baseLdJson, ...ldJsonConfig } : baseLdJson;
103
95
 
104
- metaTagsHtml += ` <script type="application/ld+json">\n`;
105
- metaTagsHtml += ` ${JSON.stringify(finalLdJson, null, 2)}\n`;
106
- metaTagsHtml += ` </script>\n`;
96
+ metaTagsHtml += `<script type="application/ld+json">\n`;
97
+ metaTagsHtml += `${JSON.stringify(finalLdJson, null, 2)}\n`;
98
+ metaTagsHtml += `</script>\n`;
107
99
  } catch (e) {
108
- console.error(`❌ Error generating LD+JSON for page: ${outputPath}`);
109
- console.error(` Could not stringify the ldJson object. Please check its structure in the frontmatter.`);
110
- console.error(` ${e.message}`);
100
+ console.error(`❌ Error generating LD+JSON: ${e.message}`);
111
101
  }
112
102
  }
113
103
 
@@ -1,10 +1,10 @@
1
- // Source file from the docmd project — https://github.com/mgks/docmd
1
+ // Source file from the docmd project — https://github.com/docmd-io/docmd
2
2
 
3
3
  /*
4
4
  * Generate sitemap.xml in the output directory root
5
5
  */
6
6
 
7
- const fs = require('fs-extra');
7
+ const fs = require('../core/fs-utils');
8
8
  const path = require('path');
9
9
 
10
10
  // Function to format paths for display (relative to CWD)