visualifyjs 2.5.3-2.dev → 3.0.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.
- package/.claude/mem/TIMELINE.md +36 -0
- package/.claude/mem/notes/2026-02-11-3d-visualization-docs-fix-external-script-solution.md +24 -0
- package/.claude/mem/notes/2026-02-11-3d-visualization-docs-fix-session-summary.md +43 -0
- package/.claude/mem/notes/2026-02-11-cli-fix-editor-command-alias.md +26 -0
- package/.claude/mem/notes/2026-02-11-phase-3-developer-experience-completed.md +51 -0
- package/.claude/mem/notes/2026-02-11-phase-4-web-workers-implementation-complete.md +59 -0
- package/.claude/mem/notes/2026-02-11-visualify-phase-2-3d-visualization-complete.md +50 -0
- package/.claude/mem/notes/2026-02-11-visualify-phase-2-committed-ready-for-phase-3.md +33 -0
- package/.claude/mem/notes/2026-02-11-visualify-phase-3-complete-developer-experience.md +52 -0
- package/.claude/mem/notes/2026-02-11-visualify-repository-cleanup-complete.md +28 -0
- package/.claude/mem/notes/2026-02-18-codebase-cleanup-docsify-plugin-documentation.md +37 -0
- package/.claude/mem/notes/2026-02-19-css-grid-layout-fix-displaycontents-on-vcontroller.md +18 -0
- package/.claude/mem/notes/2026-02-19-docsify-plugin-fixes-latex-and-visualify-code-bloc.md +26 -0
- package/.claude/mem/notes/2026-02-19-page-mode-docs-update-decisions.md +23 -0
- package/.claude/mem/notes/2026-02-19-react-context-infinite-re-render-loop-fix-pattern.md +31 -0
- package/.claude/mem/notes/2026-02-19-version-300-bump-and-build-fixes.md +32 -0
- package/.claude/mem/notes/2026-02-19-visualify-build-deployment-architecture-bug-fixes.md +25 -0
- package/.claude/mem/notes/2026-02-19-visualify-dist-iife-self-contained-build-config.md +30 -0
- package/.claude/mem/notes/2026-02-19-visualify-infinite-loop-i18n-fixes.md +31 -0
- package/.claude/mem/notes/2026-02-19-visualify-v3-bundle-splitting-docs-restructuring.md +32 -0
- package/.claude/mem/notes/2026-02-20-bundle-externalization-final-architecture.md +29 -0
- package/.claude/mem/notes/2026-02-20-chromium-page-fix-unstable-keys-and-double-event-b.md +27 -0
- package/.claude/mem/notes/2026-02-20-console-cleanup-bundle-optimization-commit.md +20 -0
- package/.claude/mem/notes/2026-02-20-dotbio-dot-plot-fix-useeffect-dependency.md +21 -0
- package/.claude/mem/notes/2026-02-20-public-folder-cleanup-and-readme-rewrite.md +25 -0
- package/.claude/mem/notes/2026-02-20-v300-release-and-beta-channel-strategy.md +29 -0
- package/.claude/mem/notes/2026-02-20-visium-background-image-unknown-legend-fix.md +19 -0
- package/.claude/mem/notes/2026-02-20-visualify-cdn-loader-bundle-externalization.md +34 -0
- package/.claude/mem/sessions/session-2026-02-20-031524.md +54 -0
- package/.claude/settings.local.json +21 -0
- package/.github/workflows/static.yml.bak +51 -51
- package/.sisyphus/boulder.json +65 -0
- package/.sisyphus/plans/phase-4-advanced-optimizations.md +217 -0
- package/LICENSE +674 -674
- package/README.md +94 -59
- package/config-overrides.js +31 -31
- package/dist/stats.html +4949 -0
- package/dist/visualify-3d.esm.js +1 -0
- package/dist/visualify-3d.js +1 -0
- package/dist/visualify-core.esm.js +1 -0
- package/dist/visualify-core.js +1 -0
- package/dist/visualify-docs.esm.js +1 -0
- package/dist/visualify-docs.js +1 -0
- package/dist/visualify-loader.js +1 -0
- package/dist/visualify-pages.esm.js +1 -0
- package/dist/visualify-pages.js +1 -0
- package/dist/visualify-portal.esm.js +1 -0
- package/dist/visualify-portal.js +1 -0
- package/dist/visualify-shared.js +26571 -0
- package/dist/visualify.js +1 -188
- package/docs/CHANGELOG.md +148 -0
- package/docs/cli/commands.md +513 -0
- package/docs/configuration/visualify-json.md +474 -0
- package/docs/docs/3d-visualization.md +374 -0
- package/docs/docs/CLI.md +303 -34
- package/docs/docs/README.md +65 -65
- package/docs/docs/Rechart/bar.md +190 -190
- package/docs/docs/Rechart/funnel.md +241 -241
- package/docs/docs/Rechart/line.md +355 -355
- package/docs/docs/Rechart/pie.md +225 -225
- package/docs/docs/Rechart/radar.md +253 -253
- package/docs/docs/Rechart/scatter.md +298 -298
- package/docs/docs/_404.md +51 -51
- package/docs/docs/_coverpage.md +11 -11
- package/docs/docs/_sidebar.md +54 -44
- package/docs/docs/components/dotBio.md +87 -34
- package/docs/docs/components/echart.md +171 -82
- package/docs/docs/components/html.md +61 -34
- package/docs/docs/components/macaron.md +156 -145
- package/docs/docs/components/markdown.md +42 -0
- package/docs/docs/components/more.md +183 -142
- package/docs/docs/components/plotly.md +132 -62
- package/docs/docs/components/scatterL.md +171 -70
- package/docs/docs/components/visium.md +112 -57
- package/docs/docs/configuration.md +121 -121
- package/docs/docs/deploy.md +31 -31
- package/docs/docs/docsify-plugin.md +655 -0
- package/docs/docs/hmr.md +165 -0
- package/docs/docs/i18n.md +332 -0
- package/docs/docs/log.md +30 -9
- package/docs/docs/more-pages.md +23 -23
- package/docs/docs/quickstart.md +148 -124
- package/docs/docs/rechart-attributes.md +74 -74
- package/docs/docs/rechart-basic-usage.md +160 -162
- package/docs/docs/theme.md +5 -5
- package/docs/docs/typescript.md +306 -0
- package/docs/docs/visual-editor.md +359 -0
- package/docs/index.html +85 -71
- package/docs/manifest.json +23 -23
- package/docs/migration/v3-migration.md +392 -0
- package/docs/static/css/fluff-stuff.css +169 -169
- package/docs/static/css/font-awesome.min.css +4 -4
- package/docs/static/css/visualify.css +6 -25
- package/docs/static/js/3d-viz-examples.js +181 -0
- package/docs/static/js/configuration.js +630 -448
- package/docs/static/js/visualify.js +1 -188
- package/package.json +106 -84
- package/rollup.config.mjs +766 -76
- package/src/_css/404.css +115 -115
- package/src/_css/App.css +37 -37
- package/src/_css/autoSuggestion.css +26 -26
- package/src/_css/circular-progress.css +32 -32
- package/src/_css/index.css +36 -36
- package/src/_css/modern.css +350 -25
- package/src/_media/corner.svg +8 -8
- package/src/_media/download.svg +3 -3
- package/src/_media/logo.svg +14 -14
- package/src/_test/App.test.js +15 -15
- package/src/_utils/reportWebVitals.js +13 -13
- package/src/a11y/README.md +177 -0
- package/src/a11y/aria-labels.js +339 -0
- package/src/a11y/color-contrast.js +535 -0
- package/src/a11y/index.js +197 -0
- package/src/a11y/keyboard-nav.js +523 -0
- package/src/a11y/styles.css +165 -0
- package/src/cli/commands/dev.js +214 -0
- package/src/cli/commands/docs.js +521 -0
- package/src/cli/commands/edit.js +379 -0
- package/src/cli/commands/init.js +213 -0
- package/src/cli/commands/portal.js +236 -0
- package/src/cli/dev-server.js +530 -0
- package/src/cli/hmr.js +456 -0
- package/src/cli/index.js +180 -0
- package/src/cli/utils/config.js +207 -0
- package/src/cli/utils/logger.js +241 -0
- package/src/config/defaults.ts +122 -0
- package/src/config/index.ts +72 -0
- package/src/config/loader.ts +478 -0
- package/src/config/schema.ts +227 -0
- package/src/config/validator.ts +337 -0
- package/src/core/appContext.js +34 -27
- package/src/core/components/Bar.js +383 -0
- package/src/core/components/Bar3D.js +473 -0
- package/src/core/components/LargeDatasetChart.js +296 -0
- package/src/core/components/Line3D.js +310 -0
- package/src/core/components/Scatter.js +392 -188
- package/src/core/components/Scatter3D.js +455 -0
- package/src/core/components/ScatterBio.js +601 -572
- package/src/core/components/Surface3D.js +326 -0
- package/src/core/components/ThreeCustom.js +648 -0
- package/src/core/components/ThreeScene.js +459 -0
- package/src/core/components/VisiumPlot.js +191 -165
- package/src/core/components/browser.js +42 -42
- package/src/core/components/dotplot.js +413 -413
- package/src/core/components/html.js +29 -29
- package/src/core/components/list.js +178 -178
- package/src/core/components/macaron.js +206 -201
- package/src/core/components/markdown.js +56 -56
- package/src/core/components/parser.scatterBio.js +582 -587
- package/src/core/components/ratio.js +82 -80
- package/src/core/components/scatterL.js +206 -173
- package/src/core/components/searchbar.js +156 -131
- package/src/core/components/selection.js +310 -193
- package/src/core/components/timeline.js +236 -281
- package/src/core/components/visium.js +114 -97
- package/src/core/data-processor.js +413 -0
- package/src/core/fetch/condfetch.js +82 -82
- package/src/core/fetch/fetch.js +92 -92
- package/src/core/fetch/json.js +29 -29
- package/src/core/fetch/vfetch.js +42 -42
- package/src/core/hmr-client.js +724 -0
- package/src/core/liveEditor.js +44 -44
- package/src/core/modules/codeEditorWithPreview.js +104 -104
- package/src/core/modules/echarts/common.js +20 -20
- package/src/core/modules/echarts/gl.js +228 -0
- package/src/core/modules/echarts/presetHandler.js +41 -41
- package/src/core/modules/echarts/presets/esodev.chromium.js +172 -172
- package/src/core/modules/echarts/presets/esodev.codex.js +130 -130
- package/src/core/modules/echarts/presets/esodev.visium.js +123 -123
- package/src/core/modules/echarts/presets/mmtrbc.js +186 -186
- package/src/core/modules/echarts.js +70 -71
- package/src/core/modules/echartsUtils.js +43 -43
- package/src/core/modules/echartswitcher.js +227 -152
- package/src/core/modules/replotly/presetHandler.js +24 -24
- package/src/core/modules/replotly/presets/minimum.js +18 -18
- package/src/core/modules/replotly/presets/mmtrbc.dot.js +114 -114
- package/src/core/modules/replotly/presets/mmtrbc.violin.js +100 -100
- package/src/core/modules/replotly.js +74 -71
- package/src/core/modules/threejs/Camera.js +373 -0
- package/src/core/modules/threejs/Lighting.js +459 -0
- package/src/core/modules/threejs/Renderer.js +364 -0
- package/src/core/modules/threejs/Scene.js +266 -0
- package/src/core/modules/threejs/index.js +155 -0
- package/src/core/pages/404.js +50 -50
- package/src/core/pages/error.js +27 -27
- package/src/core/pages/jsonPage.js +62 -62
- package/src/core/pages/loading.js +44 -44
- package/src/core/parser/echart.data.js +204 -183
- package/src/core/parser/echart.features.js +125 -125
- package/src/core/parser/echart.general.js +147 -147
- package/src/core/parser/echart.hilbert.js +57 -57
- package/src/core/parser/echart.parser.js +210 -210
- package/src/core/parser/echart.series.js +67 -67
- package/src/core/parser/echart.types.js +76 -76
- package/src/core/parser/plotly.config.js +10 -10
- package/src/core/parser/plotly.data.js +132 -132
- package/src/core/parser/plotly.layout.js +9 -9
- package/src/core/parser/plotly.violin.js +18 -18
- package/src/core/recharts.js +361 -62
- package/src/core/router/alias.js +49 -49
- package/src/core/router/jsonRouter.js +31 -31
- package/src/core/themes/modern.js +32 -32
- package/src/core/themes/themeSelector.js +33 -33
- package/src/core/visualify.js +213 -47
- package/src/core/widgets/circularProgress.js +23 -23
- package/src/core/widgets/controller.js +116 -83
- package/src/core/widgets/errorBoundary.js +36 -36
- package/src/core/widgets/footer.js +185 -177
- package/src/core/widgets/header.js +238 -234
- package/src/core/widgets/layout/Grid.js +31 -31
- package/src/core/widgets/layout.js +36 -36
- package/src/core/widgets/mapping.js +56 -42
- package/src/core/workers/data-worker.js +349 -0
- package/src/core/workers/worker-pool.js +396 -0
- package/src/docsify/bundle.js +215 -0
- package/src/docsify/markdown.js +271 -0
- package/src/docsify/plugin.js +268 -0
- package/src/editor/README.md +172 -0
- package/src/editor/components/ChartBuilder.jsx +341 -0
- package/src/editor/components/ChartTypeSidebar.jsx +91 -0
- package/src/editor/components/Editor.jsx +367 -0
- package/src/editor/components/Preview.jsx +446 -0
- package/src/editor/components/PropertyPanel.jsx +468 -0
- package/src/editor/components/StatusBar.jsx +85 -0
- package/src/editor/context/EditorContext.js +248 -0
- package/src/editor/hooks/useDebounce.js +32 -0
- package/src/editor/index.js +315 -0
- package/src/editor/styles/editor.css +637 -0
- package/src/editor/utils/chartValidator.js +263 -0
- package/src/entries/charts3d.js +70 -0
- package/src/entries/core.js +78 -0
- package/src/entries/docs.js +154 -0
- package/src/entries/pages.js +93 -0
- package/src/entries/portal.js +204 -0
- package/src/entries/shared.js +50 -0
- package/src/i18n/formatters.js +455 -0
- package/src/i18n/index.js +169 -0
- package/src/i18n/locales/ar.json +137 -0
- package/src/i18n/locales/de.json +137 -0
- package/src/i18n/locales/en.json +137 -0
- package/src/i18n/locales/es.json +137 -0
- package/src/i18n/locales/he.json +137 -0
- package/src/i18n/locales/zh.json +137 -0
- package/src/i18n/rtl.css +183 -0
- package/src/index.js +82 -62
- package/src/loader.js +103 -0
- package/src/setupTests.js +5 -5
- package/tsconfig.json +51 -0
- package/types/charts.d.ts +569 -0
- package/types/components.d.ts +441 -0
- package/types/config.d.ts +199 -0
- package/types/index.d.ts +353 -0
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Documentation commands for Visualify CLI
|
|
3
|
+
* @module cli/commands/docs
|
|
4
|
+
*
|
|
5
|
+
* Implements `visualify docs dev` and `visualify docs build` commands
|
|
6
|
+
* with full Docsify integration and Visualify plugin support.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { Command } = require('commander');
|
|
10
|
+
const fs = require('fs').promises;
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const { spawn, exec } = require('child_process');
|
|
13
|
+
const logger = require('../utils/logger');
|
|
14
|
+
const { loadConfig, fileExists } = require('../utils/config');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Valid documentation actions
|
|
18
|
+
* @readonly
|
|
19
|
+
* @type {string[]}
|
|
20
|
+
*/
|
|
21
|
+
const VALID_ACTIONS = ['dev', 'build'];
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Default Docsify configuration
|
|
25
|
+
* @readonly
|
|
26
|
+
* @type {Object}
|
|
27
|
+
*/
|
|
28
|
+
const DEFAULT_DOCSIFY_CONFIG = {
|
|
29
|
+
name: 'Documentation',
|
|
30
|
+
repo: '',
|
|
31
|
+
loadSidebar: true,
|
|
32
|
+
loadNavbar: true,
|
|
33
|
+
coverpage: false,
|
|
34
|
+
onlyCover: false,
|
|
35
|
+
auto2top: true,
|
|
36
|
+
maxLevel: 4,
|
|
37
|
+
subMaxLevel: 2,
|
|
38
|
+
mergeNavbar: true,
|
|
39
|
+
search: {
|
|
40
|
+
maxAge: 86400000,
|
|
41
|
+
paths: 'auto',
|
|
42
|
+
placeholder: 'Type to search',
|
|
43
|
+
noData: 'No results!',
|
|
44
|
+
depth: 2,
|
|
45
|
+
hideOtherSidebarContent: false,
|
|
46
|
+
},
|
|
47
|
+
plugins: [],
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Find the docs directory
|
|
52
|
+
* @param {string} [customPath] - Custom path provided by user
|
|
53
|
+
* @returns {Promise<string|null>} Path to docs directory or null
|
|
54
|
+
*/
|
|
55
|
+
async function findDocsDirectory(customPath) {
|
|
56
|
+
if (customPath) {
|
|
57
|
+
const resolvedPath = path.resolve(customPath);
|
|
58
|
+
if (await fileExists(resolvedPath)) {
|
|
59
|
+
const stat = await fs.stat(resolvedPath);
|
|
60
|
+
if (stat.isDirectory()) {
|
|
61
|
+
return resolvedPath;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
logger.error(`Docs directory not found: ${resolvedPath}`);
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Try common docs directory names
|
|
69
|
+
const candidates = ['docs', 'doc', 'documentation', 'md'];
|
|
70
|
+
const cwd = process.cwd();
|
|
71
|
+
|
|
72
|
+
for (const dir of candidates) {
|
|
73
|
+
const dirPath = path.join(cwd, dir);
|
|
74
|
+
if (await fileExists(dirPath)) {
|
|
75
|
+
const stat = await fs.stat(dirPath);
|
|
76
|
+
if (stat.isDirectory()) {
|
|
77
|
+
logger.debug(`Found docs directory: ${dirPath}`);
|
|
78
|
+
return dirPath;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Default to current directory if it has markdown files
|
|
84
|
+
try {
|
|
85
|
+
const files = await fs.readdir(cwd);
|
|
86
|
+
const hasMarkdown = files.some((f) => f.endsWith('.md'));
|
|
87
|
+
if (hasMarkdown) {
|
|
88
|
+
logger.debug('Using current directory as docs root (found markdown files)');
|
|
89
|
+
return cwd;
|
|
90
|
+
}
|
|
91
|
+
} catch (err) {
|
|
92
|
+
logger.debug('Error checking current directory:', err.message);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Ensure docsify-cli is installed
|
|
100
|
+
* @returns {Promise<boolean>}
|
|
101
|
+
*/
|
|
102
|
+
async function ensureDocsifyCLI() {
|
|
103
|
+
return new Promise((resolve) => {
|
|
104
|
+
exec('npx docsify --version', (error) => {
|
|
105
|
+
if (error) {
|
|
106
|
+
logger.warn('docsify-cli not found. It will be installed when needed.');
|
|
107
|
+
resolve(false);
|
|
108
|
+
} else {
|
|
109
|
+
resolve(true);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Generate Visualify plugin script for Docsify
|
|
117
|
+
* @returns {string} Script tag HTML
|
|
118
|
+
*/
|
|
119
|
+
function generateVisualifyScript() {
|
|
120
|
+
const visualifyPath = path.join(__dirname, '../../../dist/visualify-docsify.js');
|
|
121
|
+
|
|
122
|
+
// Check if built bundle exists, otherwise use source
|
|
123
|
+
return `
|
|
124
|
+
<!-- Visualify Plugin for Docsify -->
|
|
125
|
+
<script>
|
|
126
|
+
window.$docsify = window.$docsify || {};
|
|
127
|
+
window.$docsify.plugins = [].concat(
|
|
128
|
+
window.$docsify.plugins || [],
|
|
129
|
+
function(hook, vm) {
|
|
130
|
+
hook.init(function() {
|
|
131
|
+
console.log('[Visualify] Plugin initialized');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
hook.mounted(function() {
|
|
135
|
+
if (window.VisualifyDocsify) {
|
|
136
|
+
window.VisualifyDocsify.mountAll();
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
hook.doneEach(function() {
|
|
141
|
+
if (window.VisualifyDocsify) {
|
|
142
|
+
window.VisualifyDocsify.mountAll();
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
);
|
|
147
|
+
</script>
|
|
148
|
+
<script src="https://cdn.jsdelivr.net/npm/visualifyjs@latest/dist/visualify-docsify.min.js"></script>
|
|
149
|
+
`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Generate index.html for Docsify
|
|
154
|
+
* @param {Object} options - Generation options
|
|
155
|
+
* @param {string} options.docsPath - Path to docs directory
|
|
156
|
+
* @param {Object} [options.config] - Custom Docsify configuration
|
|
157
|
+
* @returns {string} HTML content
|
|
158
|
+
*/
|
|
159
|
+
async function generateIndexHtml(options) {
|
|
160
|
+
const { docsPath, config = {} } = options;
|
|
161
|
+
|
|
162
|
+
// Try to load existing configuration
|
|
163
|
+
const visualifyConfig = await loadConfig().catch(() => ({}));
|
|
164
|
+
const docsifyConfig = {
|
|
165
|
+
...DEFAULT_DOCSIFY_CONFIG,
|
|
166
|
+
...visualifyConfig.docsify,
|
|
167
|
+
...config,
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
// Check for README.md
|
|
171
|
+
const readmePath = path.join(docsPath, 'README.md');
|
|
172
|
+
const hasReadme = await fileExists(readmePath);
|
|
173
|
+
|
|
174
|
+
if (!hasReadme) {
|
|
175
|
+
logger.warn('No README.md found in docs directory');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const configJson = JSON.stringify(docsifyConfig, null, 2);
|
|
179
|
+
|
|
180
|
+
return `<!DOCTYPE html>
|
|
181
|
+
<html lang="en">
|
|
182
|
+
<head>
|
|
183
|
+
<meta charset="UTF-8">
|
|
184
|
+
<title>${docsifyConfig.name}</title>
|
|
185
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
|
186
|
+
<meta name="description" content="${docsifyConfig.name}">
|
|
187
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
|
|
188
|
+
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css">
|
|
189
|
+
<style>
|
|
190
|
+
.visualify-chart-wrapper {
|
|
191
|
+
margin: 1em 0;
|
|
192
|
+
border: 1px solid #e8e8e8;
|
|
193
|
+
border-radius: 4px;
|
|
194
|
+
overflow: hidden;
|
|
195
|
+
}
|
|
196
|
+
.visualify-chart-container {
|
|
197
|
+
width: 100%;
|
|
198
|
+
min-height: 400px;
|
|
199
|
+
}
|
|
200
|
+
.visualify-error {
|
|
201
|
+
padding: 16px;
|
|
202
|
+
border: 1px solid #ff4d4f;
|
|
203
|
+
border-radius: 4px;
|
|
204
|
+
background: #fff2f0;
|
|
205
|
+
color: #cf1322;
|
|
206
|
+
margin: 16px 0;
|
|
207
|
+
}
|
|
208
|
+
</style>
|
|
209
|
+
</head>
|
|
210
|
+
<body>
|
|
211
|
+
<div id="app"></div>
|
|
212
|
+
<script>
|
|
213
|
+
window.$docsify = ${configJson};
|
|
214
|
+
</script>
|
|
215
|
+
<!-- Docsify v4 -->
|
|
216
|
+
<script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
|
|
217
|
+
<!-- Search plugin -->
|
|
218
|
+
<script src="//cdn.jsdelivr.net/npm/docsify@4/lib/plugins/search.min.js"></script>
|
|
219
|
+
<!-- Copy code plugin -->
|
|
220
|
+
<script src="//cdn.jsdelivr.net/npm/docsify-copy-code@2"></script>
|
|
221
|
+
${generateVisualifyScript()}
|
|
222
|
+
</body>
|
|
223
|
+
</html>
|
|
224
|
+
`;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Execute the docs dev command
|
|
229
|
+
* @param {string} [docsPath] - Path to docs directory
|
|
230
|
+
* @param {Object} options - Command options
|
|
231
|
+
* @param {boolean} options.verbose - Enable verbose logging
|
|
232
|
+
* @param {string} options.port - Port to run server on
|
|
233
|
+
* @param {string} options.host - Host to bind server to
|
|
234
|
+
* @param {boolean} options.open - Open browser automatically
|
|
235
|
+
* @returns {Promise<void>}
|
|
236
|
+
*/
|
|
237
|
+
async function executeDocsDev(docsPath, options) {
|
|
238
|
+
try {
|
|
239
|
+
if (options.verbose) {
|
|
240
|
+
logger.enableVerbose();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
logger.debug('Starting docs dev server');
|
|
244
|
+
logger.debug('Options:', options);
|
|
245
|
+
|
|
246
|
+
// Find docs directory
|
|
247
|
+
const targetPath = await findDocsDirectory(docsPath);
|
|
248
|
+
if (!targetPath) {
|
|
249
|
+
logger.error('Could not find docs directory');
|
|
250
|
+
logger.tip('Create a docs/ directory or specify a path: visualify docs dev ./my-docs');
|
|
251
|
+
process.exit(1);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
logger.header('Documentation Development Server');
|
|
255
|
+
logger.info(`Docs directory: ${targetPath}`);
|
|
256
|
+
|
|
257
|
+
// Ensure index.html exists
|
|
258
|
+
const indexPath = path.join(targetPath, 'index.html');
|
|
259
|
+
if (!(await fileExists(indexPath))) {
|
|
260
|
+
logger.info('Creating index.html...');
|
|
261
|
+
const html = await generateIndexHtml({ docsPath: targetPath });
|
|
262
|
+
await fs.writeFile(indexPath, html, 'utf-8');
|
|
263
|
+
logger.success('Created index.html');
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Check for docsify-cli
|
|
267
|
+
await ensureDocsifyCLI();
|
|
268
|
+
|
|
269
|
+
const port = options.port || '3000';
|
|
270
|
+
const host = options.host || 'localhost';
|
|
271
|
+
|
|
272
|
+
logger.info('Starting Docsify dev server...');
|
|
273
|
+
logger.debug(`Port: ${port}, Host: ${host}`);
|
|
274
|
+
|
|
275
|
+
// Build docsify-cli command
|
|
276
|
+
const args = ['docsify', 'serve', targetPath, '--port', port, '--host', host];
|
|
277
|
+
|
|
278
|
+
if (options.open) {
|
|
279
|
+
args.push('--open');
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Spawn docsify serve process
|
|
283
|
+
const child = spawn('npx', args, {
|
|
284
|
+
stdio: 'pipe',
|
|
285
|
+
shell: true,
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
let serverStarted = false;
|
|
289
|
+
|
|
290
|
+
child.stdout.on('data', (data) => {
|
|
291
|
+
const output = data.toString();
|
|
292
|
+
|
|
293
|
+
// Filter and format Docsify output
|
|
294
|
+
if (output.includes('Listening') || output.includes('http')) {
|
|
295
|
+
if (!serverStarted) {
|
|
296
|
+
serverStarted = true;
|
|
297
|
+
logger.success(`Server running at http://${host}:${port}`);
|
|
298
|
+
logger.newline();
|
|
299
|
+
logger.info('Features:');
|
|
300
|
+
logger.example('Hot reload', 'Changes are automatically refreshed');
|
|
301
|
+
logger.example('Visualify charts', 'Code blocks with ```visualify are rendered as charts');
|
|
302
|
+
logger.newline();
|
|
303
|
+
logger.tip('Press Ctrl+C to stop the server');
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (options.verbose) {
|
|
308
|
+
process.stdout.write(output);
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
child.stderr.on('data', (data) => {
|
|
313
|
+
const output = data.toString();
|
|
314
|
+
|
|
315
|
+
// Only show errors unless verbose
|
|
316
|
+
if (options.verbose || output.includes('error') || output.includes('Error')) {
|
|
317
|
+
process.stderr.write(output);
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
child.on('close', (code) => {
|
|
322
|
+
if (code !== 0 && code !== null) {
|
|
323
|
+
logger.error(`Docsify server exited with code ${code}`);
|
|
324
|
+
process.exit(1);
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
child.on('error', (err) => {
|
|
329
|
+
logger.error('Failed to start Docsify server:', err.message);
|
|
330
|
+
logger.tip('Try installing docsify-cli globally: npm i -g docsify-cli');
|
|
331
|
+
process.exit(1);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
// Handle graceful shutdown
|
|
335
|
+
process.on('SIGINT', () => {
|
|
336
|
+
logger.newline();
|
|
337
|
+
logger.info('Shutting down server...');
|
|
338
|
+
child.kill('SIGINT');
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
process.on('SIGTERM', () => {
|
|
342
|
+
child.kill('SIGTERM');
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
} catch (err) {
|
|
346
|
+
logger.error('Failed to start docs dev server:', err.message);
|
|
347
|
+
logger.debug('Stack trace:', err.stack);
|
|
348
|
+
process.exit(1);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Execute the docs build command
|
|
354
|
+
* @param {string} [docsPath] - Path to docs directory
|
|
355
|
+
* @param {string} [destPath] - Destination path for built files
|
|
356
|
+
* @param {Object} options - Command options
|
|
357
|
+
* @param {boolean} options.verbose - Enable verbose logging
|
|
358
|
+
* @returns {Promise<void>}
|
|
359
|
+
*/
|
|
360
|
+
async function executeDocsBuild(docsPath, destPath, options) {
|
|
361
|
+
try {
|
|
362
|
+
if (options.verbose) {
|
|
363
|
+
logger.enableVerbose();
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
logger.debug('Building documentation');
|
|
367
|
+
logger.debug('Options:', options);
|
|
368
|
+
|
|
369
|
+
// Find docs directory
|
|
370
|
+
const sourcePath = await findDocsDirectory(docsPath);
|
|
371
|
+
if (!sourcePath) {
|
|
372
|
+
logger.error('Could not find docs directory');
|
|
373
|
+
logger.tip('Create a docs/ directory or specify a path: visualify docs build ./my-docs');
|
|
374
|
+
process.exit(1);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Determine output directory
|
|
378
|
+
const outputDir = destPath
|
|
379
|
+
? path.resolve(destPath)
|
|
380
|
+
: path.join(process.cwd(), 'dist-docs');
|
|
381
|
+
|
|
382
|
+
logger.header('Documentation Build');
|
|
383
|
+
logger.info(`Source: ${sourcePath}`);
|
|
384
|
+
logger.info(`Output: ${outputDir}`);
|
|
385
|
+
|
|
386
|
+
// Ensure index.html exists
|
|
387
|
+
const indexPath = path.join(sourcePath, 'index.html');
|
|
388
|
+
if (!(await fileExists(indexPath))) {
|
|
389
|
+
logger.info('Creating index.html...');
|
|
390
|
+
const html = await generateIndexHtml({ docsPath: sourcePath });
|
|
391
|
+
await fs.writeFile(indexPath, html, 'utf-8');
|
|
392
|
+
logger.success('Created index.html');
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Create output directory
|
|
396
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
397
|
+
|
|
398
|
+
// Copy all files from source to output
|
|
399
|
+
logger.info('Copying files...');
|
|
400
|
+
await copyDirectory(sourcePath, outputDir);
|
|
401
|
+
|
|
402
|
+
logger.success('Documentation built successfully!');
|
|
403
|
+
logger.newline();
|
|
404
|
+
logger.info('To serve the built documentation:');
|
|
405
|
+
logger.example(`npx serve ${outputDir}`, 'Serve with npx serve');
|
|
406
|
+
logger.example(`python -m http.server -d ${outputDir}`, 'Serve with Python');
|
|
407
|
+
|
|
408
|
+
} catch (err) {
|
|
409
|
+
logger.error('Failed to build documentation:', err.message);
|
|
410
|
+
logger.debug('Stack trace:', err.stack);
|
|
411
|
+
process.exit(1);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Copy directory recursively
|
|
417
|
+
* @param {string} src - Source directory
|
|
418
|
+
* @param {string} dest - Destination directory
|
|
419
|
+
*/
|
|
420
|
+
async function copyDirectory(src, dest) {
|
|
421
|
+
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
422
|
+
|
|
423
|
+
for (const entry of entries) {
|
|
424
|
+
const srcPath = path.join(src, entry.name);
|
|
425
|
+
const destPath = path.join(dest, entry.name);
|
|
426
|
+
|
|
427
|
+
if (entry.isDirectory()) {
|
|
428
|
+
await fs.mkdir(destPath, { recursive: true });
|
|
429
|
+
await copyDirectory(srcPath, destPath);
|
|
430
|
+
} else {
|
|
431
|
+
await fs.copyFile(srcPath, destPath);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Execute the docs command with a subcommand
|
|
438
|
+
* @param {string} action - The action to perform
|
|
439
|
+
* @param {string} [docsPath] - Path to docs directory
|
|
440
|
+
* @param {string} [destPath] - Destination path (for build)
|
|
441
|
+
* @param {Object} options - Command options
|
|
442
|
+
* @returns {Promise<void>}
|
|
443
|
+
*/
|
|
444
|
+
async function executeDocs(action, docsPath, destPath, options) {
|
|
445
|
+
if (!VALID_ACTIONS.includes(action)) {
|
|
446
|
+
logger.error(`Invalid action: "${action}"`);
|
|
447
|
+
logger.tip(`Valid actions are: ${VALID_ACTIONS.join(', ')}`);
|
|
448
|
+
process.exit(1);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
switch (action) {
|
|
452
|
+
case 'dev':
|
|
453
|
+
await executeDocsDev(docsPath, options);
|
|
454
|
+
break;
|
|
455
|
+
case 'build':
|
|
456
|
+
await executeDocsBuild(docsPath, destPath, options);
|
|
457
|
+
break;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Create and configure the docs command
|
|
463
|
+
* @returns {Command} The configured command
|
|
464
|
+
*/
|
|
465
|
+
function createDocsCommand() {
|
|
466
|
+
const command = new Command('docs')
|
|
467
|
+
.description('Documentation management commands')
|
|
468
|
+
.addHelpText(
|
|
469
|
+
'after',
|
|
470
|
+
`
|
|
471
|
+
Examples:
|
|
472
|
+
$ visualify docs dev Start dev server (auto-detect docs dir)
|
|
473
|
+
$ visualify docs dev ./docs Start dev server with specific path
|
|
474
|
+
$ visualify docs dev -p 8080 Start on port 8080
|
|
475
|
+
$ visualify docs build Build to ./dist-docs
|
|
476
|
+
$ visualify docs build ./docs ./site Build to custom output directory
|
|
477
|
+
$ visualify docs dev --open Start and open browser
|
|
478
|
+
|
|
479
|
+
Configuration:
|
|
480
|
+
Create visualify.json to customize Docsify behavior:
|
|
481
|
+
{
|
|
482
|
+
"docsify": {
|
|
483
|
+
"name": "My Documentation",
|
|
484
|
+
"themeColor": "#3F51B5",
|
|
485
|
+
"search": { "depth": 3 }
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
`
|
|
489
|
+
);
|
|
490
|
+
|
|
491
|
+
// Add subcommands
|
|
492
|
+
command
|
|
493
|
+
.command('dev')
|
|
494
|
+
.description('Start the documentation development server')
|
|
495
|
+
.argument('[path]', 'Path to docs directory (default: auto-detect)')
|
|
496
|
+
.option('-v, --verbose', 'Enable verbose logging')
|
|
497
|
+
.option('-p, --port <number>', 'Port to run the server on', '3000')
|
|
498
|
+
.option('-h, --host <host>', 'Host to bind the server to', 'localhost')
|
|
499
|
+
.option('-o, --open', 'Open browser automatically')
|
|
500
|
+
.action((path, options) => executeDocsDev(path, options));
|
|
501
|
+
|
|
502
|
+
command
|
|
503
|
+
.command('build')
|
|
504
|
+
.description('Build static documentation')
|
|
505
|
+
.argument('[path]', 'Path to docs directory (default: auto-detect)')
|
|
506
|
+
.argument('[dest]', 'Output directory (default: ./dist-docs)')
|
|
507
|
+
.option('-v, --verbose', 'Enable verbose logging')
|
|
508
|
+
.action((path, dest, options) => executeDocsBuild(path, dest, options));
|
|
509
|
+
|
|
510
|
+
return command;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
module.exports = {
|
|
514
|
+
createDocsCommand,
|
|
515
|
+
executeDocs,
|
|
516
|
+
executeDocsDev,
|
|
517
|
+
executeDocsBuild,
|
|
518
|
+
VALID_ACTIONS,
|
|
519
|
+
generateIndexHtml,
|
|
520
|
+
findDocsDirectory,
|
|
521
|
+
};
|