private IReadOnlyCollection BuildNavigation()

in src/tooling/docs-assembler/Navigation/GlobalNavigation.cs [87:171]


	private IReadOnlyCollection<INavigationItem> BuildNavigation(IReadOnlyCollection<TocReference> node, int depth, INavigationItem? parent = null)
	{
		var list = new List<INavigationItem>();
		foreach (var toc in node)
		{
			if (!_assembleSources.TreeCollector.TryGetTableOfContentsTree(toc.Source, out var tree))
			{
				_navigationFile.EmitWarning($"No {nameof(TableOfContentsTree)} found for {toc.Source}");
				if (!_assembleSources.TocTopLevelMappings.TryGetValue(toc.Source, out var topLevel))
				{
					_navigationFile.EmitError(
						$"Can not create temporary {nameof(TableOfContentsTree)} for {toc.Source} since no top level source could be located for it"
					);
					continue;
				}

				// TODO passing DocumentationSet to TableOfContentsTree constructor is temporary
				// We only build this fallback in order to aid with bootstrapping the navigation
				if (!_assembleSources.TreeCollector.TryGetTableOfContentsTree(topLevel.TopLevelSource, out tree))
				{
					_navigationFile.EmitError(
						$"Can not create temporary {nameof(TableOfContentsTree)} for {topLevel.TopLevelSource} since no top level source could be located for it"
					);
					continue;
				}

				var documentationSet = tree.DocumentationSet ?? (tree.Parent as TableOfContentsTree)?.DocumentationSet
					?? throw new InvalidOperationException($"Can not fall back for {toc.Source} because no documentation set is available");

				var lookups = new NavigationLookups
				{
					FlatMappedFiles = new Dictionary<string, DocumentationFile>().ToFrozenDictionary(),
					TableOfContents = [],
					EnabledExtensions = documentationSet.EnabledExtensions,
					FilesGroupedByFolder = new Dictionary<string, DocumentationFile[]>().ToFrozenDictionary(),
				};

				var fileIndex = 0;
				tree = new TableOfContentsTree(
					documentationSet,
					toc.Source,
					documentationSet.Context,
					lookups,
					_assembleSources.TreeCollector, ref fileIndex);
			}

			var navigationItem = new TocNavigationItem(depth, tree, toc.Source, parent);
			var tocChildren = toc.Children.OfType<TocReference>().ToArray();
			var tocNavigationItems = BuildNavigation(tocChildren, depth + 1);

			var allNavigationItems =
				depth == 0
					? tocNavigationItems.Concat(tree.NavigationItems)
					: tree.NavigationItems.Concat(tocNavigationItems);

			var cleanNavigationItems = new List<INavigationItem>();
			var seenSources = new HashSet<Uri>();
			foreach (var item in allNavigationItems)
			{
				if (item is not TocNavigationItem tocNav)
				{
					cleanNavigationItems.Add(item);
					continue;
				}

				if (seenSources.Contains(tocNav.Source))
					continue;

				if (!_assembleSources.TocTopLevelMappings.TryGetValue(tocNav.Source, out var mapping))
					continue;

				if (mapping.ParentSource != tree.Source)
					continue;

				_ = seenSources.Add(tocNav.Source);
				cleanNavigationItems.Add(item);
				item.Parent = navigationItem;
			}

			tree.NavigationItems = cleanNavigationItems.ToArray();
			list.Add(navigationItem);
		}

		return list.ToArray().AsReadOnly();
	}