Skip to content

Commit dcd2c67

Browse files
committed
moar docs
1 parent 6dcd072 commit dcd2c67

File tree

8 files changed

+437
-1323
lines changed

8 files changed

+437
-1323
lines changed

docs/development/navigation/assembler-process.md

Lines changed: 187 additions & 541 deletions
Large diffs are not rendered by default.
Lines changed: 29 additions & 206 deletions
Original file line numberDiff line numberDiff line change
@@ -1,222 +1,45 @@
11
# First Principles
22

3-
This document outlines the fundamental principles that guide the design of `Elastic.Documentation.Navigation`.
3+
The navigation system is built on two types of principles:
44

5-
## Core Principles
5+
## [Functional Principles](functional-principles.md)
66

7-
### 1. Two-Phase Loading
7+
These define **what** the navigation system does and **why**:
88

9-
Navigation construction follows a strict two-phase approach:
9+
1. **Two-Phase Loading** - Separate configuration resolution from navigation construction
10+
2. **Single Documentation Source** - All paths relative to docset root
11+
3. **URL Building is Dynamic** - URLs calculated on-demand, not stored
12+
4. **Navigation Roots Can Be Re-homed** - O(1) URL prefix changes
13+
5. **Navigation Scope via HomeProvider** - Scoped URL calculation contexts
14+
6. **Index Files Determine URLs** - Folders and indexes share URLs
15+
7. **File Structure Mirrors Navigation** - Predictable, maintainable structure
16+
8. **Acyclic Graph Structure** - Tree with no cycles, unique URLs
17+
9. **Phantom Nodes** - Acknowledge content without including it
1018

11-
**Phase 1: Configuration Resolution** (`Elastic.Documentation.Configuration`)
12-
- Parse YAML files (`docset.yml`, `toc.yml`, `navigation.yml`)
13-
- Resolve all file references to **full paths** relative to documentation set root
14-
- Validate configuration structure and relationships
15-
- Output: Fully resolved configuration objects with complete file paths
19+
[Read Functional Principles →](functional-principles.md)
1620

17-
**Phase 2: Navigation Construction** (`Elastic.Documentation.Navigation`)
18-
- Consume resolved configuration from Phase 1
19-
- Build navigation tree with **full URLs**
20-
- Create node relationships (parent/child/root)
21-
- Set up home providers for URL calculation
22-
- Output: Complete navigation tree with calculated URLs
21+
## [Technical Principles](technical-principles.md)
2322

24-
**Why Two Phases?**
25-
- **Separation of Concerns**: Configuration parsing is independent of navigation structure
26-
- **Validation**: Catch file/structure errors before building expensive navigation trees
27-
- **Reusability**: Same configuration can build different navigation structures (isolated vs assembler)
28-
- **Performance**: Resolve file system operations once, reuse for navigation
23+
These define **how** the navigation system is implemented:
2924

30-
### 2. Single Documentation Source
25+
1. **Generic Type System** - Covariance enables static typing without runtime casts
26+
2. **Provider Pattern** - Decouples URL calculation from tree structure
27+
3. **Lazy URL Calculation** - Smart caching with automatic invalidation
3128

32-
URLs are always built relative to the documentation set's source directory:
33-
- Files referenced in `docset.yml` are relative to the docset root
34-
- Files referenced in nested `toc.yml` are relative to the toc directory
35-
- During Phase 1, all paths are resolved to be relative to the docset root
36-
- During Phase 2, URLs are calculated from these resolved paths
29+
[Read Technical Principles →](technical-principles.md)
3730

38-
**Example:**
39-
```
40-
docs/
41-
├── docset.yml # Root
42-
├── index.md
43-
└── api/
44-
├── toc.yml # Nested TOC
45-
└── rest.md
46-
```
31+
---
4732

48-
Phase 1 resolves `api/toc.yml` reference to `rest.md` as: `api/rest.md` (relative to docset root)
49-
Phase 2 builds URL as: `/api/rest/`
33+
## Quick Reference
5034

