Thanks to visit codestin.com
Credit goes to elastic.github.io

docs-builder
Loading

Assembler Process

The assembler combines multiple documentation repositories into a unified site with custom URL prefixes.

Prerequisites: Read Functional Principles #4 and Home Provider Architecture first to understand re-homing.

Multiple repositories need to appear as one site:

  • elastic-docs with /api/ and /guides/
  • Assembled site needs /elasticsearch/api/ and /elasticsearch/guides/
  • Same content, different URLs, no rebuilding

Four-phase process:

public AssemblerDocumentationSet(
    ILoggerFactory logFactory,
    AssembleContext context,
    Checkout checkout,
    ICrossLinkResolver crossLinkResolver,
    IConfigurationContext configurationContext,
    IReadOnlySet<Exporter> availableExporters)
{
    // For each repository:
    // 1. Load and resolve docset.yml
    var buildContext = new BuildContext(...)
    {
        AssemblerBuild = true
    };

    // 2. Build DocumentationSetNavigation with assembler context
    DocumentationSet = new DocumentationSet(buildContext, logFactory, crossLinkResolver);
}
		
  1. ← CRITICAL!

Why AssemblerBuild = true matters:

// DocumentationSetNavigation constructor when creating TOCs:
var assemblerBuild = context.AssemblerBuild;

var tocHomeProvider = assemblerBuild
    ? new NavigationHomeProvider(...)
    : parentHomeProvider;

// Result: Each TOC gets its own HomeProvider instance
		
  1. Create NEW scope
  2. Inherit parent's scope

Without this flag:

DocumentationSetNavigation
  └─ TableOfContentsNavigation (api)
      HomeProvider: INHERITED ← shares parent's provider
		

Can't re-home independently.

With this flag:

DocumentationSetNavigation
  └─ TableOfContentsNavigation (api)
      HomeProvider: NEW INSTANCE ← own provider!
		

Can re-home independently!

toc:
  - toc: elastic-docs://api
    path_prefix: elasticsearch/api
  - toc: elastic-docs://guides
    path_prefix: elasticsearch/guides
		

Defines where each TOC appears in the site.

public SiteNavigation(
    SiteNavigationFile siteNavigationFile,
    IDocumentationContext context,
    IReadOnlyCollection<IDocumentationSetNavigation> documentationSetNavigations,
    string? sitePrefix)
{
    // 1. Initialize SiteNavigation as root
    NavigationRoot = this;

    // 2. Collect all docset/TOC nodes into dictionary
    foreach (var setNavigation in documentationSetNavigations)
    {
        foreach (var (identifier, node) in setNavigation.TableOfContentNodes)
            _nodes.TryAdd(identifier, node);
    }

    // 3. Process each navigation.yml reference
    foreach (var tocRef in siteNavigationFile.TableOfContents)
    {
        var navItem = CreateSiteTableOfContentsNavigation(tocRef, index++, context, this, null);
        if (navItem != null)
            items.Add(navItem);
    }
}
		

For each entry in navigation.yml:

private INavigationItem? CreateSiteTableOfContentsNavigation(
    SiteTableOfContentsRef tocRef,
    int index,
    IDocumentationContext context,
    INodeNavigationItem<INavigationModel, INavigationItem> parent,
    IRootNavigationItem<INavigationModel, INavigationItem>? root)
{
    // 1. Calculate final path_prefix
    // 2. Look up node by identifier (elastic-docs://api)
    // 3. Replace node's HomeProvider ← THE MAGIC! ⚡
    // 4. Update parent/index
    // 5. Process children (skip nested root nodes)
}
		

The critical line:

private INavigationItem? CreateSiteTableOfContentsNavigation(...)
{
    // ...
    homeAccessor.HomeProvider = new NavigationHomeProvider(pathPrefix, siteRoot);
}
		

This single assignment updates all descendant URLs instantly (O(1)).

Input: Built with AssemblerBuild = true

