Structured content · Intrinsic page hierarchy
Page hierarchy.
Every tracked page belongs to an intrinsic project hierarchy derived from its tracked name. Pages expose parent, children, ancestors, descendants and siblings, so breadcrumbs, section navigation and nested documentation compose directly with collection operations.
The hierarchy relations
A page's parent is the nearest existing tracked ancestor by name path: docs/advanced/guide is a child of docs/advanced when that page exists, otherwise of docs, otherwise of the root /. The root has no parent. children are ordered by tracked order; ancestors and descendants exclude the page itself; siblings are the other children of the parent, in tracked order.
| Relation | Result | Cost |
|---|---|---|
page.parent | The parent page value, or null for the root. | O(1) |
page.children | Direct children in tracked order. | O(children) |
page.ancestors | Ancestors top-down (root first, immediate parent last), excluding self. | O(depth) |
page.descendants | All descendants in pre-order, excluding self. | O(descendants) |
page.siblings | Other children of the parent, excluding self. | O(siblings) |
Every page value also exposes its data: name, title, path, output_path, url, type, metadata and content.
Getting a page value
In a page template, page binds to the current page. Anywhere (templates, scripts, nift eval), page(name) returns a tracked page by name:
$[current := page]
@// current page (templates)
$[docs := page("docs")]
@// any tracked page by name
$[title := page("docs/advanced").title]
@// data field on a page value Breadcrumbs from ancestors
$[crumbs := page.ancestors.reverse().map(a => "<a href=\"" + a.url + "\">" + a.title + "</a>").join(" / ")] Section and index navigation from children
$[links := page.children.map(c => "<a href=\"" + c.url + "\">" + c.title + "</a>").join(", ")] Children compose with collection operations directly:
$[published := page.children.filter(c => !c.metadata.draft)]
$[newest := page.children.sort_by(c => c.metadata.date, "desc").take(5)]
$[tags := page.children.map(c => c.metadata.tags).flatten().unique()] Nested documentation navigation
Agent use through nift eval
nift eval 'page("docs/advanced").parent.title'
nift eval --json 'page("docs").children.map(c => c.title)'
nift eval 'page("docs").descendants.size()' Incremental behaviour
Pages that use the hierarchy record one compact structural dependency (a hierarchy fingerprint), so adding, removing, renaming or reparenting a page rebuilds hierarchy consumers without recording every tracked item against every consumer. Ordinary pages that never use the hierarchy carry no hierarchy dependency and pay nothing for it.