51-
### 3. URL Building is Dynamic and Cheap
35+
**For understanding architecture:** Start with [Functional Principles](functional-principles.md)
5236

53-
URLs are **calculated on-demand**, not stored:
54-
- Nodes don't store their final URL
55-
- URLs are computed from `HomeProvider.PathPrefix` + relative path
56-
- Changing a `HomeProvider` instantly updates all descendant URLs
57-
- No tree traversal needed to update URLs
37+
**For implementation details:** See [Technical Principles](technical-principles.md)
5838

59-
**Why Dynamic?**
60-
- **Re-homing**: Same subtree can have different URLs in different contexts
61-
- **Memory Efficient**: Don't store redundant URL strings
62-
- **Consistency**: URLs always reflect current home provider state
39+
**For visual examples:** See [Visual Walkthrough](visual-walkthrough.md)
6340

64-
### 4. Navigation Roots Can Be Re-homed
65-
66-
A key design feature that enables assembler builds:
67-
- **Isolated Build**: Each `DocumentationSetNavigation` is its own root
68-
- **Assembler Build**: `SiteNavigation` becomes the root, docsets are "re-homed"
69-
- **Re-homing**: Replace a subtree's `HomeProvider` to change its URL prefix
70-
- **Cheap Operation**: O(1) - just replace the provider reference
71-
72-
**Example:**
73-
```csharp
74-
// Isolated: URLs start at /
75-
homeProvider.PathPrefix = "";
76-
// → /api/rest/
77-
78-
// Assembled: Re-home to /guide
79-
homeProvider = new NavigationHomeProvider("/guide", siteNav);
80-
// → /guide/api/rest/
81-
```
82-
83-
### 5. Navigation Scope via HomeProvider
84-
85-
`INavigationHomeProvider` creates navigation scopes:
86-
- **Provider**: Defines `PathPrefix` and `NavigationRoot` for a scope
87-
- **Accessor**: Children use `INavigationHomeAccessor` to access their scope
88-
- **Inheritance**: Child nodes inherit their parent's accessor
89-
- **Isolation**: Changes to a provider only affect its scope
90-
91-
**Scope Creators:**
92-
- `DocumentationSetNavigation` - Creates scope for entire docset
93-
- `TableOfContentsNavigation` - Creates scope for TOC subtree (enables re-homing)
94-
95-
**Scope Consumers:**
96-
- `FileNavigationLeaf` - Uses accessor to calculate URL
97-
- `FolderNavigation` - Passes accessor to children
98-
- `VirtualFileNavigation` - Passes accessor to children
99-
100-
### 6. Index Files Determine Folder URLs
101-
102-
Every folder/node navigation has an **Index**:
103-
- Index is either `index.md` or the first file
104-
- The node's URL is the same as its Index's URL
105-
- Children appear "under" the index in navigation
106-
- Index files map to folder paths: `/api/index.md``/api/`
107-
108-
**Why?**
109-
- **Consistent URL Structure**: Folders and their indexes share the same URL
110-
- **Natural Navigation**: Index represents the folder's landing page
111-
- **Hierarchical**: Clear parent-child URL relationships
112-
113-
### 7. File Structure Should Mirror Navigation
114-
115-
Best practices for maintainability:
116-
- Navigation structure should follow file system structure
117-
- Avoid deep-linking files from different directories
118-
- Use `folder:` references when possible
119-
- Virtual files should group sibling files, not restructure the tree
120-
121-
**Rationale:**
122-
- **Discoverability**: Developers can find files by following navigation
123-
- **Predictability**: URL structure matches file structure
124-
- **Maintainability**: Moving files in navigation matches moving them on disk
125-
126-
### 8. Generic Type System for Covariance
127-
128-
Navigation classes are generic over `TModel`:
129-
```csharp
130-
public class DocumentationSetNavigation<TModel>
131-
where TModel : class, IDocumentationFile
132-
```
133-
134-
**Why Generic?**
135-
- **Covariance**: Can treat `DocumentationSetNavigation<MarkdownFile>` as `IRootNavigationItem<IDocumentationFile, INavigationItem>`
136-
- **Type Safety**: Factory pattern ensures correct model types
137-
- **Flexibility**: Same navigation code works with different file models
138-
139-
### 9. Lazy URL Calculation with Caching
140-
141-
`FileNavigationLeaf` implements smart URL caching:
142-
```csharp
143-
private string? _homeProviderCache;
144-
private string? _urlCache;
145-
146-
public string Url
147-
{
148-
get
149-
{
150-
if (_homeProviderCache == HomeProvider.Id && _urlCache != null)
151-
return _urlCache;
152-
153-
_urlCache = CalculateUrl();
154-
_homeProviderCache = HomeProvider.Id;
155-
return _urlCache;
156-
}
157-
}
158-
```
159-
160-
**Strategy:**
161-
- Cache URL along with HomeProvider ID
162-
- Invalidate cache when HomeProvider changes
163-
- Recalculate only when needed
164-
- O(1) for repeated access, O(path) for calculation
165-
166-
### 10. Phantom Nodes for Incomplete Navigation
167-
168-
`navigation.yml` can declare phantoms:
169-
```yaml
170-
phantoms:
171-
- source: plugins://
172-
```
173-
174-
**Purpose:**
175-
- Reference nodes that exist but aren't included in site navigation
176-
- Prevent "undeclared navigation" warnings
177-
- Document intentionally excluded content
178-
- Enable validation of cross-links
179-
180-
## Design Patterns
181-
182-
### Factory Pattern for Node Creation
183-
184-
`DocumentationNavigationFactory` creates navigation items:
185-
- Encapsulates construction logic
186-
- Ensures consistent initialization
187-
- Centralizes node creation
188-
- Type-safe generic methods
189-
190-
### Provider Pattern for URL Context
191-
192-
`INavigationHomeProvider` / `INavigationHomeAccessor`:
193-
- Providers define context (PathPrefix, NavigationRoot)
194-
- Accessors reference providers
195-
- Decouples URL calculation from tree structure
196-
- Enables context switching (re-homing)
197-
198-
### Visitor Pattern for Tree Operations
199-
200-
Navigation items implement interfaces for traversal:
201-
- `IRootNavigationItem<TModel, TChild>` - Root nodes
202-
- `INodeNavigationItem<TModel, TChild>` - Nodes with children
203-
- `ILeafNavigationItem<TModel>` - Leaf nodes
204-
- Common `INavigationItem` base for polymorphic traversal
205-
206-
## Key Invariants
207-
208-
1. **Phase Order**: Configuration must be fully resolved before navigation construction
209-
2. **Path Resolution**: All paths in configuration are relative to docset root after Phase 1
210-
3. **URL Uniqueness**: Every navigation item must have a unique URL within its site
211-
4. **Root Consistency**: All nodes in a subtree point to the same `NavigationRoot`
212-
5. **Provider Validity**: A node's `HomeProvider` must be an ancestor in the tree
213-
6. **Index Requirement**: All node navigations (folder/toc/docset) must have an Index
214-
7. **Path Prefix Uniqueness**: In assembler builds, all `path_prefix` values must be unique
215-
216-
## Performance Characteristics
217-
218-
- **Tree Construction**: O(n) where n = number of files
219-
- **URL Calculation**: O(depth) for first access, O(1) with caching
220-
- **Re-homing**: O(1) - just replace HomeProvider reference
221-
- **Tree Traversal**: O(n) for full tree, but rarely needed
222-
- **Memory**: O(n) for nodes, URLs computed on-demand
41+
**For specific topics:**
42+
- How assembly works: [Assembler Process](assembler-process.md)
43+
- How re-homing works: [Home Provider Architecture](home-provider-architecture.md)
44+
- Two-phase approach: [Two-Phase Loading](two-phase-loading.md)
45+
- Node reference: [Node Types](node-types.md)

0 commit comments

Comments
 (0)