@mgks/docmd 0.3.6 → 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.
- package/LICENSE +1 -1
- package/README.md +86 -77
- package/bin/docmd.js +13 -16
- package/bin/postinstall.js +4 -4
- package/package.json +19 -16
- package/src/assets/css/docmd-highlight-dark.css +86 -1
- package/src/assets/css/docmd-highlight-light.css +86 -1
- package/src/assets/css/docmd-main.css +544 -464
- package/src/assets/css/docmd-theme-retro.css +105 -106
- package/src/assets/css/docmd-theme-ruby.css +92 -92
- package/src/assets/css/docmd-theme-sky.css +63 -64
- package/src/assets/favicon.ico +0 -0
- package/src/assets/images/docmd-logo-dark.png +0 -0
- package/src/assets/images/docmd-logo-light.png +0 -0
- package/src/assets/js/docmd-image-lightbox.js +2 -2
- package/src/assets/js/docmd-main.js +14 -6
- package/src/assets/js/docmd-mermaid.js +1 -1
- package/src/assets/js/docmd-search.js +1 -1
- package/src/commands/build.js +71 -370
- package/src/commands/dev.js +199 -72
- package/src/commands/init.js +135 -134
- package/src/commands/live.js +145 -0
- package/src/core/asset-manager.js +72 -0
- package/src/core/config-loader.js +2 -2
- package/src/core/config-validator.js +1 -1
- package/src/core/file-processor.js +13 -9
- package/src/core/fs-utils.js +40 -0
- package/src/core/html-formatter.js +97 -0
- package/src/core/html-generator.js +61 -65
- package/src/core/icon-renderer.js +1 -1
- package/src/core/logger.js +1 -1
- package/src/core/markdown/containers.js +1 -1
- package/src/core/markdown/renderers.js +1 -1
- package/src/core/markdown/rules.js +1 -2
- package/src/core/markdown/setup.js +1 -1
- package/src/core/navigation-helper.js +1 -1
- package/src/index.js +12 -0
- package/src/live/core.js +5 -1
- package/src/live/index.html +16 -1
- package/src/live/live.css +157 -68
- package/src/plugins/analytics.js +1 -1
- package/src/plugins/seo.js +26 -36
- package/src/plugins/sitemap.js +2 -2
- package/src/templates/layout.ejs +50 -81
- package/src/templates/navigation.ejs +23 -76
- package/src/templates/no-style.ejs +115 -129
- package/src/templates/partials/theme-init.js +1 -1
- package/src/templates/toc.ejs +6 -35
- package/docmd.config.js +0 -175
- package/scripts/build-live.js +0 -157
- package/scripts/test-live.js +0 -54
- package/src/assets/images/docmd-logo.png +0 -0
- package/src/live/templates.js +0 -9
package/src/commands/init.js
CHANGED
|
@@ -1,162 +1,165 @@
|
|
|
1
|
-
// Source file from the docmd project — https://github.com/
|
|
1
|
+
// Source file from the docmd project — https://github.com/docmd-io/docmd
|
|
2
2
|
|
|
3
|
-
const fs = require('fs-
|
|
3
|
+
const fs = require('../core/fs-utils');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const readline = require('readline');
|
|
6
|
+
const { version } = require('../../package.json');
|
|
6
7
|
|
|
7
|
-
const defaultConfigContent = `// docmd.config.js
|
|
8
|
+
const defaultConfigContent = `// docmd.config.js
|
|
8
9
|
module.exports = {
|
|
9
|
-
// Core
|
|
10
|
-
siteTitle: '
|
|
11
|
-
|
|
12
|
-
// No trailing slash
|
|
13
|
-
siteUrl: '', // Replace with your actual deployed URL
|
|
10
|
+
// --- Core Metadata ---
|
|
11
|
+
siteTitle: 'My Documentation',
|
|
12
|
+
siteUrl: '', // e.g. https://mysite.com (Critical for SEO/Sitemap)
|
|
14
13
|
|
|
15
|
-
//
|
|
14
|
+
// --- Branding ---
|
|
16
15
|
logo: {
|
|
17
|
-
light: 'assets/images/docmd-logo-
|
|
18
|
-
dark: 'assets/images/docmd-logo-
|
|
19
|
-
alt: '
|
|
20
|
-
href: './',
|
|
16
|
+
light: 'assets/images/docmd-logo-dark.png',
|
|
17
|
+
dark: 'assets/images/docmd-logo-light.png',
|
|
18
|
+
alt: 'Logo',
|
|
19
|
+
href: './',
|
|
21
20
|
},
|
|
21
|
+
favicon: 'assets/favicon.ico',
|
|
22
22
|
|
|
23
|
-
//
|
|
24
|
-
srcDir: 'docs',
|
|
25
|
-
outputDir: 'site',
|
|
26
|
-
|
|
27
|
-
// Search Configuration
|
|
28
|
-
search: true, // Enable/disable search functionality
|
|
29
|
-
|
|
30
|
-
// Build Options
|
|
31
|
-
minify: true, // Enable/disable HTML/CSS/JS minification
|
|
23
|
+
// --- Source & Output ---
|
|
24
|
+
srcDir: 'docs',
|
|
25
|
+
outputDir: 'site',
|
|
32
26
|
|
|
33
|
-
//
|
|
34
|
-
sidebar: {
|
|
35
|
-
collapsible: true, // or false to disable
|
|
36
|
-
defaultCollapsed: false, // or true to start collapsed
|
|
37
|
-
},
|
|
38
|
-
|
|
39
|
-
// Theme Configuration
|
|
27
|
+
// --- Theme & Layout ---
|
|
40
28
|
theme: {
|
|
41
|
-
name: 'sky', //
|
|
42
|
-
defaultMode: '
|
|
43
|
-
enableModeToggle: true, // Show
|
|
44
|
-
positionMode: 'top',
|
|
45
|
-
codeHighlight: true, // Enable
|
|
46
|
-
customCss: [
|
|
47
|
-
// 'assets/css/custom.css', // Custom TOC styles
|
|
48
|
-
]
|
|
29
|
+
name: 'sky', // Options: 'default', 'sky', 'ruby', 'retro'
|
|
30
|
+
defaultMode: 'system', // 'light', 'dark', or 'system'
|
|
31
|
+
enableModeToggle: true, // Show mode toggle button
|
|
32
|
+
positionMode: 'top', // 'top' or 'bottom'
|
|
33
|
+
codeHighlight: true, // Enable Highlight.js
|
|
34
|
+
customCss: [], // e.g. ['assets/css/custom.css']
|
|
49
35
|
},
|
|
50
36
|
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
37
|
+
// --- Features ---
|
|
38
|
+
search: true, // Built-in offline search
|
|
39
|
+
minify: true, // Minify HTML/CSS/JS in build
|
|
40
|
+
autoTitleFromH1: true, // Auto-generate page title from first H1
|
|
41
|
+
copyCode: true, // Show "copy" button on code blocks
|
|
42
|
+
pageNavigation: true, // Prev/Next buttons at bottom
|
|
56
43
|
|
|
57
|
-
//
|
|
58
|
-
|
|
59
|
-
|
|
44
|
+
// --- Navigation (Sidebar) ---
|
|
45
|
+
navigation: [
|
|
46
|
+
{ title: 'Introduction', path: '/', icon: 'home' },
|
|
47
|
+
{
|
|
48
|
+
title: 'Guide',
|
|
49
|
+
icon: 'book-open',
|
|
50
|
+
collapsible: true,
|
|
51
|
+
children: [
|
|
52
|
+
{ title: 'Getting Started', path: 'https://docs.docmd.io/getting-started/installation', icon: 'rocket', external: true },
|
|
53
|
+
{ title: 'Configuration', path: 'https://docs.docmd.io/configuration', icon: 'settings', external: true },
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
{ title: 'Live Editor', path: 'https://live.docmd.io', icon: 'pencil-ruler', external: true },
|
|
57
|
+
{ title: 'GitHub', path: 'https://github.com/docmd-io/docmd', icon: 'github', external: true },
|
|
58
|
+
],
|
|
60
59
|
|
|
61
|
-
// Plugins
|
|
62
|
-
// Plugins are configured here. docmd will look for these keys.
|
|
60
|
+
// --- Plugins ---
|
|
63
61
|
plugins: {
|
|
64
|
-
// SEO Plugin Configuration
|
|
65
|
-
// Most SEO data is pulled from page frontmatter (title, description, image, etc.)
|
|
66
|
-
// These are fallbacks or site-wide settings.
|
|
67
62
|
seo: {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
// siteName: 'docmd Documentation', // Optional, defaults to config.siteTitle
|
|
72
|
-
// Default image for og:image if not specified in page frontmatter
|
|
73
|
-
// Path relative to outputDir root
|
|
74
|
-
defaultImage: 'assets/images/docmd-preview.png',
|
|
63
|
+
defaultDescription: 'Documentation built with docmd.',
|
|
64
|
+
openGraph: {
|
|
65
|
+
defaultImage: '', // e.g. 'assets/images/og-image.png'
|
|
75
66
|
},
|
|
76
|
-
twitter: {
|
|
77
|
-
cardType: 'summary_large_image',
|
|
78
|
-
// siteUsername: '@docmd_handle', // Your site's Twitter handle (optional)
|
|
79
|
-
// creatorUsername: '@your_handle', // Default author handle (optional, can be overridden in frontmatter)
|
|
67
|
+
twitter: {
|
|
68
|
+
cardType: 'summary_large_image',
|
|
80
69
|
}
|
|
81
70
|
},
|
|
82
|
-
// Analytics Plugin Configuration
|
|
83
71
|
analytics: {
|
|
84
|
-
// Google Analytics 4 (GA4)
|
|
85
72
|
googleV4: {
|
|
86
|
-
measurementId: 'G-
|
|
73
|
+
measurementId: 'G-X9WTDL262N' // Replace with your Google Analytics Measurement ID
|
|
87
74
|
}
|
|
88
75
|
},
|
|
89
|
-
// Enable Sitemap plugin
|
|
90
76
|
sitemap: {
|
|
91
|
-
defaultChangefreq: 'weekly',
|
|
92
|
-
defaultPriority: 0.8
|
|
77
|
+
defaultChangefreq: 'weekly', // e.g. 'daily', 'weekly', 'monthly'
|
|
78
|
+
defaultPriority: 0.8 // Priority between 0.0 and 1.0
|
|
93
79
|
}
|
|
94
|
-
// Add other future plugin configurations here by their key
|
|
95
80
|
},
|
|
96
81
|
|
|
97
|
-
//
|
|
82
|
+
// --- Footer ---
|
|
83
|
+
footer: '© ' + new Date().getFullYear() + ' My Project. Built with [docmd](https://docmd.io).',
|
|
84
|
+
|
|
85
|
+
// --- Edit Link ---
|
|
98
86
|
editLink: {
|
|
99
87
|
enabled: false,
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
text: 'Edit this page on GitHub'
|
|
104
|
-
},
|
|
105
|
-
|
|
106
|
-
// Navigation Structure (Sidebar)
|
|
107
|
-
// Icons are kebab-case names from Lucide Icons (https://lucide.dev/)
|
|
108
|
-
navigation: [
|
|
109
|
-
{ title: 'Welcome', path: '/', icon: 'home' }, // Corresponds to docs/index.md
|
|
110
|
-
{
|
|
111
|
-
title: 'Getting Started',
|
|
112
|
-
icon: 'rocket',
|
|
113
|
-
path: '#',
|
|
114
|
-
collapsible: true, // This makes the menu section collapsible
|
|
115
|
-
children: [
|
|
116
|
-
{ title: 'Documentation', path: 'https://docmd.mgks.dev', icon: 'scroll', external: true },
|
|
117
|
-
{ title: 'Installation', path: 'https://docmd.mgks.dev/getting-started/installation', icon: 'download', external: true },
|
|
118
|
-
{ title: 'Basic Usage', path: 'https://docmd.mgks.dev/getting-started/basic-usage', icon: 'play', external: true },
|
|
119
|
-
{ title: 'Content', path: 'https://docmd.mgks.dev/content', icon: 'layout-template', external: true },
|
|
120
|
-
],
|
|
121
|
-
},
|
|
122
|
-
// External links:
|
|
123
|
-
{ title: 'GitHub', path: 'https://github.com/mgks/docmd', icon: 'github', external: true },
|
|
124
|
-
{ title: 'Support the Project', path: 'https://github.com/sponsors/mgks', icon: 'heart', external: true },
|
|
125
|
-
],
|
|
126
|
-
|
|
127
|
-
pageNavigation: true, // Enable previous / next page navigation at the bottom of each page
|
|
128
|
-
|
|
129
|
-
// Sponsor Ribbon Configuration
|
|
130
|
-
Sponsor: {
|
|
131
|
-
enabled: false,
|
|
132
|
-
title: 'Support docmd',
|
|
133
|
-
link: 'https://github.com/sponsors/mgks',
|
|
134
|
-
},
|
|
135
|
-
|
|
136
|
-
// Footer Configuration
|
|
137
|
-
// Markdown is supported here.
|
|
138
|
-
footer: '© ' + new Date().getFullYear() + ' Project.',
|
|
139
|
-
|
|
140
|
-
// Favicon Configuration
|
|
141
|
-
// Path relative to outputDir root
|
|
142
|
-
favicon: 'assets/favicon.ico',
|
|
88
|
+
baseUrl: 'https://github.com/USERNAME/REPO/edit/main/docs',
|
|
89
|
+
text: 'Edit this page'
|
|
90
|
+
}
|
|
143
91
|
};
|
|
144
92
|
`;
|
|
145
93
|
|
|
146
94
|
const defaultIndexMdContent = `---
|
|
147
95
|
title: "Welcome"
|
|
148
|
-
description: "
|
|
96
|
+
description: "Welcome to your new documentation site."
|
|
149
97
|
---
|
|
150
98
|
|
|
151
|
-
#
|
|
99
|
+
# Welcome to Your Docs
|
|
100
|
+
|
|
101
|
+
Congratulations! You have successfully initialized a new **docmd** project.
|
|
102
|
+
|
|
103
|
+
## 🚀 Quick Start
|
|
104
|
+
|
|
105
|
+
You are currently viewing the content of \`docs/index.md\`.
|
|
152
106
|
|
|
153
|
-
|
|
107
|
+
\`\`\`bash
|
|
108
|
+
npm start # Start the dev server
|
|
109
|
+
docmd build # Build for production
|
|
110
|
+
\`\`\`
|
|
111
|
+
|
|
112
|
+
## ✨ Features Demo
|
|
113
|
+
|
|
114
|
+
docmd comes with built-in components to make your documentation beautiful.
|
|
115
|
+
|
|
116
|
+
::: callout tip
|
|
117
|
+
**Try this:** Edit this file and save it. The browser will live reload instantly!
|
|
118
|
+
:::
|
|
119
|
+
|
|
120
|
+
### Container Examples
|
|
121
|
+
|
|
122
|
+
::: card Flexible Structure
|
|
123
|
+
**Organize your way.**
|
|
124
|
+
Create Markdown files in the \`docs/\` folder and map them in \`docmd.config.js\`.
|
|
125
|
+
:::
|
|
126
|
+
|
|
127
|
+
::: tabs
|
|
128
|
+
== tab "Simple"
|
|
129
|
+
This is a simple tab content.
|
|
130
|
+
|
|
131
|
+
== tab "Nested"
|
|
132
|
+
::: callout info
|
|
133
|
+
You can even nest other components inside tabs!
|
|
134
|
+
:::
|
|
135
|
+
:::
|
|
136
|
+
|
|
137
|
+
## 📚 Next Steps
|
|
138
|
+
|
|
139
|
+
* [Check the Official Documentation](https://docs.docmd.io)
|
|
140
|
+
* [Customize your Theme](https://docs.docmd.io/theming)
|
|
141
|
+
* [Deploy to GitHub Pages](https://docs.docmd.io/deployment)
|
|
154
142
|
`;
|
|
155
143
|
|
|
144
|
+
const defaultPackageJson = {
|
|
145
|
+
name: "my-docs",
|
|
146
|
+
version: "0.0.1",
|
|
147
|
+
private: true,
|
|
148
|
+
scripts: {
|
|
149
|
+
"dev": "docmd dev",
|
|
150
|
+
"build": "docmd build",
|
|
151
|
+
"preview": "npx serve site"
|
|
152
|
+
},
|
|
153
|
+
dependencies: {
|
|
154
|
+
"@mgks/docmd": `^${version}`
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
156
158
|
async function initProject() {
|
|
157
159
|
const baseDir = process.cwd();
|
|
158
|
-
const
|
|
160
|
+
const packageJsonFile = path.join(baseDir, 'package.json');
|
|
159
161
|
const configFile = path.join(baseDir, 'docmd.config.js');
|
|
162
|
+
const docsDir = path.join(baseDir, 'docs');
|
|
160
163
|
const indexMdFile = path.join(docsDir, 'index.md');
|
|
161
164
|
const assetsDir = path.join(baseDir, 'assets');
|
|
162
165
|
const assetsCssDir = path.join(assetsDir, 'css');
|
|
@@ -169,19 +172,28 @@ async function initProject() {
|
|
|
169
172
|
assets: false
|
|
170
173
|
};
|
|
171
174
|
|
|
175
|
+
// Check if package.json exists
|
|
176
|
+
if (!await fs.pathExists(packageJsonFile)) {
|
|
177
|
+
await fs.writeJson(packageJsonFile, defaultPackageJson, { spaces: 2 });
|
|
178
|
+
console.log('📦 Created `package.json` (Deployment Ready)');
|
|
179
|
+
} else {
|
|
180
|
+
console.log('⏭️ Skipped existing `package.json`');
|
|
181
|
+
}
|
|
182
|
+
|
|
172
183
|
// Check each file individually
|
|
173
184
|
if (await fs.pathExists(configFile)) {
|
|
174
185
|
existingFiles.push('docmd.config.js');
|
|
175
186
|
}
|
|
176
|
-
|
|
187
|
+
|
|
188
|
+
// Check for the legacy config.js
|
|
177
189
|
const oldConfigFile = path.join(baseDir, 'config.js');
|
|
178
190
|
if (await fs.pathExists(oldConfigFile)) {
|
|
179
191
|
existingFiles.push('config.js');
|
|
180
192
|
}
|
|
181
193
|
|
|
194
|
+
// Check if docs directory exists
|
|
182
195
|
if (await fs.pathExists(docsDir)) {
|
|
183
196
|
dirExists.docs = true;
|
|
184
|
-
|
|
185
197
|
if (await fs.pathExists(indexMdFile)) {
|
|
186
198
|
existingFiles.push('docs/index.md');
|
|
187
199
|
}
|
|
@@ -234,21 +246,9 @@ async function initProject() {
|
|
|
234
246
|
} else {
|
|
235
247
|
console.log('📁 Using existing `assets/` directory');
|
|
236
248
|
|
|
237
|
-
|
|
238
|
-
if (!await fs.pathExists(
|
|
239
|
-
|
|
240
|
-
console.log('📁 Created `assets/css/` directory');
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
if (!await fs.pathExists(assetsJsDir)) {
|
|
244
|
-
await fs.ensureDir(assetsJsDir);
|
|
245
|
-
console.log('📁 Created `assets/js/` directory');
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
if (!await fs.pathExists(assetsImagesDir)) {
|
|
249
|
-
await fs.ensureDir(assetsImagesDir);
|
|
250
|
-
console.log('📁 Created `assets/images/` directory');
|
|
251
|
-
}
|
|
249
|
+
if (!await fs.pathExists(assetsCssDir)) await fs.ensureDir(assetsCssDir);
|
|
250
|
+
if (!await fs.pathExists(assetsJsDir)) await fs.ensureDir(assetsJsDir);
|
|
251
|
+
if (!await fs.pathExists(assetsImagesDir)) await fs.ensureDir(assetsImagesDir);
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
// Write config file if it doesn't exist or user confirmed override
|
|
@@ -260,7 +260,7 @@ async function initProject() {
|
|
|
260
260
|
}
|
|
261
261
|
|
|
262
262
|
// Write index.md file if it doesn't exist or user confirmed override
|
|
263
|
-
if (!await fs.pathExists(indexMdFile)) {
|
|
263
|
+
if (!await fs.pathExists(indexMdFile) || shouldOverride) {
|
|
264
264
|
await fs.writeFile(indexMdFile, defaultIndexMdContent, 'utf8');
|
|
265
265
|
console.log('📄 Created `docs/index.md`');
|
|
266
266
|
} else if (shouldOverride) {
|
|
@@ -271,6 +271,7 @@ async function initProject() {
|
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
console.log('✅ Project initialization complete!');
|
|
274
|
+
console.log('👉 Run `npm install` to setup dependencies.');
|
|
274
275
|
}
|
|
275
276
|
|
|
276
277
|
module.exports = { initProject };
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// Source file from the docmd project — https://github.com/docmd-io/docmd
|
|
2
|
+
|
|
3
|
+
const fs = require('../core/fs-utils'); // Native wrapper
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const esbuild = require('esbuild');
|
|
6
|
+
const { processAssets } = require('../core/asset-manager');
|
|
7
|
+
|
|
8
|
+
async function build() {
|
|
9
|
+
console.log('📦 Building @docmd/live core...');
|
|
10
|
+
|
|
11
|
+
// Resolve paths relative to src/commands/live.js
|
|
12
|
+
const SRC_DIR = path.resolve(__dirname, '..'); // Points to /src
|
|
13
|
+
const LIVE_SRC_DIR = path.join(SRC_DIR, 'live');
|
|
14
|
+
const DIST_DIR = path.resolve(__dirname, '../../dist'); // Points to /dist in root
|
|
15
|
+
|
|
16
|
+
// 1. Clean/Create dist
|
|
17
|
+
if (await fs.exists(DIST_DIR)) {
|
|
18
|
+
await fs.remove(DIST_DIR);
|
|
19
|
+
}
|
|
20
|
+
await fs.ensureDir(DIST_DIR);
|
|
21
|
+
|
|
22
|
+
// 2. Generate Shim for Buffer (Browser compatibility)
|
|
23
|
+
const shimPath = path.join(LIVE_SRC_DIR, 'shims.js');
|
|
24
|
+
await fs.writeFile(shimPath, `import { Buffer } from 'buffer'; globalThis.Buffer = Buffer;`);
|
|
25
|
+
|
|
26
|
+
// 3. Define the Virtual Template Plugin
|
|
27
|
+
// This reads EJS files from disk and bundles them as a JSON object string
|
|
28
|
+
const templatePlugin = {
|
|
29
|
+
name: 'docmd-templates',
|
|
30
|
+
setup(build) {
|
|
31
|
+
build.onResolve({ filter: /^virtual:docmd-templates$/ }, args => ({
|
|
32
|
+
path: args.path,
|
|
33
|
+
namespace: 'docmd-templates-ns',
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
build.onLoad({ filter: /.*/, namespace: 'docmd-templates-ns' }, async () => {
|
|
37
|
+
const templatesDir = path.join(SRC_DIR, 'templates');
|
|
38
|
+
const files = await fs.readdir(templatesDir);
|
|
39
|
+
const templates = {};
|
|
40
|
+
|
|
41
|
+
for (const file of files) {
|
|
42
|
+
if (file.endsWith('.ejs')) {
|
|
43
|
+
const content = await fs.readFile(path.join(templatesDir, file), 'utf8');
|
|
44
|
+
templates[file] = content;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
contents: `module.exports = ${JSON.stringify(templates)};`,
|
|
50
|
+
loader: 'js',
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// 4. Define Node Modules Shim Plugin
|
|
57
|
+
// Stubs out fs/path requires so the browser bundle doesn't crash
|
|
58
|
+
const nodeShimPlugin = {
|
|
59
|
+
name: 'node-deps-shim',
|
|
60
|
+
setup(build) {
|
|
61
|
+
build.onResolve({ filter: /^(node:)?path$/ }, args => ({ path: args.path, namespace: 'path-shim' }));
|
|
62
|
+
build.onLoad({ filter: /.*/, namespace: 'path-shim' }, () => ({
|
|
63
|
+
contents: `
|
|
64
|
+
module.exports = {
|
|
65
|
+
join: (...args) => args.filter(Boolean).join('/'),
|
|
66
|
+
resolve: (...args) => '/' + args.filter(Boolean).join('/'),
|
|
67
|
+
basename: (p) => p ? p.split(/[\\\\/]/).pop() : '',
|
|
68
|
+
dirname: (p) => p ? p.split(/[\\\\/]/).slice(0, -1).join('/') || '.' : '.',
|
|
69
|
+
extname: (p) => { if (!p) return ''; const parts = p.split('.'); return parts.length > 1 ? '.' + parts.pop() : ''; },
|
|
70
|
+
isAbsolute: (p) => p.startsWith('/'),
|
|
71
|
+
normalize: (p) => p,
|
|
72
|
+
sep: '/'
|
|
73
|
+
};
|
|
74
|
+
`,
|
|
75
|
+
loader: 'js'
|
|
76
|
+
}));
|
|
77
|
+
|
|
78
|
+
build.onResolve({ filter: /^(node:)?fs(\/promises)?|fs-extra$/ }, args => ({ path: args.path, namespace: 'fs-shim' }));
|
|
79
|
+
build.onLoad({ filter: /.*/, namespace: 'fs-shim' }, () => ({
|
|
80
|
+
contents: `
|
|
81
|
+
module.exports = {
|
|
82
|
+
existsSync: () => false,
|
|
83
|
+
readFileSync: () => '',
|
|
84
|
+
statSync: () => ({ isFile: () => true, isDirectory: () => false }),
|
|
85
|
+
constants: { F_OK: 0, R_OK: 4 },
|
|
86
|
+
promises: {}
|
|
87
|
+
};
|
|
88
|
+
`,
|
|
89
|
+
loader: 'js'
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// 5. Bundle JS
|
|
95
|
+
console.log('⚡ Bundling & Compressing JS...');
|
|
96
|
+
try {
|
|
97
|
+
await esbuild.build({
|
|
98
|
+
entryPoints: [path.join(LIVE_SRC_DIR, 'core.js')],
|
|
99
|
+
bundle: true,
|
|
100
|
+
outfile: path.join(DIST_DIR, 'docmd-live.js'),
|
|
101
|
+
platform: 'browser',
|
|
102
|
+
format: 'iife',
|
|
103
|
+
globalName: 'docmd',
|
|
104
|
+
minify: true,
|
|
105
|
+
define: { 'process.env.NODE_ENV': '"production"' },
|
|
106
|
+
inject: [shimPath],
|
|
107
|
+
plugins: [templatePlugin, nodeShimPlugin]
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// 6. Copy & Minify Static Assets using Universal Manager
|
|
111
|
+
console.log('📂 Processing static assets...');
|
|
112
|
+
const assetsSrc = path.join(SRC_DIR, 'assets');
|
|
113
|
+
const assetsDest = path.join(DIST_DIR, 'assets');
|
|
114
|
+
|
|
115
|
+
if (await fs.exists(assetsSrc)) {
|
|
116
|
+
await processAssets(assetsSrc, assetsDest, { minify: true });
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// 7. Copy HTML Wrapper & Minify Live CSS
|
|
120
|
+
await fs.copy(path.join(LIVE_SRC_DIR, 'index.html'), path.join(DIST_DIR, 'index.html'));
|
|
121
|
+
|
|
122
|
+
const liveCss = await fs.readFile(path.join(LIVE_SRC_DIR, 'live.css'), 'utf8');
|
|
123
|
+
const minifiedLiveCss = await esbuild.transform(liveCss, { loader: 'css', minify: true });
|
|
124
|
+
await fs.writeFile(path.join(DIST_DIR, 'live.css'), minifiedLiveCss.code);
|
|
125
|
+
|
|
126
|
+
// 8. Copy Favicon to Root
|
|
127
|
+
const internalFavicon = path.join(assetsSrc, 'favicon.ico');
|
|
128
|
+
if (await fs.exists(internalFavicon)) {
|
|
129
|
+
await fs.copy(internalFavicon, path.join(DIST_DIR, 'favicon.ico'));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
console.log('✅ Live Editor build complete!');
|
|
133
|
+
|
|
134
|
+
} catch (e) {
|
|
135
|
+
console.error('❌ Build failed:', e);
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Allow direct execution (via scripts/failsafe.js)
|
|
141
|
+
if (require.main === module) {
|
|
142
|
+
build();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
module.exports = { build };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Source file from the docmd project — https://github.com/docmd-io/docmd
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('./fs-utils');
|
|
5
|
+
const esbuild = require('esbuild');
|
|
6
|
+
|
|
7
|
+
const DOCMD_HEADER = `/*! Source file from the docmd project — https://github.com/docmd-io/docmd */\n\n`;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Recursively copies assets from src to dest.
|
|
11
|
+
* Minifies CSS/JS files and adds docmd header.
|
|
12
|
+
*
|
|
13
|
+
* @param {string} srcDir - Source directory
|
|
14
|
+
* @param {string} destDir - Destination directory
|
|
15
|
+
* @param {object} options - { minify: boolean }
|
|
16
|
+
*/
|
|
17
|
+
async function processAssets(srcDir, destDir, options = { minify: true }) {
|
|
18
|
+
// Ensure source exists
|
|
19
|
+
if (!await fs.exists(srcDir)) return;
|
|
20
|
+
|
|
21
|
+
// Ensure dest exists
|
|
22
|
+
await fs.ensureDir(destDir);
|
|
23
|
+
|
|
24
|
+
const entries = await fs.readdir(srcDir, { withFileTypes: true });
|
|
25
|
+
|
|
26
|
+
for (const entry of entries) {
|
|
27
|
+
const srcPath = path.join(srcDir, entry.name);
|
|
28
|
+
const destPath = path.join(destDir, entry.name);
|
|
29
|
+
|
|
30
|
+
if (entry.isDirectory()) {
|
|
31
|
+
await processAssets(srcPath, destPath, options);
|
|
32
|
+
} else {
|
|
33
|
+
const ext = path.extname(entry.name).toLowerCase();
|
|
34
|
+
|
|
35
|
+
// Handle CSS & JS: Minify + docmd Header
|
|
36
|
+
if (ext === '.css' || ext === '.js') {
|
|
37
|
+
try {
|
|
38
|
+
const content = await fs.readFile(srcPath, 'utf8');
|
|
39
|
+
|
|
40
|
+
if (options.minify) {
|
|
41
|
+
// Minify using esbuild
|
|
42
|
+
const result = await esbuild.transform(content, {
|
|
43
|
+
loader: ext.slice(1), // 'css' or 'js'
|
|
44
|
+
minify: true,
|
|
45
|
+
banner: ext === '.css' || ext === '.js' ? DOCMD_HEADER : ''
|
|
46
|
+
});
|
|
47
|
+
await fs.writeFile(destPath, result.code);
|
|
48
|
+
} else {
|
|
49
|
+
// Just add banner if not minifying (Dev mode)
|
|
50
|
+
const contentWithBanner = `${DOCMD_HEADER}\n${content}`;
|
|
51
|
+
await fs.writeFile(destPath, contentWithBanner);
|
|
52
|
+
}
|
|
53
|
+
} catch (e) {
|
|
54
|
+
console.warn(`⚠️ Processing failed for ${entry.name}, copying original.`);
|
|
55
|
+
await fs.copy(srcPath, destPath);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Handle HTML Files (if any in assets): HTML Comment Header
|
|
59
|
+
else if (ext === '.html') {
|
|
60
|
+
const content = await fs.readFile(srcPath, 'utf8');
|
|
61
|
+
const htmlBanner = `<!-- Generated by docmd - https://docmd.io -->\n\n`;
|
|
62
|
+
await fs.writeFile(destPath, htmlBanner + content);
|
|
63
|
+
}
|
|
64
|
+
// Everything else (Images, Fonts): Direct Copy
|
|
65
|
+
else {
|
|
66
|
+
await fs.copy(srcPath, destPath);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
module.exports = { processAssets, DOCMD_HEADER };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// Source file from the docmd project — https://github.com/
|
|
1
|
+
// Source file from the docmd project — https://github.com/docmd-io/docmd
|
|
2
2
|
|
|
3
3
|
const path = require('path');
|
|
4
|
-
const fs = require('fs-
|
|
4
|
+
const fs = require('./fs-utils');
|
|
5
5
|
const { validateConfig } = require('./config-validator');
|
|
6
6
|
|
|
7
7
|
async function loadConfig(configPath) {
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
// Source file from the docmd project — https://github.com/
|
|
1
|
+
// Source file from the docmd project — https://github.com/docmd-io/docmd
|
|
2
2
|
|
|
3
|
-
const fs = require('fs-
|
|
3
|
+
const fs = require('./fs-utils');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const matter = require('gray-matter');
|
|
6
6
|
const { createMarkdownItInstance } = require('./markdown/setup');
|
|
7
|
-
const striptags = require('striptags');
|
|
8
7
|
|
|
9
8
|
function decodeHtmlEntities(html) {
|
|
10
9
|
return html.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, "'").replace(/ /g, ' ');
|
|
11
10
|
}
|
|
11
|
+
|
|
12
|
+
function stripHtmlTags(str) {
|
|
13
|
+
if (!str) return '';
|
|
14
|
+
return str.replace(/<[^>]*>?/gm, '');
|
|
15
|
+
}
|
|
12
16
|
|
|
13
17
|
function extractHeadingsFromHtml(htmlContent) {
|
|
14
18
|
const headings = [];
|
|
@@ -65,12 +69,12 @@ function processMarkdownContent(rawContent, md, config, filePath = 'memory') {
|
|
|
65
69
|
|
|
66
70
|
let searchData = null;
|
|
67
71
|
if (!frontmatter.noindex) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
const rawText = decodeHtmlEntities(stripHtmlTags(htmlContent));
|
|
73
|
+
searchData = {
|
|
74
|
+
title: frontmatter.title || 'Untitled',
|
|
75
|
+
content: rawText.slice(0, 5000), // Safety cap to prevent massive JSON
|
|
76
|
+
headings: headings.map(h => h.text)
|
|
77
|
+
};
|
|
74
78
|
}
|
|
75
79
|
|
|
76
80
|
return { frontmatter, htmlContent, headings, searchData };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Source file from the docmd project — https://github.com/docmd-io/docmd
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs/promises');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
|
|
6
|
+
async function ensureDir(dirPath) {
|
|
7
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async function remove(dirPath) {
|
|
11
|
+
await fs.rm(dirPath, { recursive: true, force: true });
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async function copy(src, dest) {
|
|
15
|
+
await fs.cp(src, dest, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function exists(filePath) {
|
|
19
|
+
try {
|
|
20
|
+
await fs.access(filePath);
|
|
21
|
+
return true;
|
|
22
|
+
} catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function writeJson(file, object, options = {}) {
|
|
28
|
+
const content = JSON.stringify(object, null, options.spaces || 2);
|
|
29
|
+
await fs.writeFile(file, content, 'utf8');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = {
|
|
33
|
+
...fs,
|
|
34
|
+
ensureDir,
|
|
35
|
+
remove,
|
|
36
|
+
copy,
|
|
37
|
+
pathExists: exists,
|
|
38
|
+
exists,
|
|
39
|
+
writeJson
|
|
40
|
+
};
|