Skip to content

Commit 18eea7a

Browse files
committed
stage
1 parent b2798f9 commit 18eea7a

File tree

14 files changed

+99
-48
lines changed

14 files changed

+99
-48
lines changed

src/Elastic.Documentation.Configuration/DocSet/DocumentationSetFile.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,9 +230,7 @@ private static TableOfContents ResolveTableOfContents(
230230

231231
// Validate: TOC must have at least one child
232232
if (resolvedChildren.Count == 0)
233-
{
234233
collector.EmitError(tocFilePath, $"Table of contents '{fullTocPath}' has no children defined");
235-
}
236234

237235
// Return TOC ref with FULL path and resolved children
238236
// The context remains the parent context (where this TOC was referenced)

src/Elastic.Documentation.Configuration/DocSet/SiteNavigationFile.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using System.Collections.Immutable;
66
using System.IO.Abstractions;
77
using Elastic.Documentation.Configuration.Assembler;
8-
using Elastic.Documentation.Configuration.Serialization;
98
using Elastic.Documentation.Diagnostics;
109
using YamlDotNet.Core;
1110
using YamlDotNet.Core.Events;

src/Elastic.Documentation.Navigation/Assembler/AssembledNavigation.cs

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
33
// See the LICENSE file in the project root for more information
44

5+
using System.Diagnostics;
56
using Elastic.Documentation.Configuration.Assembler;
67
using Elastic.Documentation.Configuration.DocSet;
78
using Elastic.Documentation.Extensions;
@@ -12,6 +13,7 @@ namespace Elastic.Documentation.Navigation.Assembler;
1213
public record SiteNavigationNoIndexFile(string NavigationTitle) : IDocumentationFile;
1314

1415

16+
[DebuggerDisplay("{Url}")]
1517
public class SiteNavigation : IRootNavigationItem<IDocumentationFile, INavigationItem>
1618
{
1719
private readonly string? _sitePrefix;
@@ -45,6 +47,7 @@ public SiteNavigation(SiteNavigationFile siteNavigationFile,
4547
}
4648
}
4749
}
50+
UnseenNodes = [.. _nodes.Keys];
4851

4952
// Build NavigationItems from SiteTableOfContentsRef items
5053
var items = new List<INavigationItem>();
@@ -54,7 +57,9 @@ public SiteNavigation(SiteNavigationFile siteNavigationFile,
5457
var navItem = CreateSiteTableOfContentsNavigation(
5558
tocRef,
5659
index++,
57-
context
60+
context,
61+
this,
62+
null
5863
);
5964

6065
if (navItem != null)
@@ -63,12 +68,16 @@ public SiteNavigation(SiteNavigationFile siteNavigationFile,
6368

6469
NavigationItems = items;
6570
_ = this.UpdateNavigationIndex(context);
71+
var count = UnseenNodes.Count;
72+
var unseen = string.Join(", ", UnseenNodes);
6673
Index = this.FindIndex<IDocumentationFile>(new NotFoundModel("/index.md"));
6774
}
6875

6976
private readonly Dictionary<Uri, INodeNavigationItem<IDocumentationFile, INavigationItem>> _nodes;
7077
public IReadOnlyDictionary<Uri, INodeNavigationItem<IDocumentationFile, INavigationItem>> Nodes => _nodes;
7178

79+
private HashSet<Uri> UnseenNodes { get; }
80+
7281
public IReadOnlyCollection<PhantomRegistration> Phantoms { get; }
7382

7483
//TODO Obsolete?
@@ -135,7 +144,9 @@ public SiteNavigation(SiteNavigationFile siteNavigationFile,
135144
private INavigationItem? CreateSiteTableOfContentsNavigation(
136145
SiteTableOfContentsRef tocRef,
137146
int index,
138-
IDocumentationContext context
147+
IDocumentationContext context,
148+
INodeNavigationItem<INavigationModel, INavigationItem> parent,
149+
IRootNavigationItem<INavigationModel, INavigationItem>? root
139150
)
140151
{
141152
var pathPrefix = tocRef.PathPrefix;
@@ -146,14 +157,13 @@ IDocumentationContext context
146157
if (tocRef.Source.Scheme != NarrativeRepository.RepositoryName)
147158
context.EmitError(context.ConfigurationPath, $"path_prefix is required for TOC reference: {tocRef.Source}");
148159

149-
pathPrefix = tocRef.Source.Scheme;
150160
if (!string.IsNullOrEmpty(tocRef.Source.Host))
151161
pathPrefix += $"/{tocRef.Source.Host}";
152162
if (!string.IsNullOrEmpty(tocRef.Source.AbsolutePath) && tocRef.Source.AbsolutePath != "/")
153163
pathPrefix += $"/{tocRef.Source.AbsolutePath}";
154164
}
155165

156-
// Normalize pathPrefix to remove leading/trailing slashes for consistent combination
166+
// Normalize pathPrefix to remove leading/trailing slashes for a consistent combination
157167
pathPrefix = pathPrefix.Trim('/');
158168

159169
// Combine with site prefix if present, otherwise ensure leading slash
@@ -173,12 +183,25 @@ IDocumentationContext context
173183
return null;
174184
}
175185

186+
_ = UnseenNodes.Remove(tocRef.Source);
176187
// Set the navigation index
177188
node.NavigationIndex = index;
178189
prefixProvider.PathPrefixProvider = new PathPrefixProvider(pathPrefix);
179190

180-
// Recursively create child navigation items if children are specified
191+
var wrapped = new SiteTableOfContentsNavigation<IDocumentationFile>(node, prefixProvider.PathPrefixProvider, parent, root);
192+
parent = wrapped;
193+
root ??= wrapped.NavigationRoot;
194+
181195
var children = new List<INavigationItem>();
196+
var nodeChildren = node.NavigationItems;
197+
foreach (var nodeChild in nodeChildren)
198+
{
199+
nodeChild.Parent = parent;
200+
if (nodeChild is IRootNavigationItem<IDocumentationFile, INavigationItem>)
201+
continue;
202+
children.Add(nodeChild);
203+
}
204+
// Recursively create child navigation items if children are specified
182205
if (tocRef.Children.Count > 0)
183206
{
184207
var childIndex = 0;
@@ -187,20 +210,18 @@ IDocumentationContext context
187210
var childItem = CreateSiteTableOfContentsNavigation(
188211
child,
189212
childIndex++,
190-
context
213+
context,
214+
parent,
215+
root
191216
);
192217
if (childItem != null)
193218
children.Add(childItem);
194219
}
195220
}
196-
else
197-
{
198-
// If no children specified, use the node's original children
199-
children = node.NavigationItems.ToList();
200-
}
201221

