@@ -190,18 +190,24 @@ function stageTM(
190190 tmStagingDir : string ,
191191 tm : TMEntry ,
192192 docsDir : string ,
193+ markdownOverride : string | null = null ,
193194 options : { expectPdf ?: boolean } = { }
194195) : StagedTMEntry | null {
195- const mdSource = resolveBuiltMarkdown ( tmStagingDir , tm ) ;
196- if ( ! mdSource ) {
197- console . warn ( `No markdown output found for ${ tm . name } ; skipping` ) ;
198- return null ;
196+ let mdContent : string ;
197+ if ( markdownOverride !== null ) {
198+ mdContent = markdownOverride ;
199+ } else {
200+ const mdSource = resolveBuiltMarkdown ( tmStagingDir , tm ) ;
201+ if ( ! mdSource ) {
202+ console . warn ( `No markdown output found for ${ tm . name } ; skipping` ) ;
203+ return null ;
204+ }
205+ mdContent = fs . readFileSync ( mdSource , 'utf-8' ) ;
199206 }
200207
201208 const tmDocsDir = path . join ( docsDir , tm . id ) ;
202209 fs . mkdirSync ( tmDocsDir , { recursive : true } ) ;
203210
204- const mdContent = fs . readFileSync ( mdSource , 'utf-8' ) ;
205211 fs . writeFileSync ( path . join ( tmDocsDir , 'index.md' ) , mdContent , 'utf-8' ) ;
206212
207213 const htmlSource = path . join ( tmStagingDir , `${ tm . id } .html` ) ;
@@ -265,7 +271,7 @@ export function buildMkdocsSite(
265271 templateSiteFolderDST,
266272 template = 'MKdocs' ,
267273 pdfArtifactLink,
268- headerNumbering = false ,
274+ headerNumbering = true ,
269275 ...tmOptions
270276 } = options ;
271277
@@ -318,26 +324,52 @@ export function buildMkdocsSite(
318324 fs . mkdirSync ( stagingDir , { recursive : true } ) ;
319325
320326 const staged : StagedTMEntry [ ] = [ ] ;
327+ const mkdocsMarkdownByTm = new Map < string , string > ( ) ;
321328 const built : Array < { tm : TMEntry ; tmStagingDir : string } > = [ ] ;
322329 for ( const tm of tmList ) {
323330 console . log ( `\n--- Building ${ tm . name } ---` ) ;
324331 const tmStagingDir = path . join ( stagingDir , tm . name ) ;
325332 fs . mkdirSync ( tmStagingDir , { recursive : true } ) ;
326333
327334 try {
328- buildSingleTM ( tm . yamlPath , tmStagingDir , { ...tmOptions , template, headerNumbering } ) ;
335+ // Pass 1: MkDocs markdown source (no TOC, no numbering)
336+ buildSingleTM ( tm . yamlPath , tmStagingDir , {
337+ ...tmOptions ,
338+ template,
339+ headerNumbering : false ,
340+ forceToc : false ,
341+ generatePDF : false ,
342+ } ) ;
343+
344+ const mkdocsMdSource = resolveBuiltMarkdown ( tmStagingDir , tm ) ;
345+ if ( ! mkdocsMdSource ) {
346+ console . warn ( `No markdown output found for ${ tm . name } ; skipping` ) ;
347+ continue ;
348+ }
349+ mkdocsMarkdownByTm . set ( tm . id , fs . readFileSync ( mkdocsMdSource , 'utf-8' ) ) ;
350+
351+ // Pass 2: HTML/PDF artifacts (with TOC + numbering)
352+ buildSingleTM ( tm . yamlPath , tmStagingDir , {
353+ ...tmOptions ,
354+ template,
355+ headerNumbering,
356+ forceToc : true ,
357+ generatePDF : Boolean ( tmOptions . generatePDF ) ,
358+ } ) ;
359+
329360 built . push ( { tm, tmStagingDir } ) ;
330361 } catch ( err ) {
331362 console . error ( `ERROR building ${ tm . name } : ${ err } ` ) ;
332363 }
333364 }
334365
335366 for ( const entry of built ) {
336- const stagedTm = stageTM ( entry . tmStagingDir , entry . tm , absDocsDir , {
367+ const mkdocsMarkdown = mkdocsMarkdownByTm . get ( entry . tm . id ) ?? null ;
368+ const stagedTmWithMarkdown = stageTM ( entry . tmStagingDir , entry . tm , absDocsDir , mkdocsMarkdown , {
337369 expectPdf : Boolean ( tmOptions . generatePDF ) ,
338370 } ) ;
339- if ( stagedTm ) {
340- staged . push ( stagedTm ) ;
371+ if ( stagedTmWithMarkdown ) {
372+ staged . push ( stagedTmWithMarkdown ) ;
341373 }
342374 }
343375
@@ -390,7 +422,7 @@ Options:
390422 --siteUrl <url> Optional canonical site URL in mkdocs.yml
391423 --templateSiteFolderSRC <path> Extra site overlay source folder
392424 --templateSiteFolderDST <path> Overlay destination (default: <MKDocsDir>)
393- --headerNumbering Enable auto heading numbers (default: OFF for MkDocs )
425+ --headerNumbering Enable auto heading numbers (default: ON )
394426 --no-headerNumbering Force-disable auto heading numbers
395427 --generatePDF Generate PDF per TM
396428 --pdfHeaderNote <text> PDF page header text
@@ -411,8 +443,8 @@ const siteName = parseOption(cliArgs, 'siteName') ?? 'Threat Models';
411443const siteUrl = parseOption ( cliArgs , 'siteUrl' ) ;
412444const templateSiteFolderSRC = parseOption ( cliArgs , 'templateSiteFolderSRC' ) ;
413445const templateSiteFolderDST = parseOption ( cliArgs , 'templateSiteFolderDST' ) ;
414- // MkDocs default: no heading numbering (site TOC/navigation already provides structure) .
415- const headerNumbering = parseFlag ( cliArgs , 'headerNumbering' ) && ! parseFlag ( cliArgs , 'no-headerNumbering' ) ;
446+ // MkDocs default: heading numbering is enabled unless explicitly disabled .
447+ const headerNumbering = ! parseFlag ( cliArgs , 'no-headerNumbering' ) ;
416448const generatePDF = parseFlag ( cliArgs , 'generatePDF' ) ;
417449const pdfHeaderNote = parseOption ( cliArgs , 'pdfHeaderNote' ) ?? 'Private and confidential' ;
418450const pdfArtifactLink = parseOption ( cliArgs , 'pdfArtifactLink' ) ;
0 commit comments