You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Any Conductor-migrated module that hands data back by calling this.exports.push(...) directly (in the constructor or initialise()) instead of exposing it through an exportedNames-listed @moduleMethod gets zero generated doc entries for that data — not "No description available", entirely absent from the output.
Two confirmed live cases, built directly against origin/conductor-migration @ 961f6414e (2026-07-24):
scrabble (src/bundles/scrabble/src/index.ts, merged via Migrate scrabble module to Conductor #792): exportedNames is [] as const since none of its 4 exports (scrabble_words, scrabble_letters, scrabble_words_tiny, scrabble_letters_tiny) are @moduleMethod closures — they're plain arrays built in initialise() and pushed onto this.exports.
$ node lib/buildtools/dist/index.js build docs src/bundles/scrabble
docs written to .../build/jsons/scrabble.json
$ cat build/jsons/scrabble.json
{}
Empty. None of the 4 exports appear anywhere in the output.
midi (merged via Migrate midi module to Conductor #791, including 6207fde's JSDoc pass): SHARP/FLAT/NATURAL are pushed the same runtime way from the constructor and aren't in exportedNames. 6207fde's own commit message verifies "all 19 exports now show real descriptions" — 19 is exactly exportedNames.length, so those 3 constants were never part of that count:
lib/buildtools/src/build/docs/conductor/normalisation.ts's normalizeContainer only touches classes that pass isConductorPluginClass() (conductor/utils.ts:85-92), which requires a non-empty exportedNames. For a class that passes, promotePluginMethods (utils.ts:267-286) promotes only the Method-kind children listed in exportedNames (no path for anything else), and only then is the class itself removed from the doc tree (normalisation.ts:151-157).
scrabble's class never passes isConductorPluginClass at all (empty exportedNames), so it's never promoted and never removed — it just falls through lib/typedoc-plugin/src/json.ts's parsers table (only handles Function/Variable) with no entries surviving.
midi's class does pass (19 real @moduleMethod exports), so it IS removed — taking SHARP/FLAT/NATURAL down with it, since they were never promoted in the first place (not methods, not in exportedNames).
Either way, this.exports.push(...) calls inside a method body are invisible to TypeDoc, which reflects declarations, not statements/arguments inside a function or constructor body. There's currently no convention for attaching a doc comment to one of these pushed exports that any part of the pipeline reads — so no amount of JSDoc placement fixes it as-is.
Why this matters going forward
Team direction (from the scrabble/midi Slack thread on the OPAQUE-vs-array question) is that data-only modules should hand back plain arrays rather than OPAQUE-wrapped objects. That means more modules will look like scrabble — all-data exports, empty exportedNames — going forward, all silently undocumented under the current pipeline as it stands.
Possible directions (not proposing one yet)
Extend isConductorPluginClass/promotePluginMethods to also recognize a declared list of data-export names (parallel to exportedNames) plus a place to hang JSDoc on each one (e.g. a static field per export, or a comment block keyed by symbol name).
Have BaseModulePlugin expose data exports as real class properties/getters (TypeDoc already reflects properties) instead of imperative this.exports.push(...) calls, so existing declaration-based reflection just works unmodified.
Something else — raising this now, before more data-only modules land, rather than guessing at the right convention unilaterally.
Raised while checking whether scrabble (#782, merged via #792) needed the same JSDoc fix as midi's 6207fde (#791) — it doesn't; this is a different, cross-cutting gap in the shared doc-build tooling, not a per-module JSDoc issue.
What's broken
Any Conductor-migrated module that hands data back by calling
this.exports.push(...)directly (in the constructor orinitialise()) instead of exposing it through anexportedNames-listed@moduleMethodgets zero generated doc entries for that data — not "No description available", entirely absent from the output.Two confirmed live cases, built directly against
origin/conductor-migration@961f6414e(2026-07-24):scrabble (
src/bundles/scrabble/src/index.ts, merged via Migrate scrabble module to Conductor #792):exportedNamesis[] as constsince none of its 4 exports (scrabble_words,scrabble_letters,scrabble_words_tiny,scrabble_letters_tiny) are@moduleMethodclosures — they're plain arrays built ininitialise()and pushed ontothis.exports.Empty. None of the 4 exports appear anywhere in the output.
midi (merged via Migrate midi module to Conductor #791, including 6207fde's JSDoc pass):
SHARP/FLAT/NATURALare pushed the same runtime way from the constructor and aren't inexportedNames. 6207fde's own commit message verifies "all 19 exports now show real descriptions" — 19 is exactlyexportedNames.length, so those 3 constants were never part of that count:Root cause
lib/buildtools/src/build/docs/conductor/normalisation.ts'snormalizeContaineronly touches classes that passisConductorPluginClass()(conductor/utils.ts:85-92), which requires a non-emptyexportedNames. For a class that passes,promotePluginMethods(utils.ts:267-286) promotes only theMethod-kind children listed inexportedNames(no path for anything else), and only then is the class itself removed from the doc tree (normalisation.ts:151-157).isConductorPluginClassat all (emptyexportedNames), so it's never promoted and never removed — it just falls throughlib/typedoc-plugin/src/json.ts'sparserstable (only handlesFunction/Variable) with no entries surviving.@moduleMethodexports), so it IS removed — takingSHARP/FLAT/NATURALdown with it, since they were never promoted in the first place (not methods, not inexportedNames).Either way,
this.exports.push(...)calls inside a method body are invisible to TypeDoc, which reflects declarations, not statements/arguments inside a function or constructor body. There's currently no convention for attaching a doc comment to one of these pushed exports that any part of the pipeline reads — so no amount of JSDoc placement fixes it as-is.Why this matters going forward
Team direction (from the scrabble/midi Slack thread on the OPAQUE-vs-array question) is that data-only modules should hand back plain arrays rather than
OPAQUE-wrapped objects. That means more modules will look like scrabble — all-data exports, emptyexportedNames— going forward, all silently undocumented under the current pipeline as it stands.Possible directions (not proposing one yet)
isConductorPluginClass/promotePluginMethodsto also recognize a declared list of data-export names (parallel toexportedNames) plus a place to hang JSDoc on each one (e.g. a static field per export, or a comment block keyed by symbol name).BaseModulePluginexpose data exports as real class properties/getters (TypeDoc already reflects properties) instead of imperativethis.exports.push(...)calls, so existing declaration-based reflection just works unmodified.Repro
Raised while checking whether scrabble (#782, merged via #792) needed the same JSDoc fix as midi's
6207fde(#791) — it doesn't; this is a different, cross-cutting gap in the shared doc-build tooling, not a per-module JSDoc issue.