@reicek/neataptic-ts 0.1.25 → 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/package.json +19 -13
- 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
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Builds per-directory README markdown for the output boundary.
|
|
3
|
+
*
|
|
4
|
+
* This chapter owns the readable docs narrative: promoted file summaries,
|
|
5
|
+
* file section ordering, symbol rendering, and the markdown block structure
|
|
6
|
+
* that turns collected symbols into educational folder READMEs.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import * as path from 'path';
|
|
10
|
+
|
|
11
|
+
import { getCachedDirectoryDocsOrderConfig } from '../generate-docs.order.js';
|
|
12
|
+
import type {
|
|
13
|
+
GenerateDocsState,
|
|
14
|
+
RenderedFileSummary,
|
|
15
|
+
RenderedSymbol,
|
|
16
|
+
} from '../generate-docs.types.js';
|
|
17
|
+
import { renderSignatureBlock } from '../symbols/generate-docs.symbols.js';
|
|
18
|
+
import {
|
|
19
|
+
resolveHiddenDirectorySymbolNames,
|
|
20
|
+
resolveSortedDirectoryFiles,
|
|
21
|
+
resolveSortedTopLevelFileSectionSymbols,
|
|
22
|
+
resolveVisibleDirectoryFiles,
|
|
23
|
+
warnForConfiguredIntroFileIfNeeded,
|
|
24
|
+
} from './generate-docs.output.ordering.utils.js';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Builds the README markdown for one directory.
|
|
28
|
+
*
|
|
29
|
+
* One file summary may be promoted into the directory opening so the folder
|
|
30
|
+
* README starts with the strongest module-level narrative instead of repeating
|
|
31
|
+
* the same text inside the first file section.
|
|
32
|
+
*
|
|
33
|
+
* @param state - Shared docs-generator state.
|
|
34
|
+
* @param relativeDirectory - Directory path relative to the target root.
|
|
35
|
+
* @param fileSymbolMap - Symbols grouped by file within the directory.
|
|
36
|
+
* @param sourceDir - Absolute source root.
|
|
37
|
+
* @returns Markdown README content.
|
|
38
|
+
*/
|
|
39
|
+
export function buildDirectoryReadme(
|
|
40
|
+
state: GenerateDocsState,
|
|
41
|
+
relativeDirectory: string,
|
|
42
|
+
fileSymbolMap: Map<string, RenderedSymbol[]>,
|
|
43
|
+
sourceDir: string,
|
|
44
|
+
): string {
|
|
45
|
+
const title = (relativeDirectory || path.basename(sourceDir)).replace(
|
|
46
|
+
/\\/g,
|
|
47
|
+
'/',
|
|
48
|
+
);
|
|
49
|
+
const directoryBaseName = path.basename(relativeDirectory || sourceDir);
|
|
50
|
+
const directoryPath =
|
|
51
|
+
relativeDirectory === ''
|
|
52
|
+
? sourceDir
|
|
53
|
+
: path.join(sourceDir, relativeDirectory);
|
|
54
|
+
const lines = [`# ${title}`, ''];
|
|
55
|
+
|
|
56
|
+
const sortedFiles = resolveSortedDirectoryFiles(
|
|
57
|
+
state,
|
|
58
|
+
directoryPath,
|
|
59
|
+
fileSymbolMap,
|
|
60
|
+
);
|
|
61
|
+
const hiddenSymbolNames = resolveHiddenDirectorySymbolNames(
|
|
62
|
+
state,
|
|
63
|
+
directoryPath,
|
|
64
|
+
fileSymbolMap,
|
|
65
|
+
);
|
|
66
|
+
const visibleSortedFiles = resolveVisibleDirectoryFiles(
|
|
67
|
+
state,
|
|
68
|
+
directoryPath,
|
|
69
|
+
sortedFiles,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const primaryDirectoryIntro = resolvePrimaryDirectoryIntro(
|
|
73
|
+
state,
|
|
74
|
+
directoryPath,
|
|
75
|
+
sortedFiles,
|
|
76
|
+
fileSymbolMap,
|
|
77
|
+
directoryBaseName,
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
if (primaryDirectoryIntro?.summary.description) {
|
|
81
|
+
lines.push(primaryDirectoryIntro.summary.description, '');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (primaryDirectoryIntro?.summary.examples?.length) {
|
|
85
|
+
lines.push(
|
|
86
|
+
primaryDirectoryIntro.summary.examples.length === 1
|
|
87
|
+
? 'Example:'
|
|
88
|
+
: 'Examples:',
|
|
89
|
+
'',
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
for (const example of primaryDirectoryIntro.summary.examples) {
|
|
93
|
+
lines.push(example, '');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
for (const filePath of visibleSortedFiles) {
|
|
98
|
+
renderFileReadmeSection(
|
|
99
|
+
state,
|
|
100
|
+
lines,
|
|
101
|
+
filePath,
|
|
102
|
+
fileSymbolMap,
|
|
103
|
+
sourceDir,
|
|
104
|
+
hiddenSymbolNames,
|
|
105
|
+
primaryDirectoryIntro?.filePath === filePath,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return `${lines.join('\n').trim()}\n`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Renders the README section for a single file.
|
|
114
|
+
*
|
|
115
|
+
* @param state - Shared docs-generator state.
|
|
116
|
+
* @param lines - Output line buffer.
|
|
117
|
+
* @param filePath - Absolute source file path.
|
|
118
|
+
* @param fileSymbolMap - Symbols grouped by file within the directory.
|
|
119
|
+
* @param sourceDir - Absolute source root.
|
|
120
|
+
* @param hiddenSymbolNames - Hidden symbol-name set for the current directory.
|
|
121
|
+
* @param suppressFileSummary - Whether the file summary was already promoted above.
|
|
122
|
+
* @returns Nothing.
|
|
123
|
+
*/
|
|
124
|
+
function renderFileReadmeSection(
|
|
125
|
+
state: GenerateDocsState,
|
|
126
|
+
lines: string[],
|
|
127
|
+
filePath: string,
|
|
128
|
+
fileSymbolMap: Map<string, RenderedSymbol[]>,
|
|
129
|
+
sourceDir: string,
|
|
130
|
+
hiddenSymbolNames: ReadonlySet<string>,
|
|
131
|
+
suppressFileSummary: boolean = false,
|
|
132
|
+
): void {
|
|
133
|
+
const visibleFileSymbols = (fileSymbolMap.get(filePath) ?? []).filter(
|
|
134
|
+
(symbol) => !hiddenSymbolNames.has(symbol.name),
|
|
135
|
+
);
|
|
136
|
+
const fileSummarySymbol = visibleFileSymbols.find(
|
|
137
|
+
(symbol) => symbol.kind === 'File',
|
|
138
|
+
);
|
|
139
|
+
const nonFileSummarySymbols = visibleFileSymbols.filter(
|
|
140
|
+
(symbol) => symbol.kind !== 'File',
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
if (
|
|
144
|
+
!fileSummarySymbol?.jsdoc.description &&
|
|
145
|
+
!fileSummarySymbol?.jsdoc.examples?.length &&
|
|
146
|
+
nonFileSummarySymbols.length === 0
|
|
147
|
+
) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const relativeFilePath = path
|
|
152
|
+
.relative(sourceDir, filePath)
|
|
153
|
+
.replace(/\\/g, '/');
|
|
154
|
+
lines.push(`## ${relativeFilePath}`, '');
|
|
155
|
+
|
|
156
|
+
if (!suppressFileSummary && fileSummarySymbol?.jsdoc.description) {
|
|
157
|
+
lines.push(fileSummarySymbol.jsdoc.description, '');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (!suppressFileSummary && fileSummarySymbol?.jsdoc.examples?.length) {
|
|
161
|
+
lines.push(
|
|
162
|
+
fileSummarySymbol.jsdoc.examples.length === 1 ? 'Example:' : 'Examples:',
|
|
163
|
+
'',
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
for (const example of fileSummarySymbol.jsdoc.examples) {
|
|
167
|
+
lines.push(example, '');
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const fileBaseName = path.basename(filePath, '.ts');
|
|
172
|
+
const sortedTopLevelCandidates = nonFileSummarySymbols
|
|
173
|
+
.filter((symbol) => !symbol.parent)
|
|
174
|
+
.toSorted((left, right) =>
|
|
175
|
+
compareFileSectionSymbols(left, right, fileBaseName),
|
|
176
|
+
);
|
|
177
|
+
const topLevelSymbols = resolveSortedTopLevelFileSectionSymbols(
|
|
178
|
+
state,
|
|
179
|
+
filePath,
|
|
180
|
+
sortedTopLevelCandidates,
|
|
181
|
+
);
|
|
182
|
+
const symbolsByParent = groupSymbolsByParent(nonFileSummarySymbols);
|
|
183
|
+
|
|
184
|
+
for (const topLevelSymbol of topLevelSymbols) {
|
|
185
|
+
renderSymbolBlock(lines, topLevelSymbol, 3);
|
|
186
|
+
|
|
187
|
+
const childSymbols = symbolsByParent.get(topLevelSymbol.name);
|
|
188
|
+
if (!childSymbols) {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
childSymbols.sort((left, right) => left.name.localeCompare(right.name));
|
|
193
|
+
for (const childSymbol of childSymbols) {
|
|
194
|
+
renderSymbolBlock(lines, childSymbol, 4);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
for (const [parentName, childSymbols] of symbolsByParent) {
|
|
199
|
+
if (topLevelSymbols.some((symbol) => symbol.name === parentName)) {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
lines.push(`### ${parentName}`, '');
|
|
204
|
+
childSymbols.sort((left, right) => left.name.localeCompare(right.name));
|
|
205
|
+
for (const childSymbol of childSymbols) {
|
|
206
|
+
renderSymbolBlock(lines, childSymbol, 4);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Resolves the file-summary block that should be promoted into the directory
|
|
213
|
+
* README opening.
|
|
214
|
+
*
|
|
215
|
+
* Selection priority is:
|
|
216
|
+
* 1. `docs.order.json` `introFile` when configured and the referenced file has
|
|
217
|
+
* a renderable summary,
|
|
218
|
+
* 2. a directory entrypoint file matching the folder name or `index.ts`,
|
|
219
|
+
* 3. the first remaining sorted file with a renderable summary.
|
|
220
|
+
*
|
|
221
|
+
* @param state - Shared docs-generator state.
|
|
222
|
+
* @param directoryPath - Absolute directory path.
|
|
223
|
+
* @param sortedFiles - Files already ordered for directory README rendering.
|
|
224
|
+
* @param fileSymbolMap - Symbols grouped by file within the directory.
|
|
225
|
+
* @param directoryBaseName - Base directory name used for entrypoint prioritization.
|
|
226
|
+
* @returns File path and summary when a promotable directory intro exists.
|
|
227
|
+
*/
|
|
228
|
+
function resolvePrimaryDirectoryIntro(
|
|
229
|
+
state: GenerateDocsState,
|
|
230
|
+
directoryPath: string,
|
|
231
|
+
sortedFiles: readonly string[],
|
|
232
|
+
fileSymbolMap: Map<string, RenderedSymbol[]>,
|
|
233
|
+
directoryBaseName: string,
|
|
234
|
+
): { filePath: string; summary: RenderedFileSummary } | undefined {
|
|
235
|
+
const configuredIntroFile = getCachedDirectoryDocsOrderConfig(
|
|
236
|
+
state,
|
|
237
|
+
directoryPath,
|
|
238
|
+
)?.config.introFile;
|
|
239
|
+
if (configuredIntroFile) {
|
|
240
|
+
warnForConfiguredIntroFileIfNeeded(
|
|
241
|
+
state,
|
|
242
|
+
directoryPath,
|
|
243
|
+
configuredIntroFile,
|
|
244
|
+
sortedFiles,
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
const configuredIntroFilePath = sortedFiles.find(
|
|
248
|
+
(filePath) => path.basename(filePath) === configuredIntroFile,
|
|
249
|
+
);
|
|
250
|
+
if (configuredIntroFilePath) {
|
|
251
|
+
const configuredIntroSummary = resolveRenderedFileSummary(
|
|
252
|
+
configuredIntroFilePath,
|
|
253
|
+
fileSymbolMap,
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
if (
|
|
257
|
+
configuredIntroSummary.description ||
|
|
258
|
+
configuredIntroSummary.examples?.length
|
|
259
|
+
) {
|
|
260
|
+
return {
|
|
261
|
+
filePath: configuredIntroFilePath,
|
|
262
|
+
summary: configuredIntroSummary,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const prioritizedFiles = sortedFiles.toSorted((leftFile, rightFile) => {
|
|
269
|
+
const leftBaseName = path.basename(leftFile, '.ts');
|
|
270
|
+
const rightBaseName = path.basename(rightFile, '.ts');
|
|
271
|
+
const leftIsDirectoryEntry =
|
|
272
|
+
leftBaseName === directoryBaseName || leftBaseName === 'index';
|
|
273
|
+
const rightIsDirectoryEntry =
|
|
274
|
+
rightBaseName === directoryBaseName || rightBaseName === 'index';
|
|
275
|
+
|
|
276
|
+
if (leftIsDirectoryEntry !== rightIsDirectoryEntry) {
|
|
277
|
+
return leftIsDirectoryEntry ? -1 : 1;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return sortedFiles.indexOf(leftFile) - sortedFiles.indexOf(rightFile);
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
for (const filePath of prioritizedFiles) {
|
|
284
|
+
const summary = resolveRenderedFileSummary(filePath, fileSymbolMap);
|
|
285
|
+
|
|
286
|
+
if (summary.description || summary.examples?.length) {
|
|
287
|
+
return { filePath, summary };
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return undefined;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Resolves the rendered file-summary block for one collected source file.
|
|
296
|
+
*
|
|
297
|
+
* @param filePath - Absolute source file path.
|
|
298
|
+
* @param fileSymbolMap - Symbols grouped by file within the directory.
|
|
299
|
+
* @returns Rendered file summary values when present.
|
|
300
|
+
*/
|
|
301
|
+
function resolveRenderedFileSummary(
|
|
302
|
+
filePath: string,
|
|
303
|
+
fileSymbolMap: Map<string, RenderedSymbol[]>,
|
|
304
|
+
): RenderedFileSummary {
|
|
305
|
+
const fileSummarySymbol = (fileSymbolMap.get(filePath) ?? []).find(
|
|
306
|
+
(renderedSymbol) => renderedSymbol.kind === 'File',
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
return {
|
|
310
|
+
description: fileSummarySymbol?.jsdoc.description,
|
|
311
|
+
examples: fileSummarySymbol?.jsdoc.examples,
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Groups symbols that have parent names.
|
|
317
|
+
*
|
|
318
|
+
* @param renderedSymbols - Symbols for one file.
|
|
319
|
+
* @returns Parent-keyed symbol map.
|
|
320
|
+
*/
|
|
321
|
+
function groupSymbolsByParent(
|
|
322
|
+
renderedSymbols: readonly RenderedSymbol[],
|
|
323
|
+
): Map<string, RenderedSymbol[]> {
|
|
324
|
+
const symbolsByParent = new Map<string, RenderedSymbol[]>();
|
|
325
|
+
|
|
326
|
+
for (const renderedSymbol of renderedSymbols.filter(
|
|
327
|
+
(symbol) => symbol.parent,
|
|
328
|
+
)) {
|
|
329
|
+
const childSymbols = symbolsByParent.get(renderedSymbol.parent!) ?? [];
|
|
330
|
+
childSymbols.push(renderedSymbol);
|
|
331
|
+
symbolsByParent.set(renderedSymbol.parent!, childSymbols);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
return symbolsByParent;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Renders one symbol block into the README line buffer.
|
|
339
|
+
*
|
|
340
|
+
* @param lines - Output line buffer.
|
|
341
|
+
* @param renderedSymbol - Symbol to render.
|
|
342
|
+
* @param headingLevel - Markdown heading level.
|
|
343
|
+
* @returns Nothing.
|
|
344
|
+
*/
|
|
345
|
+
function renderSymbolBlock(
|
|
346
|
+
lines: string[],
|
|
347
|
+
renderedSymbol: RenderedSymbol,
|
|
348
|
+
headingLevel: number,
|
|
349
|
+
): void {
|
|
350
|
+
const symbolDescription =
|
|
351
|
+
renderedSymbol.jsdoc.description || renderedSymbol.jsdoc.summary;
|
|
352
|
+
|
|
353
|
+
lines.push(`${'#'.repeat(headingLevel)} ${renderedSymbol.name}`);
|
|
354
|
+
|
|
355
|
+
if (renderedSymbol.signature) {
|
|
356
|
+
lines.push(
|
|
357
|
+
'',
|
|
358
|
+
...renderSignatureBlock(renderedSymbol.name, renderedSymbol.signature),
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if (symbolDescription) {
|
|
363
|
+
lines.push('', symbolDescription);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (renderedSymbol.jsdoc.deprecated) {
|
|
367
|
+
lines.push('', `**Deprecated:** ${renderedSymbol.jsdoc.deprecated}`);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (renderedSymbol.jsdoc.params?.length) {
|
|
371
|
+
lines.push('', 'Parameters:');
|
|
372
|
+
for (const parameter of renderedSymbol.jsdoc.params) {
|
|
373
|
+
lines.push(
|
|
374
|
+
`- \`${parameter.name}\`${parameter.doc ? ` - ${parameter.doc}` : ''}`,
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (renderedSymbol.jsdoc.returns) {
|
|
380
|
+
lines.push('', `Returns: ${renderedSymbol.jsdoc.returns}`);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (renderedSymbol.jsdoc.examples?.length) {
|
|
384
|
+
lines.push(
|
|
385
|
+
'',
|
|
386
|
+
renderedSymbol.jsdoc.examples.length === 1 ? 'Example:' : 'Examples:',
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
for (const example of renderedSymbol.jsdoc.examples) {
|
|
390
|
+
lines.push('', example);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
lines.push('');
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Compares file-section symbols using the stable fallback order.
|
|
399
|
+
*
|
|
400
|
+
* @param left - Left rendered symbol.
|
|
401
|
+
* @param right - Right rendered symbol.
|
|
402
|
+
* @param fileBaseName - Base file name without extension.
|
|
403
|
+
* @returns Negative when left sorts before right.
|
|
404
|
+
*/
|
|
405
|
+
function compareFileSectionSymbols(
|
|
406
|
+
left: RenderedSymbol,
|
|
407
|
+
right: RenderedSymbol,
|
|
408
|
+
fileBaseName: string,
|
|
409
|
+
): number {
|
|
410
|
+
const leftIsPrimary = !left.parent && left.name === fileBaseName;
|
|
411
|
+
const rightIsPrimary = !right.parent && right.name === fileBaseName;
|
|
412
|
+
if (leftIsPrimary !== rightIsPrimary) {
|
|
413
|
+
return leftIsPrimary ? -1 : 1;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
return (
|
|
417
|
+
(left.parent || left.name).localeCompare(right.parent || right.name) ||
|
|
418
|
+
left.name.localeCompare(right.name)
|
|
419
|
+
);
|
|
420
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Public output boundary for the folderized docs generator.
|
|
3
|
+
*
|
|
4
|
+
* This root keeps the exported emitters orchestration-first while narrower
|
|
5
|
+
* helper chapters inside the folder own README composition, folder-index
|
|
6
|
+
* rendering, ordering policy, and config warning details.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import fs from 'fs-extra';
|
|
10
|
+
import * as path from 'path';
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
DOCS_DIR,
|
|
14
|
+
FOLDER_INDEX_FILE_NAME,
|
|
15
|
+
} from '../generate-docs.constants.js';
|
|
16
|
+
import { loadDirectoryDocsOrderConfig } from '../generate-docs.order.js';
|
|
17
|
+
import type {
|
|
18
|
+
DirectorySymbolMap,
|
|
19
|
+
DocsTargetConfig,
|
|
20
|
+
GenerateDocsState,
|
|
21
|
+
} from '../generate-docs.types.js';
|
|
22
|
+
import { buildFolderIndexMarkdown } from './generate-docs.output.folder-index.utils.js';
|
|
23
|
+
import { buildDirectoryReadme } from './generate-docs.output.readme.utils.js';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Emits directory README files to both docs output and the source tree.
|
|
27
|
+
*
|
|
28
|
+
* @param state - Shared docs-generator state.
|
|
29
|
+
* @param directorySymbolMap - Normalized directory symbol map.
|
|
30
|
+
* @param target - Target configuration.
|
|
31
|
+
* @returns Nothing.
|
|
32
|
+
*/
|
|
33
|
+
export async function emitDirectoryDocs(
|
|
34
|
+
state: GenerateDocsState,
|
|
35
|
+
directorySymbolMap: DirectorySymbolMap,
|
|
36
|
+
target: DocsTargetConfig,
|
|
37
|
+
): Promise<void> {
|
|
38
|
+
for (const [directoryPath, fileSymbolMap] of directorySymbolMap) {
|
|
39
|
+
const relativeDirectory = path.relative(target.sourceDir, directoryPath);
|
|
40
|
+
if (relativeDirectory.startsWith('..')) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const outputDirectory =
|
|
45
|
+
relativeDirectory === ''
|
|
46
|
+
? target.rootDocsDir
|
|
47
|
+
: path.join(target.docsDir, relativeDirectory);
|
|
48
|
+
const sourceDirectory =
|
|
49
|
+
relativeDirectory === ''
|
|
50
|
+
? target.sourceDir
|
|
51
|
+
: path.join(target.sourceDir, relativeDirectory);
|
|
52
|
+
|
|
53
|
+
await loadDirectoryDocsOrderConfig(state, sourceDirectory);
|
|
54
|
+
|
|
55
|
+
const markdown = buildDirectoryReadme(
|
|
56
|
+
state,
|
|
57
|
+
relativeDirectory,
|
|
58
|
+
fileSymbolMap,
|
|
59
|
+
target.sourceDir,
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
await fs.ensureDir(outputDirectory);
|
|
63
|
+
await writeFileIfChanged(path.join(outputDirectory, 'README.md'), markdown);
|
|
64
|
+
await writeFileIfChanged(path.join(sourceDirectory, 'README.md'), markdown);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Emits the folder index for targets that want a docs landing page.
|
|
70
|
+
*
|
|
71
|
+
* @param state - Shared docs-generator state.
|
|
72
|
+
* @param directorySymbolMap - Normalized directory symbol map.
|
|
73
|
+
* @param target - Target configuration.
|
|
74
|
+
* @returns Nothing.
|
|
75
|
+
*/
|
|
76
|
+
export async function emitFolderIndex(
|
|
77
|
+
state: GenerateDocsState,
|
|
78
|
+
directorySymbolMap: DirectorySymbolMap,
|
|
79
|
+
target: DocsTargetConfig,
|
|
80
|
+
): Promise<void> {
|
|
81
|
+
const relativeDirectories = [...directorySymbolMap.keys()]
|
|
82
|
+
.map((directoryPath) => path.relative(target.sourceDir, directoryPath))
|
|
83
|
+
.filter((relativeDirectory) => !relativeDirectory.startsWith('..'));
|
|
84
|
+
|
|
85
|
+
const directoriesWithConfigSupport = [
|
|
86
|
+
target.sourceDir,
|
|
87
|
+
...relativeDirectories.map((relativeDirectory) =>
|
|
88
|
+
path.join(target.sourceDir, relativeDirectory),
|
|
89
|
+
),
|
|
90
|
+
];
|
|
91
|
+
await Promise.all(
|
|
92
|
+
[...new Set(directoriesWithConfigSupport)].map((directoryPath) =>
|
|
93
|
+
loadDirectoryDocsOrderConfig(state, directoryPath),
|
|
94
|
+
),
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const markdown = buildFolderIndexMarkdown(state, directorySymbolMap, target);
|
|
98
|
+
await writeFileIfChanged(
|
|
99
|
+
path.join(DOCS_DIR, FOLDER_INDEX_FILE_NAME),
|
|
100
|
+
markdown,
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Writes a file only when its content changed.
|
|
106
|
+
*
|
|
107
|
+
* @param filePath - Output file path.
|
|
108
|
+
* @param content - Desired file content.
|
|
109
|
+
* @returns Nothing.
|
|
110
|
+
*/
|
|
111
|
+
async function writeFileIfChanged(
|
|
112
|
+
filePath: string,
|
|
113
|
+
content: string,
|
|
114
|
+
): Promise<void> {
|
|
115
|
+
if (await fs.pathExists(filePath)) {
|
|
116
|
+
const previousContent = await fs.readFile(filePath, 'utf8');
|
|
117
|
+
if (previousContent === content) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
await fs.writeFile(filePath, content, 'utf8');
|
|
123
|
+
}
|