feat(core): navigation graph — frontmatter parser, meta.json reader, prev/next, breadcrumb - #2
Merged
Merged
Conversation
…. Add NavigationGraph, NavigationNode, and related builders to manage document structure. Introduce FrontmatterParser for YAML frontmatter extraction and MetaJson for metadata handling.
…nd NavigationGraphBuilder. Validate parsing, handling of edge cases, and document structure resolution.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ships the foundation everything downstream builds on: a walkable navigation tree over your
content/folder, with typed frontmatter reads, polymorphicmeta.jsonsupport, and the queries every ShellDocs primitive will need (ResolveByUrl,GetPrevNext,GetBreadcrumb,Flatten).What ships to
ShellDocs.CoreNavigationNode.csNodeKindenum (Page / Section / Divider). Simple POCO —Url,Title,Description,Category,Order,Path,Kind,Parent,ChildrenHeading.csrecord Heading(int Level, string Text, string Id)— pulled to its own file for reuse byShellDocs.Markdownin the next branchFrontmatterParser.csParse(string) → ParsedDocument(Frontmatter, Body). Robust against missing / unclosed / malformed YAML.GetValue<T>()extension for typed readsMetaJson.csParse(json) → MetaJson?. Four entry kinds (PageRef/Divider/Subsection) via a customUtf8JsonReaderconverter that dispatches on JSON token typeNavigationGraph.csResolveByUrl,GetPrevNext,GetBreadcrumb,Flatten. URL-indexed at construction — O(1) lookupNavigationGraphBuilder.csBuild(contentRoot)— walks folders, readsmeta.jsonif present else alphabetical, resolves subsections recursively, silently skips typos (build-time warnings come infeat/cli-init)Design decisions worth calling out
URL normalization is case-insensitive and trailing-slash-tolerant on lookup.
graph.ResolveByUrl("/BUTTON"),"/button/","button"all resolve the same node. Preserves the URL as authored for display; only the lookup key is normalized.Custom
Utf8JsonReaderconverter formeta.json. Each entry in thepagesarray is polymorphic — string slug, literal"---", or nested subsection object.System.Text.Json's built-in polymorphism assumes a discriminator; here we dispatch onJsonTokenType(string vs. object) instead.meta.jsontypos are silently dropped, not thrown. A slug inmeta.jsonthat doesn't match any.mdfile or subfolder is skipped rather than crashing the build. Rationale: docs authors will hit this constantly during content-authoring flow; a hard crash there breaks the write→see loop. The build-time warning path lives infeat/cli-initwhere user-facing errors are the right pattern.Folder-level
meta.jsonordering vs. alphabetical fallback. When present,meta.jsonfully controls the order and titles. When absent, subfolders (asSectionnodes) are sorted alphabetically first, then.mdpages byorderfrontmatter (default 0) with title as tiebreaker.Root node is synthetic.
RoothasKind = Section, empty title,Url = "/". Its children are the top-level content. Keeps recursion simple.Path preserved on
Sectionnodes. Points at the folder sofeat/cli-dev-build's dev-mode file watcher can rescan just-changed folders without rebuilding the whole graph.Test coverage
22 new tests, 24 total, all green.
FrontmatterParserTests---, invalid YAML,GetValue<T>type coercionMetaJsonTests"---"divider, nested subsection object, blank input → nullNavigationGraphBuilderTestsmeta.jsonordering, dividers, subsections, unknown-slug tolerance, missing content root throws,GetPrevNextadjacency,GetPrevNextboundaries,GetBreadcrumbwalks up from leaf, case-insensitive + trailing-slash URL lookupScaffoldingTestsMarkdownPipelineFactory+StarterPageTemplatesmokeTests use a per-test temp directory via
IDisposableso parallel runs don't collide.Verified green
dotnet build shelldocs.slnx→ 0 warnings, 0 errorsdotnet test shelldocs.slnx→ 24/24, ~630msShellDocs.Coreis called from at least one testWhat this unblocks
feat/markdown-pipeline— needs theNavigationNodeshape locked in so the pipeline knows what it's populatingfeat/components-shell— needs the navigation graph as itsDocsSidebardata sourcefeat/search-primitives— the search indexer walks the graphPrevNextNav/Breadcrumb/Sidebarnow has a canonical source of truthFiles
.csfiles insrc/ShellDocs.Core/(~430 LOC total, no XML-comment bloat)tests/ShellDocs.Tests/