elastic-docs://
  HomeProvider: self
  └─ elastic-docs://api
      HomeProvider: Instance A (PathPrefix = "")
      └─ api/rest.md → URL: /api/rest/
  └─ elastic-docs://guides
      HomeProvider: Instance B (PathPrefix = "")
      └─ guides/start.md → URL: /guides/start/
		

navigation.yml:

- toc: elastic-docs://api
  path_prefix: elasticsearch/api
- toc: elastic-docs://guides
  path_prefix: elasticsearch/guides
		

After Re-homing:

SiteNavigation
  └─ elastic-docs://api
      HomeProvider: NEW (PathPrefix = "elasticsearch/api") ← Replaced!
      └─ api/rest.md → URL: /elasticsearch/api/rest/ ✓
  └─ elastic-docs://guides
      HomeProvider: NEW (PathPrefix = "elasticsearch/guides") ← Replaced!
      └─ guides/start.md → URL: /elasticsearch/guides/start/ ✓
		

Scenario: Split a docset across the site.

# elastic-docs has both api/ and guides/ TOCs
toc:
  - toc: elastic-docs://api
    path_prefix: reference/api
  - toc: elastic-docs://guides
    path_prefix: learn/guides
		
  1. Goes here
  2. Goes there

If TOCs shared their parent's provider, both would get the same prefix. Separate providers enable different prefixes from the same repository.

1. AssemblerBuild Flag Controls Scope Creation

  • True: TOCs create own HomeProvider
  • False: TOCs inherit parent's HomeProvider

2. HomeProvider is the Re-homing Mechanism

  • URLs calculated from HomeProvider.PathPrefix
  • Changing provider changes all descendant URLs
  • No tree traversal needed

3. Root Nodes Can Be Re-homed

  • DocumentationSetNavigation - Entire docset
  • TableOfContentsNavigation - Individual TOC
  • Must have own provider (not inherited)

4. Non-Root Nodes Inherit

  • FileNavigationLeaf, FolderNavigation, etc.
  • Use parent's HomeProvider
  • Re-home automatically when parent re-homed
# Required
- toc: elastic-docs://api
  path_prefix: elasticsearch/api

# Exception: narrative repository
- toc: docs-content://guides
  # path_prefix defaults to "guides"
		
  1. Must be unique!

All path_prefix values must be unique across the site.

Declared but not included:

phantoms:
  - source: plugins://
		

Prevents "undeclared navigation" warnings for excluded content.

1. Build with AssemblerBuild = true
   → TOCs get own HomeProvider

2. Collect all nodes into dictionary
   → Indexed by identifier (elastic-docs://api)

3. For each navigation.yml entry:
   → Look up node
   → Replace HomeProvider ← O(1) operation
   → All URLs update automatically

4. Result: Unified site with custom structure
		

O(1) Re-homing:

// This updates 10,000 URLs instantly:
node.HomeProvider = new NavigationHomeProvider(newPrefix, newRoot);
		

Why?

  • URLs calculated on-demand from HomeProvider
  • Not stored in nodes
  • Changing provider = all URLs recalculate next access
  • Smart caching invalidates on provider change

Pattern 1: Keep docset together

- toc: elastic-docs://
  path_prefix: elasticsearch
		

Pattern 2: Split docset apart

- toc: elastic-docs://api
  path_prefix: reference/api
- toc: elastic-docs://guides
  path_prefix: learn/guides
		

Pattern 3: Nest docsets

- toc: products
  children:
    - toc: elasticsearch://
      path_prefix: products/elasticsearch
    - toc: kibana://
      path_prefix: products/kibana
		

The assembler enables:

  • Build repositories independently (isolated)
  • Combine into unified site (assembled)
  • Custom URL structure per site
  • Split single docset across multiple sections
  • O(1) re-homing (no tree reconstruction)

The critical piece: AssemblerBuild = true causes TableOfContentsNavigation to create own HomeProvider, enabling independent re-homing of TOCs within a docset.

Without this, you can only re-home entire docsets. With it, you can split a docset anywhere.