@docmd/core 0.4.0

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.
@@ -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
+ };
@@ -0,0 +1,21 @@
1
+ // Source file from the docmd project — https://github.com/docmd-io/docmd
2
+
3
+ const chalk = require('chalk');
4
+
5
+ const { version } = require('../../package.json');
6
+
7
+ const printBanner = () => {
8
+ const logo = `
9
+
10
+ ${chalk.blue(' _ _ ')}
11
+ ${chalk.blue(' _| |___ ___ _____ _| |')}
12
+ ${chalk.blue(' | . | . | _| | . |')}
13
+ ${chalk.blue(' |___|___|___|_|_|_|___|')}
14
+ `;
15
+
16
+ console.log(logo);
17
+ console.log(` ${chalk.dim(`v${version}`)}`);
18
+ console.log(`\n`);
19
+ };
20
+
21
+ module.exports = { printBanner };
@@ -0,0 +1,90 @@
1
+ const chalk = require('chalk');
2
+
3
+ const hooks = {
4
+ markdownSetup: [],
5
+ injectHead: [],
6
+ injectBody: [],
7
+ onPostBuild: [],
8
+ assets: [],
9
+ getClientAssets: [] // Legacy support
10
+ };
11
+
12
+ // Map short names to package names
13
+ const ALIASES = {
14
+ 'search': '@docmd/plugin-search',
15
+ 'seo': '@docmd/plugin-seo',
16
+ 'sitemap': '@docmd/plugin-sitemap',
17
+ 'analytics': '@docmd/plugin-analytics',
18
+ 'mermaid': '@docmd/plugin-mermaid'
19
+ };
20
+
21
+ function loadPlugins(config) {
22
+ // 1. Reset hooks
23
+ Object.keys(hooks).forEach(key => hooks[key] = []);
24
+
25
+ // 2. Initialize Plugin Map (Name -> Options)
26
+ // This ensures unique plugins (last write wins)
27
+ const pluginMap = new Map();
28
+
29
+ // A. Add Defaults
30
+ pluginMap.set('@docmd/plugin-search', config.search !== false ? {} : false);
31
+ pluginMap.set('@docmd/plugin-seo', config.plugins?.seo || {});
32
+ pluginMap.set('@docmd/plugin-sitemap', config.plugins?.sitemap || {});
33
+ pluginMap.set('@docmd/plugin-analytics', config.plugins?.analytics || {});
34
+
35
+ // B. Add/Override from Config
36
+ if (config.plugins) {
37
+ Object.keys(config.plugins).forEach(key => {
38
+ // Resolve Alias (e.g., 'mermaid' -> '@docmd/plugin-mermaid')
39
+ const resolvedName = ALIASES[key] || key;
40
+ const options = config.plugins[key];
41
+
42
+ // Update map (Override default if exists)
43
+ pluginMap.set(resolvedName, options);
44
+ });
45
+ }
46
+
47
+ // 3. Load and Register
48
+ for (const [name, options] of pluginMap) {
49
+ if (options === false) continue; // Skip disabled
50
+
51
+ try {
52
+ // Try resolving standard package
53
+ let pluginModule;
54
+ try {
55
+ pluginModule = require(name);
56
+ } catch (e) {
57
+ // Fallback for local development or misnamed packages
58
+ console.warn(chalk.dim(` > Debug: Could not require '${name}', checking alternatives...`));
59
+ throw e;
60
+ }
61
+
62
+ registerPlugin(name, pluginModule, options);
63
+ } catch (e) {
64
+ console.warn(chalk.yellow(`⚠️ Could not load plugin: ${name}`));
65
+ // Only log full error in verbose/debug mode to reduce noise
66
+ // console.error(e.message);
67
+ }
68
+ }
69
+
70
+ return hooks;
71
+ }
72
+
73
+ function registerPlugin(name, plugin, options) {
74
+ if (typeof plugin.markdownSetup === 'function') hooks.markdownSetup.push((md) => plugin.markdownSetup(md, options));
75
+
76
+ if (typeof plugin.generateMetaTags === 'function') {
77
+ hooks.injectHead.push((config, page, root) => plugin.generateMetaTags(config, page, root));
78
+ }
79
+
80
+ if (typeof plugin.generateScripts === 'function') {
81
+ hooks.injectHead.push((c) => plugin.generateScripts(c, options).headScriptsHtml || '');
82
+ hooks.injectBody.push((c) => plugin.generateScripts(c, options).bodyScriptsHtml || '');
83
+ }
84
+
85
+ if (typeof plugin.onPostBuild === 'function') hooks.onPostBuild.push((ctx) => plugin.onPostBuild({ ...ctx, options }));
86
+
87
+ if (typeof plugin.getAssets === 'function') hooks.assets.push(() => plugin.getAssets(options));
88
+ }
89
+
90
+ module.exports = { loadPlugins, hooks };
@@ -0,0 +1,31 @@
1
+ const { onPostBuild: searchPostBuild, getClientAssets: getSearchAssets } = require('@docmd/plugin-search');
2
+ const { onPostBuild: sitemapPostBuild } = require('@docmd/plugin-sitemap');
3
+ // We will implement SEO/Analytics later, but they are typically "hooks" inside the HTML generation
4
+ // or post-build actions.
5
+
6
+ // Map of standard plugins that run post-build
7
+ const POST_BUILD_PLUGINS = [
8
+ { name: 'search', fn: searchPostBuild },
9
+ { name: 'sitemap', fn: sitemapPostBuild }
10
+ ];
11
+
12
+ async function runPostBuildHooks(context) {
13
+ for (const plugin of POST_BUILD_PLUGINS) {
14
+ try {
15
+ if (plugin.fn) {
16
+ await plugin.fn(context);
17
+ }
18
+ } catch (e) {
19
+ console.error(`❌ Plugin '${plugin.name}' failed:`, e.message);
20
+ }
21
+ }
22
+ }
23
+
24
+ function getPluginAssets() {
25
+ // Aggregate assets from plugins that have client-side scripts (like Search)
26
+ return [
27
+ { src: getSearchAssets(), dest: 'plugins/search' }
28
+ ];
29
+ }
30
+
31
+ module.exports = { runPostBuildHooks, getPluginAssets };