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,396 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Web Worker Pool Manager
|
|
3
|
+
* @module core/workers/worker-pool
|
|
4
|
+
*
|
|
5
|
+
* Manages a pool of web workers for concurrent data processing.
|
|
6
|
+
* Provides task queuing, load balancing, and error handling.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Default configuration for worker pool
|
|
11
|
+
* @readonly
|
|
12
|
+
*/
|
|
13
|
+
const DEFAULT_CONFIG = {
|
|
14
|
+
minWorkers: 2,
|
|
15
|
+
maxWorkers: navigator.hardwareConcurrency || 4,
|
|
16
|
+
taskTimeout: 30000,
|
|
17
|
+
idleTimeout: 60000,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Worker task status
|
|
22
|
+
* @readonly
|
|
23
|
+
*/
|
|
24
|
+
const TASK_STATUS = {
|
|
25
|
+
PENDING: 'pending',
|
|
26
|
+
RUNNING: 'running',
|
|
27
|
+
COMPLETED: 'completed',
|
|
28
|
+
FAILED: 'failed',
|
|
29
|
+
CANCELLED: 'cancelled',
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Worker Pool Manager
|
|
34
|
+
* Manages multiple web workers for parallel data processing
|
|
35
|
+
*/
|
|
36
|
+
class WorkerPool {
|
|
37
|
+
/**
|
|
38
|
+
* Create a new worker pool
|
|
39
|
+
* @param {Object} options - Pool configuration
|
|
40
|
+
* @param {string} options.workerScript - Path to worker script
|
|
41
|
+
* @param {number} options.minWorkers - Minimum number of workers
|
|
42
|
+
* @param {number} options.maxWorkers - Maximum number of workers
|
|
43
|
+
* @param {number} options.taskTimeout - Task timeout in milliseconds
|
|
44
|
+
* @param {number} options.idleTimeout - Idle worker termination timeout
|
|
45
|
+
*/
|
|
46
|
+
constructor(options = {}) {
|
|
47
|
+
this.config = { ...DEFAULT_CONFIG, ...options };
|
|
48
|
+
this.workerScript = options.workerScript;
|
|
49
|
+
|
|
50
|
+
if (!this.workerScript) {
|
|
51
|
+
throw new Error('WorkerPool requires a workerScript path');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
this.workers = new Map();
|
|
55
|
+
this.taskQueue = [];
|
|
56
|
+
this.activeTasks = new Map();
|
|
57
|
+
this.taskIdCounter = 0;
|
|
58
|
+
this.isTerminated = false;
|
|
59
|
+
|
|
60
|
+
// Initialize minimum workers
|
|
61
|
+
this._ensureMinWorkers();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Ensure minimum number of workers are available
|
|
66
|
+
* @private
|
|
67
|
+
*/
|
|
68
|
+
_ensureMinWorkers() {
|
|
69
|
+
const currentCount = this.workers.size;
|
|
70
|
+
const needed = this.config.minWorkers - currentCount;
|
|
71
|
+
|
|
72
|
+
for (let i = 0; i < needed; i++) {
|
|
73
|
+
this._createWorker();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Create a new worker
|
|
79
|
+
* @private
|
|
80
|
+
* @returns {string} Worker ID
|
|
81
|
+
*/
|
|
82
|
+
_createWorker() {
|
|
83
|
+
const workerId = `worker-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
const worker = new Worker(this.workerScript, { type: 'module' });
|
|
87
|
+
|
|
88
|
+
const workerInfo = {
|
|
89
|
+
id: workerId,
|
|
90
|
+
worker,
|
|
91
|
+
status: 'idle',
|
|
92
|
+
currentTask: null,
|
|
93
|
+
createdAt: Date.now(),
|
|
94
|
+
taskCount: 0,
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
worker.onmessage = (event) => this._handleMessage(workerId, event);
|
|
98
|
+
worker.onerror = (error) => this._handleError(workerId, error);
|
|
99
|
+
worker.onmessageerror = (error) => this._handleMessageError(workerId, error);
|
|
100
|
+
|
|
101
|
+
this.workers.set(workerId, workerInfo);
|
|
102
|
+
|
|
103
|
+
return workerId;
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.error('[WorkerPool] Failed to create worker:', error);
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Handle message from worker
|
|
112
|
+
* @private
|
|
113
|
+
* @param {string} workerId - Worker ID
|
|
114
|
+
* @param {MessageEvent} event - Message event
|
|
115
|
+
*/
|
|
116
|
+
_handleMessage(workerId, event) {
|
|
117
|
+
const { type, taskId, payload, error } = event.data;
|
|
118
|
+
const workerInfo = this.workers.get(workerId);
|
|
119
|
+
|
|
120
|
+
if (!workerInfo) return;
|
|
121
|
+
|
|
122
|
+
const task = this.activeTasks.get(taskId);
|
|
123
|
+
if (!task) return;
|
|
124
|
+
|
|
125
|
+
// Clear timeout
|
|
126
|
+
if (task.timeoutId) {
|
|
127
|
+
clearTimeout(task.timeoutId);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Update worker status
|
|
131
|
+
workerInfo.status = 'idle';
|
|
132
|
+
workerInfo.currentTask = null;
|
|
133
|
+
workerInfo.taskCount++;
|
|
134
|
+
|
|
135
|
+
// Remove from active tasks
|
|
136
|
+
this.activeTasks.delete(taskId);
|
|
137
|
+
|
|
138
|
+
// Resolve or reject the task
|
|
139
|
+
if (type === 'error' || error) {
|
|
140
|
+
task.status = TASK_STATUS.FAILED;
|
|
141
|
+
task.reject(new Error(error?.message || 'Worker error'));
|
|
142
|
+
} else {
|
|
143
|
+
task.status = TASK_STATUS.COMPLETED;
|
|
144
|
+
task.resolve(payload);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Process next task in queue
|
|
148
|
+
this._processQueue();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Handle worker error
|
|
153
|
+
* @private
|
|
154
|
+
* @param {string} workerId - Worker ID
|
|
155
|
+
* @param {ErrorEvent} error - Error event
|
|
156
|
+
*/
|
|
157
|
+
_handleError(workerId, error) {
|
|
158
|
+
console.error(`[WorkerPool] Worker ${workerId} error:`, error);
|
|
159
|
+
|
|
160
|
+
const workerInfo = this.workers.get(workerId);
|
|
161
|
+
if (workerInfo?.currentTask) {
|
|
162
|
+
const task = this.activeTasks.get(workerInfo.currentTask);
|
|
163
|
+
if (task) {
|
|
164
|
+
task.status = TASK_STATUS.FAILED;
|
|
165
|
+
task.reject(new Error(`Worker error: ${error.message}`));
|
|
166
|
+
this.activeTasks.delete(workerInfo.currentTask);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Terminate and remove the faulty worker
|
|
171
|
+
this._terminateWorker(workerId);
|
|
172
|
+
|
|
173
|
+
// Create a replacement if needed
|
|
174
|
+
if (this.workers.size < this.config.minWorkers) {
|
|
175
|
+
this._createWorker();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Process queue
|
|
179
|
+
this._processQueue();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Handle message error
|
|
184
|
+
* @private
|
|
185
|
+
* @param {string} workerId - Worker ID
|
|
186
|
+
* @param {ErrorEvent} error - Error event
|
|
187
|
+
*/
|
|
188
|
+
_handleMessageError(workerId, error) {
|
|
189
|
+
console.error(`[WorkerPool] Worker ${workerId} message error:`, error);
|
|
190
|
+
this._handleError(workerId, error);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Terminate a worker
|
|
195
|
+
* @private
|
|
196
|
+
* @param {string} workerId - Worker ID
|
|
197
|
+
*/
|
|
198
|
+
_terminateWorker(workerId) {
|
|
199
|
+
const workerInfo = this.workers.get(workerId);
|
|
200
|
+
if (workerInfo) {
|
|
201
|
+
workerInfo.worker.terminate();
|
|
202
|
+
this.workers.delete(workerId);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Get an available worker
|
|
208
|
+
* @private
|
|
209
|
+
* @returns {Object|null} Worker info or null if none available
|
|
210
|
+
*/
|
|
211
|
+
_getAvailableWorker() {
|
|
212
|
+
for (const workerInfo of this.workers.values()) {
|
|
213
|
+
if (workerInfo.status === 'idle') {
|
|
214
|
+
return workerInfo;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Process the task queue
|
|
222
|
+
* @private
|
|
223
|
+
*/
|
|
224
|
+
_processQueue() {
|
|
225
|
+
if (this.isTerminated || this.taskQueue.length === 0) return;
|
|
226
|
+
|
|
227
|
+
const availableWorker = this._getAvailableWorker();
|
|
228
|
+
if (!availableWorker) {
|
|
229
|
+
// Try to create a new worker if under max
|
|
230
|
+
if (this.workers.size < this.config.maxWorkers) {
|
|
231
|
+
const newWorkerId = this._createWorker();
|
|
232
|
+
this._assignTask(newWorkerId, this.taskQueue.shift());
|
|
233
|
+
}
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const task = this.taskQueue.shift();
|
|
238
|
+
this._assignTask(availableWorker.id, task);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Assign a task to a worker
|
|
243
|
+
* @private
|
|
244
|
+
* @param {string} workerId - Worker ID
|
|
245
|
+
* @param {Object} task - Task object
|
|
246
|
+
*/
|
|
247
|
+
_assignTask(workerId, task) {
|
|
248
|
+
const workerInfo = this.workers.get(workerId);
|
|
249
|
+
if (!workerInfo) {
|
|
250
|
+
task.reject(new Error('Worker not found'));
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
workerInfo.status = 'busy';
|
|
255
|
+
workerInfo.currentTask = task.id;
|
|
256
|
+
|
|
257
|
+
task.status = TASK_STATUS.RUNNING;
|
|
258
|
+
this.activeTasks.set(task.id, task);
|
|
259
|
+
|
|
260
|
+
// Set timeout
|
|
261
|
+
task.timeoutId = setTimeout(() => {
|
|
262
|
+
task.status = TASK_STATUS.FAILED;
|
|
263
|
+
task.reject(new Error(`Task ${task.id} timed out after ${this.config.taskTimeout}ms`));
|
|
264
|
+
this.activeTasks.delete(task.id);
|
|
265
|
+
|
|
266
|
+
// Reset worker
|
|
267
|
+
workerInfo.status = 'idle';
|
|
268
|
+
workerInfo.currentTask = null;
|
|
269
|
+
|
|
270
|
+
// Terminate and recreate worker
|
|
271
|
+
this._terminateWorker(workerId);
|
|
272
|
+
this._createWorker();
|
|
273
|
+
this._processQueue();
|
|
274
|
+
}, this.config.taskTimeout);
|
|
275
|
+
|
|
276
|
+
// Send task to worker
|
|
277
|
+
workerInfo.worker.postMessage({
|
|
278
|
+
type: 'task',
|
|
279
|
+
taskId: task.id,
|
|
280
|
+
payload: task.payload,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Execute a task in a worker
|
|
286
|
+
* @param {Object} payload - Task payload
|
|
287
|
+
* @returns {Promise<any>} Task result
|
|
288
|
+
*/
|
|
289
|
+
execute(payload) {
|
|
290
|
+
if (this.isTerminated) {
|
|
291
|
+
return Promise.reject(new Error('Worker pool has been terminated'));
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return new Promise((resolve, reject) => {
|
|
295
|
+
const task = {
|
|
296
|
+
id: `task-${++this.taskIdCounter}`,
|
|
297
|
+
payload,
|
|
298
|
+
status: TASK_STATUS.PENDING,
|
|
299
|
+
resolve,
|
|
300
|
+
reject,
|
|
301
|
+
timeoutId: null,
|
|
302
|
+
createdAt: Date.now(),
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
this.taskQueue.push(task);
|
|
306
|
+
this._processQueue();
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Execute multiple tasks in parallel
|
|
312
|
+
* @param {Array<Object>} payloads - Array of task payloads
|
|
313
|
+
* @returns {Promise<Array<any>>} Array of results
|
|
314
|
+
*/
|
|
315
|
+
executeAll(payloads) {
|
|
316
|
+
return Promise.all(payloads.map((payload) => this.execute(payload)));
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Get pool statistics
|
|
321
|
+
* @returns {Object} Pool statistics
|
|
322
|
+
*/
|
|
323
|
+
getStats() {
|
|
324
|
+
let idleWorkers = 0;
|
|
325
|
+
let busyWorkers = 0;
|
|
326
|
+
|
|
327
|
+
for (const workerInfo of this.workers.values()) {
|
|
328
|
+
if (workerInfo.status === 'idle') idleWorkers++;
|
|
329
|
+
else busyWorkers++;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return {
|
|
333
|
+
totalWorkers: this.workers.size,
|
|
334
|
+
idleWorkers,
|
|
335
|
+
busyWorkers,
|
|
336
|
+
queuedTasks: this.taskQueue.length,
|
|
337
|
+
activeTasks: this.activeTasks.size,
|
|
338
|
+
isTerminated: this.isTerminated,
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Terminate all workers and clear queue
|
|
344
|
+
*/
|
|
345
|
+
terminate() {
|
|
346
|
+
this.isTerminated = true;
|
|
347
|
+
|
|
348
|
+
// Clear queue
|
|
349
|
+
for (const task of this.taskQueue) {
|
|
350
|
+
task.status = TASK_STATUS.CANCELLED;
|
|
351
|
+
task.reject(new Error('Worker pool terminated'));
|
|
352
|
+
}
|
|
353
|
+
this.taskQueue = [];
|
|
354
|
+
|
|
355
|
+
// Cancel active tasks
|
|
356
|
+
for (const task of this.activeTasks.values()) {
|
|
357
|
+
if (task.timeoutId) clearTimeout(task.timeoutId);
|
|
358
|
+
task.status = TASK_STATUS.CANCELLED;
|
|
359
|
+
task.reject(new Error('Worker pool terminated'));
|
|
360
|
+
}
|
|
361
|
+
this.activeTasks.clear();
|
|
362
|
+
|
|
363
|
+
// Terminate all workers
|
|
364
|
+
for (const workerId of this.workers.keys()) {
|
|
365
|
+
this._terminateWorker(workerId);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Singleton instance
|
|
371
|
+
let globalPool = null;
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Get or create global worker pool
|
|
375
|
+
* @param {Object} config - Pool configuration
|
|
376
|
+
* @returns {WorkerPool} Global worker pool instance
|
|
377
|
+
*/
|
|
378
|
+
export function getWorkerPool(config = {}) {
|
|
379
|
+
if (!globalPool) {
|
|
380
|
+
globalPool = new WorkerPool(config);
|
|
381
|
+
}
|
|
382
|
+
return globalPool;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Terminate global worker pool
|
|
387
|
+
*/
|
|
388
|
+
export function terminateWorkerPool() {
|
|
389
|
+
if (globalPool) {
|
|
390
|
+
globalPool.terminate();
|
|
391
|
+
globalPool = null;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
export { WorkerPool, TASK_STATUS };
|
|
396
|
+
export default WorkerPool;
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Docsify + Visualify Bundled Distribution
|
|
3
|
+
* @module docsify/bundle
|
|
4
|
+
*
|
|
5
|
+
* UMD bundle entry point that combines Docsify with Visualify plugin.
|
|
6
|
+
* Auto-initializes if Docsify configuration is present.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* // In HTML:
|
|
10
|
+
* <script src="visualify-docsify.min.js"></script>
|
|
11
|
+
* <script>
|
|
12
|
+
* window.$docsify = {
|
|
13
|
+
* // Docsify configuration
|
|
14
|
+
* };
|
|
15
|
+
* </script>
|
|
16
|
+
* <script src="https://cdn.jsdelivr.net/npm/docsify@4/lib/docsify.min.js"></script>
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import DocsifyPlugin from './plugin';
|
|
20
|
+
import { processMarkdown, processVisualifyBlocks, extractConfigs } from './markdown';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Bundle version (replaced during build)
|
|
24
|
+
* @type {string}
|
|
25
|
+
*/
|
|
26
|
+
const VERSION = process.env.VISUALIFY_VERSION || 'dev';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Check if running in browser environment
|
|
30
|
+
* @type {boolean}
|
|
31
|
+
*/
|
|
32
|
+
const isBrowser = typeof window !== 'undefined';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Default Docsify configuration with Visualify support
|
|
36
|
+
* @type {Object}
|
|
37
|
+
*/
|
|
38
|
+
const DEFAULT_DOCSIFY_CONFIG = {
|
|
39
|
+
// Enable markdown plugin
|
|
40
|
+
markdown: {
|
|
41
|
+
renderer: {
|
|
42
|
+
code: function (code, lang) {
|
|
43
|
+
if (lang === 'visualify') {
|
|
44
|
+
return processMarkdown(code);
|
|
45
|
+
}
|
|
46
|
+
// Default code rendering
|
|
47
|
+
return (
|
|
48
|
+
'<pre v-pre><code class="lang-' +
|
|
49
|
+
lang +
|
|
50
|
+
'">' +
|
|
51
|
+
code +
|
|
52
|
+
'</code></pre>'
|
|
53
|
+
);
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
// Add Visualify plugin
|
|
58
|
+
plugins: [DocsifyPlugin.install],
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Merge user config with defaults
|
|
63
|
+
* @param {Object} userConfig - User's Docsify configuration
|
|
64
|
+
* @returns {Object} Merged configuration
|
|
65
|
+
*/
|
|
66
|
+
function mergeConfig(userConfig = {}) {
|
|
67
|
+
const merged = {
|
|
68
|
+
...DEFAULT_DOCSIFY_CONFIG,
|
|
69
|
+
...userConfig,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// Merge markdown renderer carefully
|
|
73
|
+
if (userConfig.markdown) {
|
|
74
|
+
if (typeof userConfig.markdown === 'function') {
|
|
75
|
+
// User provided a custom markdown function
|
|
76
|
+
const userMarkdown = userConfig.markdown;
|
|
77
|
+
merged.markdown = function (marked, renderer) {
|
|
78
|
+
const result = userMarkdown(marked, renderer);
|
|
79
|
+
// Ensure visualify code blocks are handled
|
|
80
|
+
const originalCode = renderer.code;
|
|
81
|
+
renderer.code = function (code, lang) {
|
|
82
|
+
if (lang === 'visualify') {
|
|
83
|
+
return processMarkdown(code);
|
|
84
|
+
}
|
|
85
|
+
return originalCode ? originalCode.call(this, code, lang) : code;
|
|
86
|
+
};
|
|
87
|
+
return result;
|
|
88
|
+
};
|
|
89
|
+
} else if (userConfig.markdown.renderer) {
|
|
90
|
+
// Merge renderers
|
|
91
|
+
merged.markdown = {
|
|
92
|
+
...userConfig.markdown,
|
|
93
|
+
renderer: {
|
|
94
|
+
...DEFAULT_DOCSIFY_CONFIG.markdown.renderer,
|
|
95
|
+
...userConfig.markdown.renderer,
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Merge plugins array
|
|
102
|
+
if (userConfig.plugins) {
|
|
103
|
+
merged.plugins = [DocsifyPlugin.install, ...userConfig.plugins];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return merged;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Initialize Docsify with Visualify plugin
|
|
111
|
+
* @param {Object} [config] - Optional configuration override
|
|
112
|
+
*/
|
|
113
|
+
function init(config = {}) {
|
|
114
|
+
if (!isBrowser) {
|
|
115
|
+
console.warn('[VisualifyDocs] init() can only be called in browser environment');
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Merge with existing $docsify config if present
|
|
120
|
+
const existingConfig = window.$docsify || {};
|
|
121
|
+
window.$docsify = mergeConfig({ ...existingConfig, ...config });
|
|
122
|
+
|
|
123
|
+
console.log('[VisualifyDocs] Configuration applied. Load Docsify to initialize.');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Auto-initialize if Docsify is already present
|
|
128
|
+
*/
|
|
129
|
+
function autoInit() {
|
|
130
|
+
if (!isBrowser) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Check if Docsify config exists
|
|
135
|
+
if (window.$docsify) {
|
|
136
|
+
// Merge our config with existing
|
|
137
|
+
window.$docsify = mergeConfig(window.$docsify);
|
|
138
|
+
console.log('[VisualifyDocs] Auto-initialized with existing Docsify config');
|
|
139
|
+
} else {
|
|
140
|
+
// Set up default config for when Docsify loads
|
|
141
|
+
window.$docsify = DEFAULT_DOCSIFY_CONFIG;
|
|
142
|
+
console.log('[VisualifyDocs] Default configuration set');
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Main bundle exports
|
|
148
|
+
*/
|
|
149
|
+
const VisualifyDocsifyBundle = {
|
|
150
|
+
// Version
|
|
151
|
+
VERSION,
|
|
152
|
+
|
|
153
|
+
// Core plugin
|
|
154
|
+
plugin: DocsifyPlugin,
|
|
155
|
+
|
|
156
|
+
// Markdown processing utilities
|
|
157
|
+
markdown: {
|
|
158
|
+
process: processMarkdown,
|
|
159
|
+
processBlocks: processVisualifyBlocks,
|
|
160
|
+
extractConfigs,
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
// Configuration
|
|
164
|
+
config: DEFAULT_DOCSIFY_CONFIG,
|
|
165
|
+
|
|
166
|
+
// Initialization
|
|
167
|
+
init,
|
|
168
|
+
mergeConfig,
|
|
169
|
+
autoInit,
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Mount all charts in a container
|
|
173
|
+
* @param {Element} [container] - Container element
|
|
174
|
+
*/
|
|
175
|
+
mountAll(container) {
|
|
176
|
+
return DocsifyPlugin.mountAllCharts(container);
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Cleanup charts in a container
|
|
181
|
+
* @param {Element} [container] - Container element
|
|
182
|
+
*/
|
|
183
|
+
cleanup(container) {
|
|
184
|
+
return DocsifyPlugin.cleanupCharts(container);
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
// Auto-initialize in browser
|
|
189
|
+
if (isBrowser) {
|
|
190
|
+
// Wait for DOM ready
|
|
191
|
+
if (document.readyState === 'loading') {
|
|
192
|
+
document.addEventListener('DOMContentLoaded', autoInit);
|
|
193
|
+
} else {
|
|
194
|
+
autoInit();
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// UMD export pattern
|
|
199
|
+
(function (root, factory) {
|
|
200
|
+
if (typeof define === 'function' && define.amd) {
|
|
201
|
+
// AMD
|
|
202
|
+
define([], factory);
|
|
203
|
+
} else if (typeof module === 'object' && module.exports) {
|
|
204
|
+
// CommonJS
|
|
205
|
+
module.exports = factory();
|
|
206
|
+
} else {
|
|
207
|
+
// Browser global
|
|
208
|
+
root.VisualifyDocsify = factory();
|
|
209
|
+
}
|
|
210
|
+
})(typeof self !== 'undefined' ? self : this, function () {
|
|
211
|
+
return VisualifyDocsifyBundle;
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
export default VisualifyDocsifyBundle;
|
|
215
|
+
export { init, mergeConfig, autoInit, DocsifyPlugin, processMarkdown };
|