88using Elastic . Codex . Sourcing ;
99using Elastic . Documentation ;
1010using Elastic . Documentation . Configuration ;
11+ using Elastic . Documentation . Configuration . Codex ;
1112using Elastic . Documentation . Diagnostics ;
1213using Elastic . Documentation . Isolated ;
1314using Elastic . Documentation . Links . CrossLinks ;
1415using Elastic . Documentation . Navigation ;
1516using Elastic . Documentation . Navigation . Isolated . Node ;
1617using Elastic . Documentation . Services ;
18+ using Elastic . Documentation . Site ;
1719using Elastic . Documentation . Site . Navigation ;
1820using Elastic . Markdown . Exporters ;
1921using Elastic . Markdown . IO ;
@@ -44,8 +46,13 @@ public async Task<CodexBuildResult> BuildAll(
4446 IReadOnlySet < Exporter > ? exporters = null )
4547 {
4648 var outputDir = context . OutputDirectory ;
47- if ( ! outputDir . Exists )
48- outputDir . Create ( ) ;
49+ if ( outputDir . Exists )
50+ {
51+ _logger . LogInformation ( "Cleaning target output directory: {Directory}" , outputDir . FullName ) ;
52+ outputDir . Delete ( true ) ;
53+ }
54+
55+ outputDir . Create ( ) ;
4956
5057 _logger . LogInformation ( "Building {Count} documentation sets to {Directory}" ,
5158 cloneResult . Checkouts . Count , outputDir . FullName ) ;
@@ -97,11 +104,14 @@ public async Task<CodexBuildResult> BuildAll(
97104 await Task . WhenAll ( stopTasks ) ;
98105 }
99106
100- // Phase 4: Generate codex landing and category pages
107+ // Phase 4: Generate codex landing and group pages
108+ CodexGenerator ? codexGenerator = null ;
101109 if ( buildContexts . Count > 0 )
102- await GenerateCodexPages ( context , buildContexts [ 0 ] . BuildContext , codexNavigation , ctx ) ;
110+ {
111+ codexGenerator = await GenerateCodexPages ( context , buildContexts [ 0 ] . BuildContext , codexNavigation , ctx ) ;
112+ }
103113
104- return new CodexBuildResult ( codexNavigation , buildContexts . Select ( b => b . DocumentationSet ) . ToList ( ) ) ;
114+ return new CodexBuildResult ( codexNavigation , buildContexts . Select ( b => b . DocumentationSet ) . ToList ( ) , codexGenerator ) ;
105115 }
106116
107117 private async Task < CodexDocumentationSetBuildContext ? > LoadDocumentationSet (
@@ -187,13 +197,16 @@ private async Task BuildDocumentationSet(
187197
188198 try
189199 {
200+ var reference = buildContext . Checkout . Reference ;
201+ var codexBreadcrumbs = ResolveCodexBreadcrumbs ( context , reference ) ;
202+
190203 _ = await isolatedBuildService . BuildDocumentationSet (
191204 buildContext . DocumentationSet ,
192205 null , // Use doc set's navigation for traversal
193206 null , // Use default navigation HTML writer (doc set's navigation)
194207 ExportOptions . Default ,
195208 sharedExporters ,
196- pageViewFactory : new CodexPageViewFactory ( context . Configuration . Title ) ,
209+ pageViewFactory : new CodexPageViewFactory ( context . Configuration . Title , codexBreadcrumbs ) ,
197210 ctx ) ;
198211 }
199212 catch ( Exception ex )
@@ -204,7 +217,27 @@ private async Task BuildDocumentationSet(
204217 }
205218 }
206219
207- private async Task GenerateCodexPages (
220+ private static IReadOnlyList < CodexBreadcrumb > ResolveCodexBreadcrumbs (
221+ CodexContext context ,
222+ CodexDocumentationSetReference reference )
223+ {
224+ var sitePrefix = context . Configuration . SitePrefix ? . Trim ( '/' ) ?? "" ;
225+ var repoName = reference . ResolvedRepoName ;
226+ var groupId = reference . Group ;
227+ var homeUrl = string . IsNullOrEmpty ( sitePrefix ) ? "/" : $ "/{ sitePrefix } /";
228+ var docSetUrl = string . IsNullOrEmpty ( sitePrefix ) ? $ "/r/{ repoName } " : $ "/{ sitePrefix } /r/{ repoName } ";
229+ var docSetTitle = reference . DisplayName ?? repoName ;
230+
231+ if ( string . IsNullOrEmpty ( groupId ) )
232+ return [ new CodexBreadcrumb ( "Home" , homeUrl ) , new CodexBreadcrumb ( docSetTitle , docSetUrl ) ] ;
233+
234+ var groupUrl = string . IsNullOrEmpty ( sitePrefix ) ? $ "/g/{ groupId } " : $ "/{ sitePrefix } /g/{ groupId } ";
235+ var groupDef = context . Configuration . Groups . FirstOrDefault ( g => g . Id == groupId ) ;
236+ var groupTitle = groupDef ? . Name ?? groupId ;
237+ return [ new CodexBreadcrumb ( "Home" , homeUrl ) , new CodexBreadcrumb ( groupTitle , groupUrl ) , new CodexBreadcrumb ( docSetTitle , docSetUrl ) ] ;
238+ }
239+
240+ private async Task < CodexGenerator > GenerateCodexPages (
208241 CodexContext context ,
209242 BuildContext docSetBuildContext ,
210243 CodexNavigation codexNavigation ,
@@ -230,6 +263,7 @@ private async Task GenerateCodexPages(
230263 // Use CodexGenerator to render the codex pages to the codex's output directory
231264 var codexGenerator = new CodexGenerator ( logFactory , codexBuildContext , context . OutputDirectory ) ;
232265 await codexGenerator . Generate ( codexNavigation , ctx ) ;
266+ return codexGenerator ;
233267 }
234268}
235269
@@ -238,9 +272,11 @@ private async Task GenerateCodexPages(
238272/// </summary>
239273/// <param name="Navigation">The codex navigation structure.</param>
240274/// <param name="DocumentationSets">The built documentation sets.</param>
275+ /// <param name="CodexGenerator">Generator for re-rendering codex pages (e.g. for dev server).</param>
241276public record CodexBuildResult (
242277 CodexNavigation Navigation ,
243- IReadOnlyList < DocumentationSet > DocumentationSets ) ;
278+ IReadOnlyList < DocumentationSet > DocumentationSets ,
279+ CodexGenerator ? CodexGenerator = null ) ;
244280
245281/// <summary>
246282/// Build context for a single documentation set within the codex.
0 commit comments