222+
wrapped.NavigationItems = children;
202223
// Always return a wrapper to ensure path_prefix is the URL (not path_prefix + node's URL)
203-
return new SiteTableOfContentsNavigation<IDocumentationFile>(node, prefixProvider.PathPrefixProvider, children);
224+
return wrapped;
204225
}
205226
}
206227

@@ -212,10 +233,12 @@ IDocumentationContext context
212233
/// Wrapper for a navigation node that applies a path prefix to URLs and optionally
213234
/// overrides the children to show only the children specified in the site navigation configuration.
214235
/// </remarks>
236+
[DebuggerDisplay("{Url}")]
215237
public sealed class SiteTableOfContentsNavigation<TModel>(
216238
INodeNavigationItem<TModel, INavigationItem> wrappedNode,
217239
IPathPrefixProvider pathPrefixProvider,
218-
IReadOnlyCollection<INavigationItem> children
240+
INodeNavigationItem<INavigationModel, INavigationItem> parent,
241+
IRootNavigationItem<INavigationModel, INavigationItem>? root
219242
) : INodeNavigationItem<TModel, INavigationItem>, INavigationPathPrefixProvider
220243
where TModel : IDocumentationFile
221244
{
@@ -231,12 +254,13 @@ public string Url
231254
}
232255

233256
public string NavigationTitle => wrappedNode.NavigationTitle;
234-
public IRootNavigationItem<INavigationModel, INavigationItem> NavigationRoot => wrappedNode.NavigationRoot;
257+
public IRootNavigationItem<INavigationModel, INavigationItem> NavigationRoot =>
258+
root ?? wrappedNode as IRootNavigationItem<INavigationModel, INavigationItem> ?? parent.NavigationRoot;
235259

236260
public INodeNavigationItem<INavigationModel, INavigationItem>? Parent
237261
{
238-
get => wrappedNode.Parent;
239-
set => wrappedNode.Parent = value;
262+
get => parent;
263+
set { }
240264
}
241265

242266
public bool Hidden => wrappedNode.Hidden;
@@ -255,7 +279,7 @@ public int NavigationIndex
255279
// Override to return the specified children from site navigation
256280
// Wrap children to apply path prefix recursively - but don't wrap children that are
257281
// already SiteTableOfContentsNavigation (they have their own path prefix)
258-
public IReadOnlyCollection<INavigationItem> NavigationItems { get; } = children;
282+
public IReadOnlyCollection<INavigationItem> NavigationItems { get; set; } = [];
259283

260284
/// <inheritdoc />
261285
public IPathPrefixProvider PathPrefixProvider { get; set; } = pathPrefixProvider;

