@reicek/neataptic-ts 0.1.24 → 0.1.26
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/.github/copilot-instructions.md +11 -0
- package/.github/skills/trace-analyzer-extension/SKILL.md +3 -3
- package/.github/skills/trace-analyzer-extension/assets/extension-checklist.md +1 -1
- package/.github/skills/trace-analyzer-extension/references/analyzer-extension-workflow.md +1 -1
- package/.github/skills/trace-audit-reporting/SKILL.md +3 -3
- package/.github/skills/trace-audit-reporting/references/trace-analysis-workflow.md +1 -1
- package/.github/workflows/ci.yml +3 -3
- package/.github/workflows/deploy-pages.yml +6 -6
- package/.github/workflows/manual_release_pipeline.yml +3 -3
- package/.github/workflows/publish.yml +18 -19
- package/.github/workflows/release_dispatch.yml +3 -3
- package/package.json +26 -20
- package/plans/Flappy_Bird_Folder_Documentation_Pass.md +4 -4
- package/plans/README.md +24 -0
- package/plans/Roadmap.md +62 -40
- package/plans/analyze-trace-solid-split.plans.md +66 -0
- package/plans/architecture-solid-split.plans.md +9 -15
- package/plans/asciiMaze-typescript-repair.plans.md +1 -1
- package/plans/generate-docs-solid-split.plans.md +87 -0
- package/plans/methods-docs.plans.md +25 -1
- package/plans/methods-solid-split.plans.md +14 -14
- package/plans/neat-docs.plans.md +9 -1
- package/plans/neat-test-surface-repair.plans.md +1 -1
- package/plans/render-docs-html-solid-split.plans.md +68 -0
- package/plans/src-no-explicit-any-cleanup.plans.md +1 -1
- package/plans/utils-docs.plans.md +6 -1
- package/scripts/analyze-trace/analyze-trace.analysis.ts +479 -0
- package/scripts/analyze-trace/analyze-trace.constants.ts +35 -0
- package/scripts/analyze-trace/analyze-trace.io.ts +69 -0
- package/scripts/analyze-trace/analyze-trace.report.ts +100 -0
- package/scripts/analyze-trace/analyze-trace.shared.ts +116 -0
- package/scripts/analyze-trace/analyze-trace.ts +45 -0
- package/scripts/analyze-trace/analyze-trace.types.ts +72 -0
- package/scripts/assets/theme.css +80 -23
- package/scripts/copy-examples.ts +239 -0
- package/scripts/export-onnx.ts +223 -0
- package/scripts/generate-bench-tables.ts +378 -37
- package/scripts/generate-docs/generate-docs.constants.ts +107 -0
- package/scripts/generate-docs/generate-docs.order.ts +355 -0
- package/scripts/generate-docs/generate-docs.state.ts +31 -0
- package/scripts/generate-docs/generate-docs.targets.ts +165 -0
- package/scripts/generate-docs/generate-docs.ts +63 -0
- package/scripts/generate-docs/generate-docs.types.ts +112 -0
- package/scripts/generate-docs/output/generate-docs.output.folder-index.utils.ts +167 -0
- package/scripts/generate-docs/output/generate-docs.output.ordering.utils.ts +353 -0
- package/scripts/generate-docs/output/generate-docs.output.readme.utils.ts +420 -0
- package/scripts/generate-docs/output/generate-docs.output.ts +123 -0
- package/scripts/generate-docs/output/generate-docs.output.warnings.utils.ts +219 -0
- package/scripts/generate-docs/symbols/generate-docs.symbols.collection.utils.ts +365 -0
- package/scripts/generate-docs/symbols/generate-docs.symbols.jsdoc.utils.ts +373 -0
- package/scripts/generate-docs/symbols/generate-docs.symbols.normalize.utils.ts +155 -0
- package/scripts/generate-docs/symbols/generate-docs.symbols.render.utils.ts +149 -0
- package/scripts/generate-docs/symbols/generate-docs.symbols.signature.utils.ts +289 -0
- package/scripts/generate-docs/symbols/generate-docs.symbols.ts +11 -0
- package/scripts/mermaid-cli.mjs +102 -22
- package/scripts/mermaid-cli.ts +736 -0
- package/scripts/render-docs-html/render-docs-html.assets.ts +54 -0
- package/scripts/render-docs-html/render-docs-html.mermaid.ts +245 -0
- package/scripts/{render-docs-html.sidebar.ts → render-docs-html/render-docs-html.navigation.ts} +141 -144
- package/scripts/render-docs-html/render-docs-html.pages.ts +333 -0
- package/scripts/render-docs-html/render-docs-html.shared.ts +333 -0
- package/scripts/render-docs-html/render-docs-html.types.ts +42 -0
- package/scripts/render-docs-html.ts +23 -587
- package/scripts/run-docs.ts +238 -0
- package/scripts/write-dist-docs-pkg.ts +40 -0
- package/src/README.md +75 -75
- package/src/architecture/connection/README.md +5 -5
- package/src/architecture/layer/README.md +508 -508
- package/src/architecture/network/README.md +1458 -1458
- package/src/architecture/network/activate/README.md +694 -694
- package/src/architecture/network/bootstrap/README.md +77 -77
- package/src/architecture/network/connect/README.md +74 -74
- package/src/architecture/network/deterministic/README.md +135 -135
- package/src/architecture/network/evolve/README.md +364 -364
- package/src/architecture/network/gating/README.md +130 -130
- package/src/architecture/network/genetic/README.md +399 -399
- package/src/architecture/network/mutate/README.md +897 -897
- package/src/architecture/network/onnx/README.md +720 -720
- package/src/architecture/network/onnx/export/README.md +728 -728
- package/src/architecture/network/onnx/export/layers/README.md +450 -450
- package/src/architecture/network/onnx/import/README.md +618 -618
- package/src/architecture/network/onnx/schema/README.md +32 -32
- package/src/architecture/network/prune/README.md +245 -245
- package/src/architecture/network/remove/README.md +135 -135
- package/src/architecture/network/runtime/README.md +106 -106
- package/src/architecture/network/serialize/README.md +542 -542
- package/src/architecture/network/slab/README.md +608 -608
- package/src/architecture/network/standalone/README.md +212 -212
- package/src/architecture/network/stats/README.md +84 -84
- package/src/architecture/network/topology/README.md +465 -465
- package/src/architecture/network/training/README.md +200 -200
- package/src/architecture/node/README.md +5 -5
- package/src/architecture/nodePool/README.md +14 -14
- package/src/methods/README.md +99 -99
- package/src/methods/activation/README.md +189 -189
- package/src/methods/cost/README.md +131 -131
- package/src/methods/rate/README.md +86 -86
- package/src/multithreading/README.md +77 -77
- package/src/multithreading/workers/browser/README.md +8 -8
- package/src/multithreading/workers/node/README.md +8 -8
- package/src/neat/README.md +148 -148
- package/src/neat/adaptive/README.md +120 -120
- package/src/neat/adaptive/acceptance/README.md +40 -40
- package/src/neat/adaptive/complexity/README.md +137 -137
- package/src/neat/adaptive/core/README.md +197 -197
- package/src/neat/adaptive/lineage/README.md +90 -90
- package/src/neat/adaptive/mutation/README.md +284 -284
- package/src/neat/compat/README.md +43 -43
- package/src/neat/compat/core/README.md +90 -90
- package/src/neat/diversity/README.md +35 -35
- package/src/neat/diversity/core/README.md +88 -88
- package/src/neat/evaluate/README.md +85 -85
- package/src/neat/evaluate/auto-distance/README.md +75 -75
- package/src/neat/evaluate/entropy-compat/README.md +37 -37
- package/src/neat/evaluate/entropy-sharing/README.md +43 -43
- package/src/neat/evaluate/fitness/README.md +23 -23
- package/src/neat/evaluate/novelty/README.md +120 -120
- package/src/neat/evaluate/objectives/README.md +17 -17
- package/src/neat/evaluate/shared/README.md +94 -94
- package/src/neat/evolve/README.md +96 -96
- package/src/neat/evolve/adaptive/README.md +60 -60
- package/src/neat/evolve/objectives/README.md +63 -63
- package/src/neat/evolve/offspring/README.md +56 -56
- package/src/neat/evolve/population/README.md +171 -171
- package/src/neat/evolve/runtime/README.md +79 -79
- package/src/neat/evolve/speciation/README.md +74 -74
- package/src/neat/evolve/warnings/README.md +10 -10
- package/src/neat/export/README.md +114 -114
- package/src/neat/helpers/README.md +50 -50
- package/src/neat/init/README.md +9 -9
- package/src/neat/lineage/core/README.md +101 -101
- package/src/neat/multiobjective/category/README.md +74 -74
- package/src/neat/multiobjective/crowding/README.md +272 -272
- package/src/neat/multiobjective/dominance/README.md +171 -171
- package/src/neat/multiobjective/fronts/README.md +68 -68
- package/src/neat/multiobjective/metrics/README.md +43 -43
- package/src/neat/multiobjective/objectives/README.md +31 -31
- package/src/neat/multiobjective/shared/README.md +27 -27
- package/src/neat/mutation/README.md +97 -97
- package/src/neat/mutation/add-conn/README.md +115 -115
- package/src/neat/mutation/add-node/README.md +126 -126
- package/src/neat/mutation/flow/README.md +149 -149
- package/src/neat/mutation/repair/README.md +185 -185
- package/src/neat/mutation/select/README.md +117 -117
- package/src/neat/mutation/shared/README.md +32 -32
- package/src/neat/objectives/README.md +25 -25
- package/src/neat/objectives/core/README.md +67 -67
- package/src/neat/pruning/README.md +40 -40
- package/src/neat/pruning/core/README.md +171 -171
- package/src/neat/pruning/facade/README.md +32 -32
- package/src/neat/rng/README.md +104 -104
- package/src/neat/rng/core/README.md +137 -137
- package/src/neat/rng/facade/README.md +50 -50
- package/src/neat/selection/README.md +111 -111
- package/src/neat/selection/core/README.md +227 -227
- package/src/neat/selection/facade/README.md +61 -61
- package/src/neat/shared/README.md +163 -163
- package/src/neat/speciation/README.md +31 -31
- package/src/neat/speciation/threshold/README.md +35 -35
- package/src/neat/species/README.md +25 -25
- package/src/neat/species/core/README.md +20 -20
- package/src/neat/species/core/shared/README.md +18 -18
- package/src/neat/species/history/context/README.md +22 -22
- package/src/neat/telemetry/accessors/README.md +58 -58
- package/src/neat/telemetry/exports/README.md +233 -233
- package/src/neat/telemetry/facade/README.md +252 -252
- package/src/neat/telemetry/facade/archive/README.md +57 -57
- package/src/neat/telemetry/facade/buffer/README.md +43 -43
- package/src/neat/telemetry/facade/lineage/README.md +12 -12
- package/src/neat/telemetry/facade/objectives/README.md +44 -44
- package/src/neat/telemetry/facade/runtime/README.md +26 -26
- package/src/neat/telemetry/facade/species/README.md +27 -27
- package/src/neat/telemetry/metrics/README.md +696 -696
- package/src/neat/telemetry/recorder/README.md +57 -57
- package/src/neat/telemetry/types/README.md +32 -32
- package/src/neat/topology-intent/README.md +75 -75
- package/src/utils/README.md +193 -193
- package/test/examples/asciiMaze/browser-entry/README.md +92 -92
- package/test/examples/asciiMaze/dashboardManager/README.md +109 -109
- package/test/examples/asciiMaze/dashboardManager/telemetry/README.md +28 -28
- package/test/examples/asciiMaze/evolutionEngine/README.md +1527 -1527
- package/test/examples/asciiMaze/mazeMovement/README.md +105 -105
- package/test/examples/asciiMaze/mazeMovement/finalization/README.md +16 -16
- package/test/examples/asciiMaze/mazeMovement/policy/README.md +57 -57
- package/test/examples/asciiMaze/mazeMovement/runtime/README.md +52 -52
- package/test/examples/asciiMaze/mazeMovement/shaping/README.md +46 -46
- package/test/examples/flappy_bird/browser-entry/README.md +508 -508
- package/test/examples/flappy_bird/browser-entry/host/README.md +101 -101
- package/test/examples/flappy_bird/browser-entry/host/resize/README.md +144 -144
- package/test/examples/flappy_bird/browser-entry/network-view/README.md +194 -194
- package/test/examples/flappy_bird/browser-entry/playback/README.md +278 -278
- package/test/examples/flappy_bird/browser-entry/playback/background/README.md +129 -129
- package/test/examples/flappy_bird/browser-entry/playback/background/ground-grid/README.md +502 -502
- package/test/examples/flappy_bird/browser-entry/playback/frame-render/README.md +139 -139
- package/test/examples/flappy_bird/browser-entry/playback/snapshot/README.md +10 -10
- package/test/examples/flappy_bird/browser-entry/playback/trail/README.md +43 -43
- package/test/examples/flappy_bird/browser-entry/playback/worker-channel/README.md +30 -30
- package/test/examples/flappy_bird/browser-entry/runtime/README.md +59 -59
- package/test/examples/flappy_bird/browser-entry/visualization/README.md +276 -276
- package/test/examples/flappy_bird/browser-entry/worker-channel/README.md +16 -16
- package/test/examples/flappy_bird/constants/README.md +1070 -1070
- package/test/examples/flappy_bird/environment/README.md +22 -22
- package/test/examples/flappy_bird/evaluation/README.md +32 -32
- package/test/examples/flappy_bird/evaluation/rollout/README.md +141 -141
- package/test/examples/flappy_bird/flappy-evolution-worker/README.md +425 -425
- package/test/examples/flappy_bird/simulation-shared/README.md +170 -170
- package/test/examples/flappy_bird/simulation-shared/observation/README.md +109 -109
- package/test/examples/flappy_bird/trainer/README.md +325 -325
- package/test/examples/flappy_bird/trainer/evaluation/README.md +74 -74
- package/scripts/analyze-trace.ts +0 -590
- package/scripts/copy-examples.mjs +0 -114
- package/scripts/export-onnx.mjs +0 -86
- package/scripts/generate-bench-tables.mjs +0 -182
- package/scripts/generate-docs.ts +0 -2900
- package/scripts/write-dist-docs-pkg.mjs +0 -16
|
@@ -1,599 +1,35 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Converts every README.md inside docs/
|
|
2
|
+
* Converts every README.md inside docs/ into an index.html in the same directory.
|
|
3
3
|
* Usage: npm run docs:html
|
|
4
|
+
*
|
|
5
|
+
* This file intentionally stays orchestration-first. The folder-owned boundary
|
|
6
|
+
* under `scripts/render-docs-html/` owns navigation, Markdown page rendering,
|
|
7
|
+
* static assets, and Mermaid validation.
|
|
4
8
|
*/
|
|
5
|
-
import { spawn } from 'node:child_process';
|
|
6
|
-
import { mkdtemp, rm } from 'node:fs/promises';
|
|
7
|
-
import os from 'node:os';
|
|
8
|
-
import fg from 'fast-glob';
|
|
9
|
-
import path from 'path';
|
|
10
|
-
import fs from 'fs-extra';
|
|
11
|
-
import { marked } from 'marked';
|
|
12
|
-
import {
|
|
13
|
-
buildDocsSidebarHtml,
|
|
14
|
-
buildExamplesTocLinksHtml,
|
|
15
|
-
} from './render-docs-html.sidebar.js';
|
|
16
|
-
|
|
17
|
-
const DOCS_DIR = path.resolve('docs');
|
|
18
|
-
const THEME_CSS_SOURCE_PATH = path.resolve('scripts', 'assets', 'theme.css');
|
|
19
|
-
const THEME_CSS_OUTPUT_PATH = path.join(DOCS_DIR, 'assets', 'theme.css');
|
|
20
|
-
const MERMAID_MODULE_SOURCE_PATH = path.resolve(
|
|
21
|
-
'node_modules',
|
|
22
|
-
'mermaid',
|
|
23
|
-
'dist',
|
|
24
|
-
'mermaid.esm.min.mjs',
|
|
25
|
-
);
|
|
26
|
-
const MERMAID_DIST_SOURCE_DIR = path.resolve('node_modules', 'mermaid', 'dist');
|
|
27
|
-
const MERMAID_MODULE_OUTPUT_PATH = path.join(
|
|
28
|
-
DOCS_DIR,
|
|
29
|
-
'assets',
|
|
30
|
-
'vendor',
|
|
31
|
-
'mermaid.esm.min.mjs',
|
|
32
|
-
);
|
|
33
|
-
const MERMAID_DIST_OUTPUT_DIR = path.join(DOCS_DIR, 'assets', 'vendor');
|
|
34
|
-
const MERMAID_CLI_SCRIPT_PATH = path.resolve('scripts', 'mermaid-cli.mjs');
|
|
35
|
-
const NN_IMAGE_SOURCE_PATH = path.resolve('nn.jpg');
|
|
36
|
-
const NN_IMAGE_FALLBACK_SOURCE_PATH = path.resolve(
|
|
37
|
-
'scripts',
|
|
38
|
-
'assets',
|
|
39
|
-
'nn.jpg',
|
|
40
|
-
);
|
|
41
|
-
const NN_IMAGE_OUTPUT_PATH = path.join(DOCS_DIR, 'nn.jpg');
|
|
42
|
-
const GITHUB_REPOSITORY_BLOB_BASE_URL =
|
|
43
|
-
'https://github.com/reicek/NeatapticTS/blob/develop';
|
|
44
|
-
const GITHUB_REPOSITORY_TREE_BASE_URL =
|
|
45
|
-
'https://github.com/reicek/NeatapticTS/tree/develop';
|
|
46
|
-
|
|
47
|
-
const RETRIABLE_FILE_SYSTEM_ERROR_CODES = new Set([
|
|
48
|
-
'UNKNOWN',
|
|
49
|
-
'EPERM',
|
|
50
|
-
'EBUSY',
|
|
51
|
-
'EACCES',
|
|
52
|
-
]);
|
|
53
|
-
const DOCS_WRITE_MAX_ATTEMPTS = 6;
|
|
54
|
-
const DOCS_WRITE_INITIAL_RETRY_DELAY_MS = 120;
|
|
55
|
-
|
|
56
|
-
interface PageMeta {
|
|
57
|
-
abs: string;
|
|
58
|
-
relDir: string;
|
|
59
|
-
title: string;
|
|
60
|
-
markdown: string;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
interface MermaidBlockReference {
|
|
64
|
-
readmePath: string;
|
|
65
|
-
blockNumber: number;
|
|
66
|
-
diagram: string;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function isRetriableFileSystemError(
|
|
70
|
-
error: unknown,
|
|
71
|
-
): error is NodeJS.ErrnoException {
|
|
72
|
-
if (!(error instanceof Error)) return false;
|
|
73
|
-
const code = (error as NodeJS.ErrnoException).code;
|
|
74
|
-
if (!code) return false;
|
|
75
|
-
return RETRIABLE_FILE_SYSTEM_ERROR_CODES.has(code);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async function waitForRetryDelay(delayMilliseconds: number): Promise<void> {
|
|
79
|
-
await new Promise((resolve) => {
|
|
80
|
-
setTimeout(resolve, delayMilliseconds);
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
async function writeFileWithRetry(
|
|
85
|
-
filePath: string,
|
|
86
|
-
content: string,
|
|
87
|
-
encoding: BufferEncoding,
|
|
88
|
-
): Promise<void> {
|
|
89
|
-
let retryDelayMilliseconds = DOCS_WRITE_INITIAL_RETRY_DELAY_MS;
|
|
90
|
-
|
|
91
|
-
for (
|
|
92
|
-
let attemptNumber = 1;
|
|
93
|
-
attemptNumber <= DOCS_WRITE_MAX_ATTEMPTS;
|
|
94
|
-
attemptNumber += 1
|
|
95
|
-
) {
|
|
96
|
-
try {
|
|
97
|
-
await fs.writeFile(filePath, content, encoding);
|
|
98
|
-
return;
|
|
99
|
-
} catch (error: unknown) {
|
|
100
|
-
const canRetry =
|
|
101
|
-
isRetriableFileSystemError(error) &&
|
|
102
|
-
attemptNumber < DOCS_WRITE_MAX_ATTEMPTS;
|
|
103
|
-
if (!canRetry) {
|
|
104
|
-
throw error;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
await waitForRetryDelay(retryDelayMilliseconds);
|
|
108
|
-
retryDelayMilliseconds = Math.min(retryDelayMilliseconds * 2, 1_000);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
async function ensureThemeCss(): Promise<void> {
|
|
114
|
-
// Step 1: Ensure destination directory exists.
|
|
115
|
-
await fs.ensureDir(path.dirname(THEME_CSS_OUTPUT_PATH));
|
|
116
|
-
|
|
117
|
-
// Step 2: Copy static theme stylesheet used by generated docs pages.
|
|
118
|
-
await fs.copyFile(THEME_CSS_SOURCE_PATH, THEME_CSS_OUTPUT_PATH);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
async function ensureMermaidModule(): Promise<void> {
|
|
122
|
-
// Step 1: Skip Mermaid bootstrapping when the browser bundle is unavailable.
|
|
123
|
-
const hasMermaidModule = await fs.pathExists(MERMAID_MODULE_SOURCE_PATH);
|
|
124
|
-
if (!hasMermaidModule) return;
|
|
125
|
-
|
|
126
|
-
// Step 2: Copy the full Mermaid dist bundle so transitive chunk imports load.
|
|
127
|
-
await fs.ensureDir(MERMAID_DIST_OUTPUT_DIR);
|
|
128
|
-
await fs.copy(MERMAID_DIST_SOURCE_DIR, MERMAID_DIST_OUTPUT_DIR, {
|
|
129
|
-
overwrite: true,
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function buildDocsLayoutInteractionScript(): string {
|
|
134
|
-
return `<script>
|
|
135
|
-
const docsPanels = Array.from(document.querySelectorAll('.docs-panel'));
|
|
136
|
-
|
|
137
|
-
function setActiveDocsPanel(nextPanel) {
|
|
138
|
-
docsPanels.forEach((panel) => {
|
|
139
|
-
panel.classList.toggle('is-active', panel === nextPanel);
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
document.addEventListener('click', (event) => {
|
|
144
|
-
const target = event.target;
|
|
145
|
-
if (!(target instanceof Element)) {
|
|
146
|
-
setActiveDocsPanel(null);
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const activePanel = target.closest('.docs-panel');
|
|
151
|
-
setActiveDocsPanel(activePanel instanceof HTMLElement ? activePanel : null);
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
document.addEventListener('keydown', (event) => {
|
|
155
|
-
if (event.key === 'Escape') {
|
|
156
|
-
setActiveDocsPanel(null);
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
</script>`;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
async function ensureStaticDocsAssets(): Promise<void> {
|
|
163
|
-
// Step 1: Ensure core theme assets are present.
|
|
164
|
-
await ensureThemeCss();
|
|
165
|
-
await ensureMermaidModule();
|
|
166
|
-
|
|
167
|
-
// Step 2: Ensure the README hero image resolves when served from `/docs/`.
|
|
168
|
-
// The root README is copied into `docs/README.md`, so `<img src="nn.jpg">`
|
|
169
|
-
// becomes a request for `/docs/nn.jpg` when hosted under that base path.
|
|
170
|
-
const hasRootImage = await fs.pathExists(NN_IMAGE_SOURCE_PATH);
|
|
171
|
-
const hasFallbackImage = await fs.pathExists(NN_IMAGE_FALLBACK_SOURCE_PATH);
|
|
172
|
-
const sourcePath = hasRootImage
|
|
173
|
-
? NN_IMAGE_SOURCE_PATH
|
|
174
|
-
: hasFallbackImage
|
|
175
|
-
? NN_IMAGE_FALLBACK_SOURCE_PATH
|
|
176
|
-
: undefined;
|
|
177
9
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
.replace(/-{2,}/g, '-');
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
function escapeHtml(value: string): string {
|
|
191
|
-
return value
|
|
192
|
-
.replace(/&/g, '&')
|
|
193
|
-
.replace(/</g, '<')
|
|
194
|
-
.replace(/>/g, '>')
|
|
195
|
-
.replace(/"/g, '"')
|
|
196
|
-
.replace(/'/g, ''');
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function buildMermaidBootstrapScript(relToRoot: string): string {
|
|
200
|
-
const mermaidModuleHref =
|
|
201
|
-
(relToRoot ? `${relToRoot}/` : '') + 'assets/vendor/mermaid.esm.min.mjs';
|
|
202
|
-
|
|
203
|
-
return `<script type="module">
|
|
204
|
-
import mermaid from "${mermaidModuleHref}";
|
|
205
|
-
|
|
206
|
-
mermaid.initialize({
|
|
207
|
-
startOnLoad: false,
|
|
208
|
-
securityLevel: 'loose',
|
|
209
|
-
theme: 'base',
|
|
210
|
-
themeVariables: {
|
|
211
|
-
darkMode: true,
|
|
212
|
-
background: '#121a24',
|
|
213
|
-
primaryColor: '#102131',
|
|
214
|
-
primaryTextColor: '#d7e4f3',
|
|
215
|
-
primaryBorderColor: '#5ec8ff',
|
|
216
|
-
secondaryColor: '#0f1722',
|
|
217
|
-
secondaryTextColor: '#d7e4f3',
|
|
218
|
-
secondaryBorderColor: '#5ec8ff',
|
|
219
|
-
tertiaryColor: '#16283a',
|
|
220
|
-
tertiaryTextColor: '#d7e4f3',
|
|
221
|
-
tertiaryBorderColor: '#ffbf69',
|
|
222
|
-
mainBkg: '#0f1722',
|
|
223
|
-
nodeBorder: '#5ec8ff',
|
|
224
|
-
clusterBkg: '#102131',
|
|
225
|
-
clusterBorder: '#5ec8ff',
|
|
226
|
-
lineColor: '#5ec8ff',
|
|
227
|
-
edgeLabelBackground: '#0f1722',
|
|
228
|
-
textColor: '#d7e4f3',
|
|
229
|
-
fontFamily: 'Open Sans, sans-serif'
|
|
230
|
-
}
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
try {
|
|
234
|
-
await mermaid.run({ querySelector: '.mermaid-diagram' });
|
|
235
|
-
} catch (error) {
|
|
236
|
-
console.error('[docs] Mermaid render failed.', error);
|
|
237
|
-
}
|
|
238
|
-
</script>`;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
function buildRelativeDocsHref(currentDir: string, targetDir: string): string {
|
|
242
|
-
const relLink = path.posix.relative(currentDir || '.', targetDir || '.') || '.';
|
|
243
|
-
return (relLink === '.' ? '.' : relLink) + '/index.html';
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
function isExternalOrAnchorHref(href: string): boolean {
|
|
247
|
-
return (
|
|
248
|
-
/^[a-z][a-z0-9+.-]*:/i.test(href) ||
|
|
249
|
-
href.startsWith('//') ||
|
|
250
|
-
href.startsWith('#')
|
|
251
|
-
);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
function normalizeRepoRelativeHref(href: string): string {
|
|
255
|
-
return href
|
|
256
|
-
.trim()
|
|
257
|
-
.replace(/\\/g, '/')
|
|
258
|
-
.replace(/^\.\//, '')
|
|
259
|
-
.replace(/^\//, '')
|
|
260
|
-
.replace(/\/{2,}/g, '/');
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
function hasCompiledDocsPage(relativeDirectoryPath: string): boolean {
|
|
264
|
-
const normalizedDirectoryPath = relativeDirectoryPath.replace(/\/$/, '');
|
|
265
|
-
if (!normalizedDirectoryPath) {
|
|
266
|
-
return false;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
return fs.existsSync(path.resolve(DOCS_DIR, normalizedDirectoryPath, 'index.html'));
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
function buildGitHubRepositoryHref(repoRelativePath: string): string {
|
|
273
|
-
const normalizedPath = normalizeRepoRelativeHref(repoRelativePath).replace(
|
|
274
|
-
/\/$/,
|
|
275
|
-
'',
|
|
276
|
-
);
|
|
277
|
-
const absoluteRepositoryPath = path.resolve(normalizedPath);
|
|
278
|
-
const pathExistsInRepository = fs.existsSync(absoluteRepositoryPath);
|
|
279
|
-
const urlBase = pathExistsInRepository && fs.statSync(absoluteRepositoryPath).isFile()
|
|
280
|
-
? GITHUB_REPOSITORY_BLOB_BASE_URL
|
|
281
|
-
: path.posix.extname(normalizedPath)
|
|
282
|
-
? GITHUB_REPOSITORY_BLOB_BASE_URL
|
|
283
|
-
: GITHUB_REPOSITORY_TREE_BASE_URL;
|
|
284
|
-
|
|
285
|
-
return `${urlBase}/${normalizedPath}`;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
function resolveRootLandingCompiledHref(href: string): string {
|
|
289
|
-
if (!href || isExternalOrAnchorHref(href)) {
|
|
290
|
-
return href;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
const normalizedHref = normalizeRepoRelativeHref(href);
|
|
294
|
-
if (!normalizedHref) {
|
|
295
|
-
return './index.html';
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
if (
|
|
299
|
-
normalizedHref === 'docs' ||
|
|
300
|
-
normalizedHref === 'docs/' ||
|
|
301
|
-
normalizedHref === 'docs/index.html'
|
|
302
|
-
) {
|
|
303
|
-
return './index.html';
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
if (normalizedHref.startsWith('docs/')) {
|
|
307
|
-
return `./${normalizedHref.slice('docs/'.length)}`;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
if (
|
|
311
|
-
normalizedHref === 'src' ||
|
|
312
|
-
normalizedHref === 'src/' ||
|
|
313
|
-
normalizedHref === 'src/README.md'
|
|
314
|
-
) {
|
|
315
|
-
return './src/index.html';
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
if (normalizedHref.startsWith('src/')) {
|
|
319
|
-
const sourceSubpath = normalizedHref.slice('src/'.length);
|
|
320
|
-
const sourceReadmeMatch = /^(.*)\/README\.md$/.exec(sourceSubpath);
|
|
321
|
-
const compiledDocsCandidate = sourceReadmeMatch
|
|
322
|
-
? sourceReadmeMatch[1]
|
|
323
|
-
: sourceSubpath.replace(/\/$/, '');
|
|
324
|
-
|
|
325
|
-
if (hasCompiledDocsPage(compiledDocsCandidate)) {
|
|
326
|
-
return `./${compiledDocsCandidate}/index.html`;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
if (normalizedHref === 'test/examples' || normalizedHref === 'test/examples/') {
|
|
331
|
-
return './examples/index.html';
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
const exampleReadmeMatch = /^test\/examples\/([^/]+)\/README\.md$/.exec(
|
|
335
|
-
normalizedHref,
|
|
336
|
-
);
|
|
337
|
-
if (exampleReadmeMatch) {
|
|
338
|
-
return `./examples/${exampleReadmeMatch[1]}/docs/index.html`;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
const exampleDirectoryMatch = /^test\/examples\/([^/]+)\/?$/.exec(
|
|
342
|
-
normalizedHref,
|
|
343
|
-
);
|
|
344
|
-
if (exampleDirectoryMatch) {
|
|
345
|
-
return `./examples/${exampleDirectoryMatch[1]}/index.html`;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
const compiledDocsDirectoryCandidate = normalizedHref.replace(/\/$/, '');
|
|
349
|
-
if (hasCompiledDocsPage(compiledDocsDirectoryCandidate)) {
|
|
350
|
-
return `./${compiledDocsDirectoryCandidate}/index.html`;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
return buildGitHubRepositoryHref(normalizedHref);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
function rewriteCompiledDocsContentLinks(
|
|
357
|
-
htmlBody: string,
|
|
358
|
-
relativeDirectory: string,
|
|
359
|
-
): string {
|
|
360
|
-
if (relativeDirectory !== '') {
|
|
361
|
-
return htmlBody;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
return htmlBody.replace(
|
|
365
|
-
/\bhref=(['"])([^'"]+)\1/g,
|
|
366
|
-
(_match, quote: string, href: string) => {
|
|
367
|
-
return `href=${quote}${resolveRootLandingCompiledHref(href)}${quote}`;
|
|
368
|
-
},
|
|
369
|
-
);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
function hasPublishedDocsPage(
|
|
373
|
-
relDir: string,
|
|
374
|
-
generatedPageDirectories: ReadonlySet<string>,
|
|
375
|
-
): boolean {
|
|
376
|
-
if (generatedPageDirectories.has(relDir)) return true;
|
|
377
|
-
return fs.existsSync(path.resolve(DOCS_DIR, relDir, 'index.html'));
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
function collectMermaidBlocks(
|
|
381
|
-
markdown: string,
|
|
382
|
-
readmePath: string,
|
|
383
|
-
): MermaidBlockReference[] {
|
|
384
|
-
const mermaidBlocks: MermaidBlockReference[] = [];
|
|
385
|
-
const mermaidFencePattern = /^```mermaid[^\n]*\r?\n([\s\S]*?)^```\s*$/gm;
|
|
386
|
-
let mermaidMatch = mermaidFencePattern.exec(markdown);
|
|
387
|
-
|
|
388
|
-
while (mermaidMatch) {
|
|
389
|
-
mermaidBlocks.push({
|
|
390
|
-
readmePath,
|
|
391
|
-
blockNumber: mermaidBlocks.length + 1,
|
|
392
|
-
diagram: mermaidMatch[1].trim(),
|
|
393
|
-
});
|
|
394
|
-
mermaidMatch = mermaidFencePattern.exec(markdown);
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
return mermaidBlocks;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
async function validateMermaidBlocks(
|
|
401
|
-
mermaidBlocks: readonly MermaidBlockReference[],
|
|
402
|
-
): Promise<void> {
|
|
403
|
-
if (mermaidBlocks.length === 0) {
|
|
404
|
-
return;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
const tempDirectoryPath = await mkdtemp(
|
|
408
|
-
path.join(os.tmpdir(), 'neatapticts-docs-mermaid-'),
|
|
409
|
-
);
|
|
410
|
-
|
|
411
|
-
try {
|
|
412
|
-
for (const mermaidBlock of mermaidBlocks) {
|
|
413
|
-
const tempInputPath = path.join(
|
|
414
|
-
tempDirectoryPath,
|
|
415
|
-
`diagram-${mermaidBlock.blockNumber}.mmd`,
|
|
416
|
-
);
|
|
417
|
-
|
|
418
|
-
// Step 1: Materialize the Mermaid block for CLI validation.
|
|
419
|
-
await fs.writeFile(tempInputPath, mermaidBlock.diagram, 'utf8');
|
|
420
|
-
|
|
421
|
-
// Step 2: Treat broken Mermaid as a docs build failure instead of a browser-only error.
|
|
422
|
-
await runMermaidValidation(tempInputPath, mermaidBlock);
|
|
423
|
-
}
|
|
424
|
-
} finally {
|
|
425
|
-
await rm(tempDirectoryPath, { recursive: true, force: true });
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
async function runMermaidValidation(
|
|
430
|
-
tempInputPath: string,
|
|
431
|
-
mermaidBlock: MermaidBlockReference,
|
|
432
|
-
): Promise<void> {
|
|
433
|
-
await new Promise<void>((resolve, reject) => {
|
|
434
|
-
const childProcess = spawn(
|
|
435
|
-
process.execPath,
|
|
436
|
-
[MERMAID_CLI_SCRIPT_PATH, 'validate', '--input', tempInputPath],
|
|
437
|
-
{ stdio: 'inherit' },
|
|
438
|
-
);
|
|
439
|
-
|
|
440
|
-
childProcess.once('exit', (exitCode) => {
|
|
441
|
-
if (exitCode === 0) {
|
|
442
|
-
resolve();
|
|
443
|
-
return;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
const relativeReadmePath = path.relative(process.cwd(), mermaidBlock.readmePath);
|
|
447
|
-
reject(
|
|
448
|
-
new Error(
|
|
449
|
-
`Invalid Mermaid diagram in ${relativeReadmePath} (block ${mermaidBlock.blockNumber}). Mermaid CLI exited with code ${exitCode ?? 'null'}.`,
|
|
450
|
-
),
|
|
451
|
-
);
|
|
452
|
-
});
|
|
453
|
-
childProcess.once('error', reject);
|
|
454
|
-
});
|
|
455
|
-
}
|
|
10
|
+
import { ensureRenderDocsAssets } from './render-docs-html/render-docs-html.assets.js';
|
|
11
|
+
import {
|
|
12
|
+
ensureMermaidBrowserAssets,
|
|
13
|
+
validateMermaidBlocks,
|
|
14
|
+
} from './render-docs-html/render-docs-html.mermaid.js';
|
|
15
|
+
import {
|
|
16
|
+
collectDocsPages,
|
|
17
|
+
emitDocsPages,
|
|
18
|
+
} from './render-docs-html/render-docs-html.pages.js';
|
|
456
19
|
|
|
457
|
-
async function main() {
|
|
458
|
-
|
|
459
|
-
|
|
20
|
+
async function main(): Promise<void> {
|
|
21
|
+
// Step 1: Ensure static assets and Mermaid browser bundles are published.
|
|
22
|
+
await ensureRenderDocsAssets();
|
|
23
|
+
await ensureMermaidBrowserAssets();
|
|
460
24
|
|
|
461
|
-
//
|
|
462
|
-
const pages
|
|
463
|
-
const mermaidBlocks: MermaidBlockReference[] = [];
|
|
464
|
-
for (const mdFile of readmes) {
|
|
465
|
-
const md = await fs.readFile(mdFile, 'utf8');
|
|
466
|
-
const title =
|
|
467
|
-
md.match(/^#\s+(.+)$/m)?.[1] ||
|
|
468
|
-
path.relative(DOCS_DIR, path.dirname(mdFile)) ||
|
|
469
|
-
'Documentation';
|
|
470
|
-
const relDir = path
|
|
471
|
-
.relative(DOCS_DIR, path.dirname(mdFile))
|
|
472
|
-
.replace(/\\/g, '/');
|
|
473
|
-
pages.push({ abs: mdFile, relDir, title, markdown: md });
|
|
474
|
-
mermaidBlocks.push(...collectMermaidBlocks(md, mdFile));
|
|
475
|
-
}
|
|
25
|
+
// Step 2: Discover markdown pages and collect Mermaid fences.
|
|
26
|
+
const { pages, mermaidBlocks } = await collectDocsPages();
|
|
476
27
|
|
|
477
|
-
// Step
|
|
28
|
+
// Step 3: Validate all Mermaid diagrams before emitting HTML.
|
|
478
29
|
await validateMermaidBlocks(mermaidBlocks);
|
|
479
30
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
// Extract headings for TOC (## file, ### symbol)
|
|
483
|
-
const fileHeadings: {
|
|
484
|
-
file: string;
|
|
485
|
-
anchor: string;
|
|
486
|
-
symbols: { name: string; anchor: string }[];
|
|
487
|
-
}[] = [];
|
|
488
|
-
const lines = md.split(/\r?\n/);
|
|
489
|
-
let currentFile: {
|
|
490
|
-
file: string;
|
|
491
|
-
anchor: string;
|
|
492
|
-
symbols: { name: string; anchor: string }[];
|
|
493
|
-
} | null = null;
|
|
494
|
-
for (const line of lines) {
|
|
495
|
-
const fileMatch = /^##\s+(.+\.ts)\s*$/.exec(line);
|
|
496
|
-
if (fileMatch) {
|
|
497
|
-
const fileName = fileMatch[1];
|
|
498
|
-
const anchor = slugify(fileName);
|
|
499
|
-
currentFile = { file: fileName, anchor, symbols: [] };
|
|
500
|
-
fileHeadings.push(currentFile);
|
|
501
|
-
continue;
|
|
502
|
-
}
|
|
503
|
-
const symMatch = /^###\s+([A-Za-z0-9_]+)\s*$/.exec(line);
|
|
504
|
-
if (symMatch && currentFile) {
|
|
505
|
-
const sym = symMatch[1];
|
|
506
|
-
currentFile.symbols.push({ name: sym, anchor: slugify(sym) });
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
// Configure marked renderer with deterministic heading IDs so anchors match our TOC.
|
|
510
|
-
const renderer = new marked.Renderer();
|
|
511
|
-
const originalCode = renderer.code?.bind(renderer);
|
|
512
|
-
let hasMermaidDiagram = false;
|
|
513
|
-
// Marked >= v16 passes a single Heading token object { text, depth, raw, tokens }
|
|
514
|
-
// See: https://marked.js.org/using_pro#renderer for updated signature.
|
|
515
|
-
(renderer as any).heading = ({ text, depth, raw }: any) => {
|
|
516
|
-
const source = (raw ?? text ?? '')
|
|
517
|
-
.toString()
|
|
518
|
-
.replace(/<[^>]+>/g, '')
|
|
519
|
-
.trim();
|
|
520
|
-
const id = slugify(source);
|
|
521
|
-
return `<h${depth} id="${id}">${text}</h${depth}>`;
|
|
522
|
-
};
|
|
523
|
-
(renderer as any).code = (codeToken: any) => {
|
|
524
|
-
const { text, lang } = codeToken;
|
|
525
|
-
if ((lang ?? '').toString().trim().toLowerCase() === 'mermaid') {
|
|
526
|
-
hasMermaidDiagram = true;
|
|
527
|
-
return `<pre class="mermaid mermaid-diagram">${escapeHtml(
|
|
528
|
-
(text ?? '').toString(),
|
|
529
|
-
)}</pre>`;
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
return originalCode?.(codeToken) ?? '';
|
|
533
|
-
};
|
|
534
|
-
marked.use({ renderer });
|
|
535
|
-
const rawHtmlBody = marked.parse(md, { async: false });
|
|
536
|
-
const htmlBody = rewriteCompiledDocsContentLinks(rawHtmlBody, meta.relDir);
|
|
537
|
-
const generatedPageDirectories = new Set(pages.map((page) => page.relDir));
|
|
538
|
-
const rootExamplesTocHtml = buildExamplesTocLinksHtml({
|
|
539
|
-
currentDir: meta.relDir,
|
|
540
|
-
generatedPageDirectories,
|
|
541
|
-
hasPublishedDocsPage,
|
|
542
|
-
buildRelativeDocsHref,
|
|
543
|
-
escapeHtml,
|
|
544
|
-
});
|
|
545
|
-
const navHtml = buildDocsSidebarHtml({
|
|
546
|
-
currentDir: meta.relDir,
|
|
547
|
-
pages,
|
|
548
|
-
generatedPageDirectories,
|
|
549
|
-
hasPublishedDocsPage,
|
|
550
|
-
buildRelativeDocsHref,
|
|
551
|
-
escapeHtml,
|
|
552
|
-
});
|
|
553
|
-
const toc = fileHeadings.length
|
|
554
|
-
? `<div class="page-toc"><h2>Files</h2>${fileHeadings
|
|
555
|
-
.map(
|
|
556
|
-
(f) =>
|
|
557
|
-
`<div class=\"toc-file\"><a href=\"#${f.anchor}\">${f.file}</a>${
|
|
558
|
-
f.symbols.length
|
|
559
|
-
? `<ul>${f.symbols
|
|
560
|
-
.map((s) => `<li><a href=#${s.anchor}>${s.name}</a></li>`)
|
|
561
|
-
.join('')}</ul>`
|
|
562
|
-
: ''
|
|
563
|
-
}</div>`,
|
|
564
|
-
)
|
|
565
|
-
.join('')}</div>`
|
|
566
|
-
: meta.relDir === '' && rootExamplesTocHtml
|
|
567
|
-
? `<div class="page-toc"><h2>Examples</h2><div class="toc-file">${rootExamplesTocHtml}</div></div>`
|
|
568
|
-
: '';
|
|
569
|
-
const outFile = path.join(path.dirname(meta.abs), 'index.html');
|
|
570
|
-
const relToRoot = path
|
|
571
|
-
.relative(path.dirname(meta.abs), DOCS_DIR)
|
|
572
|
-
.replace(/\\/g, '/');
|
|
573
|
-
const cssHref = (relToRoot ? relToRoot + '/' : '') + 'assets/theme.css';
|
|
574
|
-
const mermaidBootstrapScript = hasMermaidDiagram
|
|
575
|
-
? buildMermaidBootstrapScript(relToRoot)
|
|
576
|
-
: '';
|
|
577
|
-
const docsLayoutInteractionScript = buildDocsLayoutInteractionScript();
|
|
578
|
-
// Add Examples top-level nav; active when current dir starts with examples
|
|
579
|
-
const examplesHref = (relToRoot || '.') + '/examples/index.html';
|
|
580
|
-
const onExamples = meta.relDir.startsWith('examples');
|
|
581
|
-
const docsActive = !onExamples ? ' class="active"' : '';
|
|
582
|
-
const examplesActive = onExamples ? ' class="active"' : '';
|
|
583
|
-
const page = `<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>${
|
|
584
|
-
meta.title
|
|
585
|
-
} – NeatapticTS Docs</title><meta name="viewport" content="width=device-width,initial-scale=1">\n<link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Raleway:wght@400;600;700&family=Open+Sans:wght@400;600&display=swap" rel="stylesheet">\n<link rel="stylesheet" href="${cssHref}"></head><body class="${
|
|
586
|
-
meta.relDir === '' ? 'is-root' : ''
|
|
587
|
-
}">\n<header class="topbar"><div class="inner topbar-inner-connected"><div class="brand"><a class="brand-link" href="${
|
|
588
|
-
relToRoot || '.'
|
|
589
|
-
}/index.html"><span class="brand-title-lockup" aria-hidden="true"><span class="brand-title-row brand-title-row-top"><span class="brand-title-corner">╔══</span><span class="brand-label">NeatapticTS</span><span class="brand-title-corner">══╗</span></span></span><span class="brand-title-accessible">NeatapticTS</span></a></div><nav class="main-nav"><a href="${
|
|
590
|
-
relToRoot || '.'
|
|
591
|
-
}/index.html">Home</a><a href="${
|
|
592
|
-
relToRoot || '.'
|
|
593
|
-
}/index.html"${docsActive}>Docs</a><a href="${examplesHref}"${examplesActive}>Examples</a><a href="https://github.com/reicek/NeatapticTS" target="_blank" rel="noopener">GitHub</a></nav></div></header>\n<div class="layout"><aside class="sidebar docs-panel docs-panel-left">${navHtml}</aside><main class="content docs-panel docs-panel-center">${htmlBody}<footer class="site-footer">Generated from source JSDoc • <a href="https://github.com/reicek/NeatapticTS">GitHub</a></footer></main><aside class="toc docs-panel docs-panel-right">${toc}</aside></div>${docsLayoutInteractionScript}${mermaidBootstrapScript}</body></html>`;
|
|
594
|
-
await writeFileWithRetry(outFile, page, 'utf8');
|
|
595
|
-
}
|
|
596
|
-
console.log('HTML docs generated.');
|
|
31
|
+
// Step 4: Render the full HTML page set.
|
|
32
|
+
await emitDocsPages(pages);
|
|
597
33
|
}
|
|
598
34
|
|
|
599
35
|
main().catch((e) => {
|