visualifyjs 2.5.3 → 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 -193
- 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 -0
- package/docs/docs/_404.md +51 -51
- package/docs/docs/_coverpage.md +11 -11
- package/docs/docs/_sidebar.md +54 -43
- 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 -123
- 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 -1
- package/docs/docs/more-pages.md +23 -23
- package/docs/docs/quickstart.md +148 -119
- 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 -579
- 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 -143
- 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,379 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Visual Editor Command for Visualify CLI
|
|
3
|
+
* @module cli/commands/edit
|
|
4
|
+
*
|
|
5
|
+
* Starts the visual configuration editor for creating and editing
|
|
6
|
+
* Visualify configurations without writing JSON.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { Command } = require('commander');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const http = require('http');
|
|
13
|
+
const logger = require('../utils/logger');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Default port for the editor server
|
|
17
|
+
* @readonly
|
|
18
|
+
*/
|
|
19
|
+
const DEFAULT_PORT = 3456;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Default host for the editor server
|
|
23
|
+
* @readonly
|
|
24
|
+
*/
|
|
25
|
+
const DEFAULT_HOST = 'localhost';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* HTML template for the editor page
|
|
29
|
+
*/
|
|
30
|
+
const EDITOR_HTML_TEMPLATE = `<!DOCTYPE html>
|
|
31
|
+
<html lang="en">
|
|
32
|
+
<head>
|
|
33
|
+
<meta charset="UTF-8">
|
|
34
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
35
|
+
<title>Visualify Editor</title>
|
|
36
|
+
<link
|
|
37
|
+
rel="stylesheet"
|
|
38
|
+
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
|
|
39
|
+
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN"
|
|
40
|
+
crossorigin="anonymous"
|
|
41
|
+
/>
|
|
42
|
+
<style>
|
|
43
|
+
body {
|
|
44
|
+
margin: 0;
|
|
45
|
+
padding: 0;
|
|
46
|
+
overflow: hidden;
|
|
47
|
+
}
|
|
48
|
+
#root {
|
|
49
|
+
height: 100vh;
|
|
50
|
+
width: 100vw;
|
|
51
|
+
}
|
|
52
|
+
.loading-screen {
|
|
53
|
+
display: flex;
|
|
54
|
+
flex-direction: column;
|
|
55
|
+
align-items: center;
|
|
56
|
+
justify-content: center;
|
|
57
|
+
height: 100vh;
|
|
58
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
59
|
+
}
|
|
60
|
+
.loading-spinner {
|
|
61
|
+
width: 50px;
|
|
62
|
+
height: 50px;
|
|
63
|
+
border: 4px solid #f3f3f3;
|
|
64
|
+
border-top: 4px solid #3498db;
|
|
65
|
+
border-radius: 50%;
|
|
66
|
+
animation: spin 1s linear infinite;
|
|
67
|
+
margin-bottom: 20px;
|
|
68
|
+
}
|
|
69
|
+
@keyframes spin {
|
|
70
|
+
0% { transform: rotate(0deg); }
|
|
71
|
+
100% { transform: rotate(360deg); }
|
|
72
|
+
}
|
|
73
|
+
</style>
|
|
74
|
+
</head>
|
|
75
|
+
<body>
|
|
76
|
+
<div id="root">
|
|
77
|
+
<div class="loading-screen">
|
|
78
|
+
<div class="loading-spinner"></div>
|
|
79
|
+
<h3>Loading Visualify Editor...</h3>
|
|
80
|
+
<p>Please wait while the editor initializes</p>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
<script>
|
|
84
|
+
// Embedded editor configuration
|
|
85
|
+
window.VISUALIFY_EDITOR_CONFIG = {{EDITOR_CONFIG}};
|
|
86
|
+
</script>
|
|
87
|
+
<script src="/editor/static/js/editor.js"></script>
|
|
88
|
+
</body>
|
|
89
|
+
</html>`;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Serve static file
|
|
93
|
+
* @param {http.ServerResponse} res - Response object
|
|
94
|
+
* @param {string} filePath - Path to file
|
|
95
|
+
* @param {string} contentType - MIME type
|
|
96
|
+
*/
|
|
97
|
+
function serveStaticFile(res, filePath, contentType) {
|
|
98
|
+
try {
|
|
99
|
+
const content = fs.readFileSync(filePath);
|
|
100
|
+
res.writeHead(200, { 'Content-Type': contentType });
|
|
101
|
+
res.end(content);
|
|
102
|
+
} catch (error) {
|
|
103
|
+
res.writeHead(404);
|
|
104
|
+
res.end('Not found');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Load configuration from file
|
|
110
|
+
* @param {string} filePath - Path to config file
|
|
111
|
+
* @returns {Object|null} Loaded configuration
|
|
112
|
+
*/
|
|
113
|
+
function loadConfigFile(filePath) {
|
|
114
|
+
try {
|
|
115
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
116
|
+
return JSON.parse(content);
|
|
117
|
+
} catch (error) {
|
|
118
|
+
logger.warn(`Failed to load config file: ${error.message}`);
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Create the editor server
|
|
125
|
+
* @param {Object} options - Server options
|
|
126
|
+
* @param {number} options.port - Server port
|
|
127
|
+
* @param {string} options.host - Server host
|
|
128
|
+
* @param {string|null} options.configFile - Path to config file
|
|
129
|
+
* @returns {http.Server}
|
|
130
|
+
*/
|
|
131
|
+
function createEditorServer(options) {
|
|
132
|
+
const { port, host, configFile } = options;
|
|
133
|
+
|
|
134
|
+
// Load config if specified
|
|
135
|
+
let editorConfig = {
|
|
136
|
+
version: '3.0.0',
|
|
137
|
+
charts: [],
|
|
138
|
+
layout: { type: 'grid', rows: 1, cols: 1, gap: '10px' },
|
|
139
|
+
theme: 'modern',
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
if (configFile) {
|
|
143
|
+
const loadedConfig = loadConfigFile(configFile);
|
|
144
|
+
if (loadedConfig) {
|
|
145
|
+
editorConfig = { ...editorConfig, ...loadedConfig };
|
|
146
|
+
logger.success(`Loaded configuration from ${configFile}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const server = http.createServer((req, res) => {
|
|
151
|
+
// Enable CORS
|
|
152
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
153
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
154
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
155
|
+
|
|
156
|
+
if (req.method === 'OPTIONS') {
|
|
157
|
+
res.writeHead(200);
|
|
158
|
+
res.end();
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const url = new URL(req.url, `http://${host}:${port}`);
|
|
163
|
+
const pathname = url.pathname;
|
|
164
|
+
|
|
165
|
+
// Main editor page
|
|
166
|
+
if (pathname === '/' || pathname === '/editor') {
|
|
167
|
+
const html = EDITOR_HTML_TEMPLATE.replace(
|
|
168
|
+
'{{EDITOR_CONFIG}}',
|
|
169
|
+
JSON.stringify(editorConfig).replace(/</g, '\\u003c')
|
|
170
|
+
);
|
|
171
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
172
|
+
res.end(html);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Static assets - editor bundle
|
|
177
|
+
if (pathname === '/editor/static/js/editor.js') {
|
|
178
|
+
const editorJsPath = path.join(__dirname, '../../../editor/static/js/editor.js');
|
|
179
|
+
if (fs.existsSync(editorJsPath)) {
|
|
180
|
+
serveStaticFile(res, editorJsPath, 'application/javascript');
|
|
181
|
+
} else {
|
|
182
|
+
// Return placeholder if bundle doesn't exist yet
|
|
183
|
+
res.writeHead(200, { 'Content-Type': 'application/javascript' });
|
|
184
|
+
res.end(`
|
|
185
|
+
// Visualify Editor Bundle
|
|
186
|
+
// This is a placeholder. In production, this would be the compiled editor bundle.
|
|
187
|
+
console.log('Visualify Editor loaded');
|
|
188
|
+
|
|
189
|
+
// Simple editor implementation for demo
|
|
190
|
+
const root = document.getElementById('root');
|
|
191
|
+
const config = window.VISUALIFY_EDITOR_CONFIG || {};
|
|
192
|
+
|
|
193
|
+
root.innerHTML = \`
|
|
194
|
+
<div style="padding: 20px; font-family: sans-serif;">
|
|
195
|
+
<h1>Visualify Editor</h1>
|
|
196
|
+
<p>Configuration loaded with \${config.charts?.length || 0} charts</p>
|
|
197
|
+
<div style="background: #f5f5f5; padding: 15px; border-radius: 8px; margin-top: 20px;">
|
|
198
|
+
<pre style="margin: 0; overflow: auto;">\${JSON.stringify(config, null, 2)}</pre>
|
|
199
|
+
</div>
|
|
200
|
+
<p style="margin-top: 20px; color: #666;">
|
|
201
|
+
<strong>Note:</strong> This is a development preview.
|
|
202
|
+
The full editor requires building the React application.
|
|
203
|
+
</p>
|
|
204
|
+
</div>
|
|
205
|
+
\`;
|
|
206
|
+
`);
|
|
207
|
+
}
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// API endpoints
|
|
212
|
+
if (pathname === '/api/config') {
|
|
213
|
+
if (req.method === 'GET') {
|
|
214
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
215
|
+
res.end(JSON.stringify(editorConfig));
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (req.method === 'POST') {
|
|
220
|
+
let body = '';
|
|
221
|
+
req.on('data', chunk => body += chunk);
|
|
222
|
+
req.on('end', () => {
|
|
223
|
+
try {
|
|
224
|
+
const newConfig = JSON.parse(body);
|
|
225
|
+
Object.assign(editorConfig, newConfig);
|
|
226
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
227
|
+
res.end(JSON.stringify({ success: true }));
|
|
228
|
+
} catch (error) {
|
|
229
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
230
|
+
res.end(JSON.stringify({ error: error.message }));
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// 404
|
|
238
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
239
|
+
res.end(JSON.stringify({ error: 'Not found' }));
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
return server;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Open browser
|
|
247
|
+
* @param {string} url - URL to open
|
|
248
|
+
*/
|
|
249
|
+
function openBrowser(url) {
|
|
250
|
+
const { exec } = require('child_process');
|
|
251
|
+
const platform = process.platform;
|
|
252
|
+
|
|
253
|
+
let command;
|
|
254
|
+
switch (platform) {
|
|
255
|
+
case 'darwin':
|
|
256
|
+
command = `open "${url}"`;
|
|
257
|
+
break;
|
|
258
|
+
case 'win32':
|
|
259
|
+
command = `start "" "${url}"`;
|
|
260
|
+
break;
|
|
261
|
+
default:
|
|
262
|
+
command = `xdg-open "${url}"`;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
exec(command, (error) => {
|
|
266
|
+
if (error) {
|
|
267
|
+
logger.debug('Failed to open browser:', error.message);
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Execute the edit command
|
|
274
|
+
* @param {string|null} configFile - Path to config file
|
|
275
|
+
* @param {Object} options - Command options
|
|
276
|
+
* @param {number} options.port - Server port
|
|
277
|
+
* @param {string} options.host - Server host
|
|
278
|
+
* @param {boolean} options.open - Whether to open browser
|
|
279
|
+
* @returns {Promise<void>}
|
|
280
|
+
*/
|
|
281
|
+
async function executeEdit(configFile, options) {
|
|
282
|
+
try {
|
|
283
|
+
const port = parseInt(options.port, 10) || DEFAULT_PORT;
|
|
284
|
+
const host = options.host || DEFAULT_HOST;
|
|
285
|
+
const shouldOpen = options.open !== false;
|
|
286
|
+
|
|
287
|
+
logger.header('Visualify Editor');
|
|
288
|
+
logger.info('Starting visual configuration editor...');
|
|
289
|
+
|
|
290
|
+
// Validate config file if provided
|
|
291
|
+
if (configFile && !fs.existsSync(configFile)) {
|
|
292
|
+
logger.warn(`Config file not found: ${configFile}`);
|
|
293
|
+
logger.tip('Starting with default configuration');
|
|
294
|
+
configFile = null;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Create and start server
|
|
298
|
+
const server = createEditorServer({ port, host, configFile });
|
|
299
|
+
|
|
300
|
+
server.listen(port, host, () => {
|
|
301
|
+
const url = `http://${host}:${port}`;
|
|
302
|
+
|
|
303
|
+
logger.success('Editor server started');
|
|
304
|
+
logger.newline();
|
|
305
|
+
logger.info(`Local: ${url}`);
|
|
306
|
+
logger.info(`Network: http://${require('os').networkInterfaces()['en0']?.[0]?.address || host}:${port}`);
|
|
307
|
+
logger.newline();
|
|
308
|
+
|
|
309
|
+
if (configFile) {
|
|
310
|
+
logger.info(`Editing: ${path.resolve(configFile)}`);
|
|
311
|
+
} else {
|
|
312
|
+
logger.info('Editing: New configuration');
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
logger.newline();
|
|
316
|
+
logger.tip('Press Ctrl+C to stop the server');
|
|
317
|
+
logger.newline();
|
|
318
|
+
|
|
319
|
+
// Open browser
|
|
320
|
+
if (shouldOpen) {
|
|
321
|
+
setTimeout(() => {
|
|
322
|
+
openBrowser(url);
|
|
323
|
+
}, 1000);
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
// Handle server errors
|
|
328
|
+
server.on('error', (error) => {
|
|
329
|
+
if (error.code === 'EADDRINUSE') {
|
|
330
|
+
logger.error(`Port ${port} is already in use`);
|
|
331
|
+
logger.tip(`Try a different port with: visualify edit --port ${port + 1}`);
|
|
332
|
+
} else {
|
|
333
|
+
logger.error('Server error:', error.message);
|
|
334
|
+
}
|
|
335
|
+
process.exit(1);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
// Graceful shutdown
|
|
339
|
+
process.on('SIGINT', () => {
|
|
340
|
+
logger.newline();
|
|
341
|
+
logger.info('Shutting down editor server...');
|
|
342
|
+
server.close(() => {
|
|
343
|
+
logger.success('Server stopped');
|
|
344
|
+
process.exit(0);
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
} catch (error) {
|
|
349
|
+
logger.error('Failed to start editor:', error.message);
|
|
350
|
+
logger.debug('Stack trace:', error.stack);
|
|
351
|
+
process.exit(1);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Create and configure the edit command
|
|
357
|
+
* @returns {Command} The configured command
|
|
358
|
+
*/
|
|
359
|
+
function createEditCommand() {
|
|
360
|
+
const command = new Command('edit')
|
|
361
|
+
.description('Start the visual configuration editor')
|
|
362
|
+
.argument('[file]', 'Configuration file to edit (optional)')
|
|
363
|
+
.option('-p, --port <number>', 'Port to run the editor on', String(DEFAULT_PORT))
|
|
364
|
+
.option('-h, --host <host>', 'Host to bind the server to', DEFAULT_HOST)
|
|
365
|
+
.option('--no-open', 'Do not open browser automatically')
|
|
366
|
+
.action(executeEdit);
|
|
367
|
+
|
|
368
|
+
// Add alias 'editor' for convenience
|
|
369
|
+
command.alias('editor');
|
|
370
|
+
|
|
371
|
+
return command;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
module.exports = {
|
|
375
|
+
createEditCommand,
|
|
376
|
+
executeEdit,
|
|
377
|
+
DEFAULT_PORT,
|
|
378
|
+
DEFAULT_HOST,
|
|
379
|
+
};
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Project initialization command for Visualify CLI
|
|
3
|
+
* @module cli/commands/init
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { Command } = require('commander');
|
|
7
|
+
const logger = require('../utils/logger');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Valid template types
|
|
11
|
+
* @readonly
|
|
12
|
+
* @type {string[]}
|
|
13
|
+
*/
|
|
14
|
+
const VALID_TEMPLATES = ['docs', 'portal', 'full'];
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Default template when not specified
|
|
18
|
+
* @readonly
|
|
19
|
+
* @type {string}
|
|
20
|
+
*/
|
|
21
|
+
const DEFAULT_TEMPLATE = 'full';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Template descriptions for help text
|
|
25
|
+
* @readonly
|
|
26
|
+
* @type {Object<string, string>}
|
|
27
|
+
*/
|
|
28
|
+
const TEMPLATE_DESCRIPTIONS = {
|
|
29
|
+
docs: 'Documentation-only project with markdown support',
|
|
30
|
+
portal: 'Data portal with visualization components',
|
|
31
|
+
full: 'Complete project with both docs and portal features',
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Execute the init command
|
|
36
|
+
* @param {string} template - The template to use
|
|
37
|
+
* @param {Object} options - Command options
|
|
38
|
+
* @param {boolean} options.verbose - Enable verbose logging
|
|
39
|
+
* @param {string} [options.name] - Project name
|
|
40
|
+
* @param {string} [options.dir] - Target directory
|
|
41
|
+
* @returns {Promise<void>}
|
|
42
|
+
*/
|
|
43
|
+
async function executeInit(template, options) {
|
|
44
|
+
try {
|
|
45
|
+
if (options.verbose) {
|
|
46
|
+
logger.enableVerbose();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
logger.debug('Initializing new project');
|
|
50
|
+
logger.debug('Template:', template);
|
|
51
|
+
logger.debug('Options:', options);
|
|
52
|
+
|
|
53
|
+
// Validate template
|
|
54
|
+
if (!VALID_TEMPLATES.includes(template)) {
|
|
55
|
+
logger.error(`Invalid template: "${template}"`);
|
|
56
|
+
logger.tip(`Valid templates are: ${VALID_TEMPLATES.join(', ')}`);
|
|
57
|
+
logger.newline();
|
|
58
|
+
logger.info('Template descriptions:');
|
|
59
|
+
Object.entries(TEMPLATE_DESCRIPTIONS).forEach(([key, desc]) => {
|
|
60
|
+
logger.example(`${key}`, desc);
|
|
61
|
+
});
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const projectName = options.name || 'my-visualify-project';
|
|
66
|
+
const targetDir = options.dir || `./${projectName}`;
|
|
67
|
+
|
|
68
|
+
logger.header('Project Initialization');
|
|
69
|
+
logger.info(`Creating new ${chalk.cyan(template)} project...`);
|
|
70
|
+
logger.info(`Project name: ${chalk.cyan(projectName)}`);
|
|
71
|
+
logger.info(`Target directory: ${chalk.cyan(targetDir)}`);
|
|
72
|
+
|
|
73
|
+
// TODO: Implement actual project scaffolding
|
|
74
|
+
await scaffoldProject(template, projectName, targetDir, options);
|
|
75
|
+
|
|
76
|
+
logger.success('Project initialized successfully!');
|
|
77
|
+
logger.newline();
|
|
78
|
+
logger.info('Next steps:');
|
|
79
|
+
logger.example(`cd ${projectName}`, 'Navigate to project directory');
|
|
80
|
+
logger.example('npm install', 'Install dependencies');
|
|
81
|
+
logger.example('visualify dev', 'Start development server');
|
|
82
|
+
} catch (err) {
|
|
83
|
+
logger.error('Failed to initialize project:', err.message);
|
|
84
|
+
logger.debug('Stack trace:', err.stack);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Scaffold a new project
|
|
91
|
+
* @param {string} template - The template type
|
|
92
|
+
* @param {string} projectName - The project name
|
|
93
|
+
* @param {string} targetDir - The target directory
|
|
94
|
+
* @param {Object} options - Command options
|
|
95
|
+
* @returns {Promise<void>}
|
|
96
|
+
*/
|
|
97
|
+
async function scaffoldProject(template, projectName, targetDir, options) {
|
|
98
|
+
logger.debug('Scaffolding project...');
|
|
99
|
+
|
|
100
|
+
// Simulate project creation steps
|
|
101
|
+
const steps = [
|
|
102
|
+
'Creating directory structure',
|
|
103
|
+
'Generating configuration files',
|
|
104
|
+
'Copying template files',
|
|
105
|
+
'Creating package.json',
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
for (const step of steps) {
|
|
109
|
+
logger.info(` ${chalk.gray('→')} ${step}`);
|
|
110
|
+
// TODO: Implement actual file operations
|
|
111
|
+
await simulateDelay(100);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Create template-specific files
|
|
115
|
+
switch (template) {
|
|
116
|
+
case 'docs':
|
|
117
|
+
await scaffoldDocsTemplate(targetDir);
|
|
118
|
+
break;
|
|
119
|
+
case 'portal':
|
|
120
|
+
await scaffoldPortalTemplate(targetDir);
|
|
121
|
+
break;
|
|
122
|
+
case 'full':
|
|
123
|
+
await scaffoldFullTemplate(targetDir);
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
logger.debug('Scaffolding complete');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Scaffold a docs-only template
|
|
132
|
+
* @param {string} targetDir - The target directory
|
|
133
|
+
* @returns {Promise<void>}
|
|
134
|
+
*/
|
|
135
|
+
async function scaffoldDocsTemplate(targetDir) {
|
|
136
|
+
logger.debug('Creating docs template files');
|
|
137
|
+
// TODO: Implement docs template scaffolding
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Scaffold a portal-only template
|
|
142
|
+
* @param {string} targetDir - The target directory
|
|
143
|
+
* @returns {Promise<void>}
|
|
144
|
+
*/
|
|
145
|
+
async function scaffoldPortalTemplate(targetDir) {
|
|
146
|
+
logger.debug('Creating portal template files');
|
|
147
|
+
// TODO: Implement portal template scaffolding
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Scaffold a full template with both docs and portal
|
|
152
|
+
* @param {string} targetDir - The target directory
|
|
153
|
+
* @returns {Promise<void>}
|
|
154
|
+
*/
|
|
155
|
+
async function scaffoldFullTemplate(targetDir) {
|
|
156
|
+
logger.debug('Creating full template files');
|
|
157
|
+
// TODO: Implement full template scaffolding
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Simulate a delay for async operations
|
|
162
|
+
* @param {number} ms - Milliseconds to delay
|
|
163
|
+
* @returns {Promise<void>}
|
|
164
|
+
*/
|
|
165
|
+
function simulateDelay(ms) {
|
|
166
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Create and configure the init command
|
|
171
|
+
* @returns {Command} The configured command
|
|
172
|
+
*/
|
|
173
|
+
function createInitCommand() {
|
|
174
|
+
const command = new Command('init')
|
|
175
|
+
.description('Initialize a new Visualify project')
|
|
176
|
+
.argument(
|
|
177
|
+
'[template]',
|
|
178
|
+
`Project template: ${VALID_TEMPLATES.join(', ')}`,
|
|
179
|
+
DEFAULT_TEMPLATE
|
|
180
|
+
)
|
|
181
|
+
.option('-v, --verbose', 'Enable verbose logging')
|
|
182
|
+
.option('-n, --name <name>', 'Project name')
|
|
183
|
+
.option('-d, --dir <directory>', 'Target directory')
|
|
184
|
+
.addHelpText(
|
|
185
|
+
'after',
|
|
186
|
+
`
|
|
187
|
+
Templates:
|
|
188
|
+
docs ${TEMPLATE_DESCRIPTIONS.docs}
|
|
189
|
+
portal ${TEMPLATE_DESCRIPTIONS.portal}
|
|
190
|
+
full ${TEMPLATE_DESCRIPTIONS.full} (default)
|
|
191
|
+
|
|
192
|
+
Examples:
|
|
193
|
+
$ visualify init Initialize with default (full) template
|
|
194
|
+
$ visualify init docs Initialize docs-only project
|
|
195
|
+
$ visualify init portal -n my-app Initialize portal with custom name
|
|
196
|
+
$ visualify init full -d ./my-dir Initialize in specific directory
|
|
197
|
+
`
|
|
198
|
+
)
|
|
199
|
+
.action(executeInit);
|
|
200
|
+
|
|
201
|
+
return command;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Import chalk for use in this module
|
|
205
|
+
const chalk = require('chalk');
|
|
206
|
+
|
|
207
|
+
module.exports = {
|
|
208
|
+
createInitCommand,
|
|
209
|
+
executeInit,
|
|
210
|
+
VALID_TEMPLATES,
|
|
211
|
+
DEFAULT_TEMPLATE,
|
|
212
|
+
TEMPLATE_DESCRIPTIONS,
|
|
213
|
+
};
|