src/Elastic.Documentation.Navigation/Isolated/CrossLinkNavigationLeaf.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
33
// See the LICENSE file in the project root for more information
44

5+
using System.Diagnostics;
6+
57
namespace Elastic.Documentation.Navigation.Isolated;
68

79
public record CrossLinkModel(Uri CrossLinkUri, string NavigationTitle) : IDocumentationFile;
810

11+
[DebuggerDisplay("{Url}")]
912
public class CrossLinkNavigationLeaf(
1013
CrossLinkModel model,
1114
string url,

src/Elastic.Documentation.Navigation/Isolated/DocumentationSetNavigation.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
33
// See the LICENSE file in the project root for more information
44

5+
using System.Diagnostics;
56
using System.IO.Abstractions;
67
using Elastic.Documentation.Configuration.DocSet;
78
using Elastic.Documentation.Extensions;
@@ -31,6 +32,7 @@ public interface IDocumentationSetNavigation : IRootNavigationItem<IDocumentatio
3132
IReadOnlyDictionary<Uri, INodeNavigationItem<IDocumentationFile, INavigationItem>> TableOfContentNodes { get; }
3233
}
3334

35+
[DebuggerDisplay("{Url}")]
3436
public class DocumentationSetNavigation<TModel>
3537
: IDocumentationSetNavigation, INavigationPathPrefixProvider, IPathPrefixProvider
3638

src/Elastic.Documentation.Navigation/Isolated/FileNavigationLeaf.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
33
// See the LICENSE file in the project root for more information
44

5+
using System.Diagnostics;
56
using System.IO.Abstractions;
67

78
namespace Elastic.Documentation.Navigation.Isolated;
@@ -15,6 +16,7 @@ public record FileNavigationArgs(
1516
IPathPrefixProvider PrefixProvider
1617
);
1718

19+
[DebuggerDisplay("{Url}")]
1820
public class FileNavigationLeaf<TModel>(TModel model, IFileInfo fileInfo, FileNavigationArgs args)
1921
: ILeafNavigationItem<TModel>
2022
where TModel : IDocumentationFile

src/Elastic.Documentation.Navigation/Isolated/FolderNavigation.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
33
// See the LICENSE file in the project root for more information
44

5+
using System.Diagnostics;
56
using Elastic.Documentation.Extensions;
67

78
namespace Elastic.Documentation.Navigation.Isolated;
89

10+
[DebuggerDisplay("{Url}")]
911
public class FolderNavigation : INodeNavigationItem<IDocumentationFile, INavigationItem>
1012
{
1113
public FolderNavigation(

src/Elastic.Documentation.Navigation/Isolated/TableOfContentsNavigation.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
33
// See the LICENSE file in the project root for more information
44

5+
using System.Diagnostics;
56
using System.IO.Abstractions;
67
using Elastic.Documentation.Extensions;
78

@@ -12,6 +13,7 @@ public interface IDocumentationFile : INavigationModel
1213
string NavigationTitle { get; }
1314
}
1415

16+
[DebuggerDisplay("{Url}")]
1517
public class TableOfContentsNavigation : IRootNavigationItem<IDocumentationFile, INavigationItem>
1618
, INavigationPathPrefixProvider
1719
, IPathPrefixProvider

src/Elastic.Documentation.Navigation/Isolated/TemporaryNavigationPlaceholder.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
33
// See the LICENSE file in the project root for more information
44

5+
using System.Diagnostics;
56
using System.IO.Abstractions;
67

78
namespace Elastic.Documentation.Navigation.Isolated;
@@ -11,6 +12,7 @@ namespace Elastic.Documentation.Navigation.Isolated;
1112
/// before the final navigation item is created with its children collection.
1213
/// This placeholder should never appear in the final navigation tree.
1314
/// </summary>
15+
[DebuggerDisplay("{Url}")]
1416
internal sealed class TemporaryNavigationPlaceholder(
1517
int depth,
1618
string id,

src/Elastic.Documentation.Navigation/Isolated/VirtualFileNavigation.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
33
// See the LICENSE file in the project root for more information
44

5+
using System.Diagnostics;
56
using System.IO.Abstractions;
67
using Elastic.Documentation.Extensions;
78

@@ -19,6 +20,7 @@ IReadOnlyCollection<INavigationItem> NavigationItems
1920
);
2021

2122
/// Represents a file navigation item that defines children which are not part of the file tree.
23+
[DebuggerDisplay("{Url}")]
2224
public class VirtualFileNavigation<TModel>(TModel model, IFileInfo fileInfo, VirtualFileNavigationArgs args)
2325
: INodeNavigationItem<TModel, INavigationItem>
2426
where TModel : IDocumentationFile

0 commit comments

Comments
 (0)