30
30
31
31
using Microsoft . VisualStudio . Services . WebApi ;
32
32
using Process = System . Diagnostics . Process ;
33
+ using System . Runtime . CompilerServices ;
34
+
35
+ [ assembly: InternalsVisibleTo ( "AzureDevOps.WikiPDFExport.Test" ) ]
33
36
34
37
namespace azuredevops_export_wiki
35
38
{
@@ -100,7 +103,6 @@ public WikiPDFExporter(Options options)
100
103
{ "icon_pull_request" , "bowtie-tfvc-pull-request" } ,
101
104
{ "icon_github_issue" , "bowtie-status-error-outline" } ,
102
105
} ;
103
-
104
106
}
105
107
106
108
public async Task Export ( )
@@ -145,7 +147,6 @@ public async Task Export()
145
147
}
146
148
} ;
147
149
}
148
- else
149
150
{
150
151
files = ReadOrderFiles ( _path , 0 ) ; // root level
151
152
}
@@ -399,7 +400,8 @@ private string ConvertMarkdownToHTML(List<MarkdownFile> files)
399
400
. UsePipeTables ( )
400
401
. UseEmojiAndSmiley ( )
401
402
. UseAdvancedExtensions ( )
402
- . UseYamlFrontMatter ( ) ;
403
+ . UseYamlFrontMatter ( )
404
+ . UseTableOfContent ( ) ;
403
405
404
406
//must be handled by us to have linking across files
405
407
pipelineBuilder . Extensions . RemoveAll ( x => x is Markdig . Extensions . AutoIdentifiers . AutoIdentifierExtension ) ;
@@ -430,11 +432,38 @@ private string ConvertMarkdownToHTML(List<MarkdownFile> files)
430
432
continue ;
431
433
}
432
434
433
- var md = File . ReadAllText ( file . FullName ) ;
435
+ var markdownContent = File . ReadAllText ( file . FullName ) ;
436
+ files [ i ] . Content = markdownContent ;
437
+ }
438
+
439
+ if ( ! string . IsNullOrEmpty ( _options . GlobalTOC ) )
440
+ {
441
+ var firstMDFileInfo = new FileInfo ( files [ 0 ] . AbsolutePath ) ;
442
+ var directoryName = firstMDFileInfo . Directory . Name ;
443
+ var tocName = _options . GlobalTOC == "" ? directoryName : _options . GlobalTOC ;
444
+ var relativePath = "/" + tocName + ".md" ;
445
+ var tocMDFilePath = new FileInfo ( files [ 0 ] . AbsolutePath ) . DirectoryName + relativePath ;
446
+
447
+ var contents = files . Select ( x => x . Content ) . ToList ( ) ;
448
+ var tocContent = CreateGlobalTableOfContent ( contents ) ;
449
+ var tocString = string . Join ( "\n " , tocContent ) ;
450
+
451
+ var tocMarkdownFile = new MarkdownFile { AbsolutePath = tocMDFilePath , Level = 0 , RelativePath = relativePath , Content = tocString } ;
452
+ files . Insert ( 0 , tocMarkdownFile ) ;
453
+ }
454
+
455
+ for ( var i = 0 ; i < files . Count ; i ++ )
456
+ {
457
+ var mf = files [ i ] ;
458
+ var file = new FileInfo ( files [ i ] . AbsolutePath ) ;
459
+
460
+ Log ( $ "{ file . Name } ", LogLevel . Information , 1 ) ;
434
461
435
- //replace Table of Content
436
- md = RemoveTableOfContent ( md ) ;
462
+ var md = mf . Content ;
437
463
464
+ //rename TOC tags to fit to MarkdigToc or delete them from each markdown document
465
+ var newTOCString = _options . GlobalTOC != null ? "" : "[TOC]" ;
466
+ md = md . Replace ( "[[_TOC_]]" , newTOCString ) ;
438
467
439
468
// remove scalings from image links, width & height: file.png =600x500
440
469
var regexImageScalings = @"\((.[^\)]*?[png|jpg|jpeg]) =(\d+)x(\d+)\)" ;
@@ -457,7 +486,7 @@ private string ConvertMarkdownToHTML(List<MarkdownFile> files)
457
486
var pipeline = pipelineBuilder . Build ( ) ;
458
487
459
488
//parse the markdown document so we can alter it later
460
- var document = ( MarkdownDocument ) Markdown . Parse ( md , pipeline ) ;
489
+ var document = Markdown . Parse ( md , pipeline ) ;
461
490
462
491
if ( _options . NoFrontmatter )
463
492
{
@@ -477,6 +506,7 @@ private string ConvertMarkdownToHTML(List<MarkdownFile> files)
477
506
}
478
507
}
479
508
509
+
480
510
//adjust the links
481
511
CorrectLinksAndImages ( document , file , mf ) ;
482
512
@@ -491,6 +521,12 @@ private string ConvertMarkdownToHTML(List<MarkdownFile> files)
491
521
}
492
522
html = builder . ToString ( ) ;
493
523
524
+ if ( ! string . IsNullOrEmpty ( _options . GlobalTOC ) && i == 0 )
525
+ {
526
+ html = RemoveDuplicatedHeadersFromGlobalTOC ( html ) ;
527
+ Log ( $ "Removed duplicated headers from toc html", LogLevel . Information , 1 ) ;
528
+ }
529
+
494
530
//add html anchor
495
531
var anchorPath = file . FullName . Substring ( _path . Length ) ;
496
532
anchorPath = anchorPath . Replace ( "\\ " , "" ) ;
@@ -513,6 +549,13 @@ private string ConvertMarkdownToHTML(List<MarkdownFile> files)
513
549
html = heading + html ;
514
550
}
515
551
552
+
553
+ if ( ! string . IsNullOrEmpty ( _options . GlobalTOC ) && i == 0 && ! _options . Heading )
554
+ {
555
+ var heading = $ "<h1>{ _options . GlobalTOC } </h1>";
556
+ html = heading + html ;
557
+ }
558
+
516
559
if ( _options . Heading )
517
560
{
518
561
var filename = file . Name . Replace ( ".md" , "" ) ;
@@ -564,6 +607,30 @@ private string ConvertMarkdownToHTML(List<MarkdownFile> files)
564
607
return result ;
565
608
}
566
609
610
+ internal string RemoveDuplicatedHeadersFromGlobalTOC ( string html )
611
+ {
612
+ var result = Regex . Replace ( html , @"^ *<h[123456].*>.*<\/h[123456]> *\n?$" , "" , RegexOptions . Multiline ) ;
613
+ result = result . Trim ( '\n ' ) ;
614
+ return result ;
615
+ }
616
+
617
+ internal List < string > CreateGlobalTableOfContent ( List < string > contents )
618
+ {
619
+ var headers = new List < string > ( ) ;
620
+ foreach ( var content in contents )
621
+ {
622
+ var headerMatches = Regex . Matches ( content , "^ *#+ ?.*$" , RegexOptions . Multiline ) ;
623
+ headers . AddRange ( headerMatches . Select ( x => x . Value . Trim ( ) ) ) ;
624
+ }
625
+
626
+ if ( ! headers . Any ( ) )
627
+ return new List < string > ( ) ; // no header -> no toc
628
+
629
+ var tocContent = new List < string > { "[TOC]" } ; // MarkdigToc style
630
+ tocContent . AddRange ( headers ) ;
631
+ return tocContent ;
632
+ }
633
+
567
634
private MarkdownDocument RemoveFrontmatter ( MarkdownDocument document )
568
635
{
569
636
var frontmatter = document . Descendants < YamlFrontMatterBlock > ( ) . FirstOrDefault ( ) ;
@@ -636,13 +703,10 @@ private bool PageMatchesFilter(MarkdownObject document)
636
703
return true ;
637
704
}
638
705
639
- private string RemoveTableOfContent ( string document )
706
+ private string RenameTableOfContent ( string document )
640
707
{
641
708
if ( document . Contains ( "TOC" ) )
642
- {
643
- Log ( "Removing Table of contents [[_TOC_]] from pdf" , LogLevel . Warning , 1 ) ;
644
- document = document . Replace ( "[[_TOC_]]" , "" ) ;
645
- }
709
+ document = document . Replace ( "[[_TOC_]]" , "[TOC]" ) ; // MarkdigToc styled. See https://github.com/leisn/MarkdigToc
646
710
return document ;
647
711
}
648
712
@@ -860,6 +924,7 @@ public class MarkdownFile
860
924
public string AbsolutePath ;
861
925
public string RelativePath ;
862
926
public int Level ;
927
+ public string Content ;
863
928
864
929
public override string ToString ( )
865
930
{
0 commit comments