Help us shape the future of Go! Take the 2026 Go Developer Survey

nodeview

package
v0.0.0-...-0800e44 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 27, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package nodeview is the compiler's one reading of a raw YAML tree: a mapping read the way the parser reads it, through aliases and `<<` merge keys, each key and each key written twice settled as the parser's model settles them (docs/parser-library.md#merge-keys, #duplicate-key, #non-scalar-key), and one bounded, iterative walk of a tree as written (Walk).

A reader that wants the parser's reading takes it from here, so no two disagree; one mirroring another reader on purpose, as load.treeReads mirrors GetTarget, says so. It is neither a scan nor a lowering, so it sits below both.

Index

Constants

View Source
const AskEvery = 256

AskEvery is how many nodes a walk of a tree visits between two asks of its context: a node costs a few nanoseconds, so asking at each would be most of a walk's work, and a stretch this long still ends within microseconds.

View Source
const MergeDepthLimit = 64

MergeDepthLimit bounds how deep a chain of `<<` merge keys the mapping view expands. It is far tighter than maxAliasChain: each merge level re-materializes every pair beneath it, so expanding a chain of depth d costs O(d²), and real specs nest merge keys one or two levels deep. A chain that hits the bound is not silently truncated: View.Exhausted says so, and each reader the bound stops reports it.

Variables

This section is empty.

Functions

func Child

func Child(n *yaml.Node, key string) *yaml.Node

Child returns the value the parser reads under key in the mapping n stands for, its alias followed, or nil where it reads none: the value MappingPairs pairs key with, found without building the pairs (docs/parser-library.md#merge-keys, docs/parser-library.md#duplicate-key). n is dereferenced, a document node unwrapped first; a node that is no mapping holds nothing.

It builds no view, and allocates nothing for a mapping that merges nothing, which is what lets every reader of a schema keyword ask it. Its work is the merge structure's, which the alias scans bound; the load phase reports a chain past MergeDepthLimit (bind.Table.Truncated).

func Deref

func Deref(n *yaml.Node) *yaml.Node

Deref follows AliasNode links to the anchored node, bounded against an alias chain that loops (the anchor-cycle detector reports those separately).

func DocumentRoot

func DocumentRoot(n *yaml.Node) *yaml.Node

DocumentRoot returns the effective root node to scan: the content of a document node, or the node itself otherwise. It returns nil for an empty document.

func IsMergeKey

func IsMergeKey(raw *yaml.Node) bool

IsMergeKey reports whether raw, a mapping key node as written, is a `<<` merge key, by the library's own predicate (yml.IsMergeKey). An alias standing in for `<<` is an ordinary key. Every reader of the parser's reading of a mapping asks this or KeyOf, never a test of its own.

func KeyOf

func KeyOf(raw *yaml.Node) (string, bool)

KeyOf returns the key the parser gives the mapping pair whose raw key node is raw, and whether the pair is one of the mapping's own: a `<<` merge key names none. A key that is no scalar once its alias is followed is read as the empty string, as the parser reads it (docs/parser-library.md#non-scalar-key), and oas.CheckFormat reports it. The view and every reader of a mapping's raw pairs ask KeyOf, so none can disagree with the parser about a pair's key.

func RepeatedKeys

func RepeatedKeys(n *yaml.Node) []string

RepeatedKeys returns the keys a mapping writes more than once, each once, in the order their second copies appear. A key an explicit pair shares with a `<<` merge is the merge's precedence rule at work, not a repeat, so merged pairs are not counted. n is dereferenced; a node that is no mapping repeats nothing.

func WrittenChildren

func WrittenChildren(n *yaml.Node) map[string]*yaml.Node

WrittenChildren maps each key the mapping n writes itself to the value its text holds there: no `<<` merge read, an alias left an alias, each key as KeyOf names it and at its last copy. It answers where a document's text puts a node, which a read through merges and aliases (Child) cannot: a node merged or aliased into a mapping is written somewhere else. A node that is no mapping, an alias to one included, writes nothing.

Types

type Aliases

type Aliases uint8

Aliases says what a Walk takes an alias node for.

const (
	// AliasLeaf takes an alias for a node of its own with no children: what it
	// names is written elsewhere in the tree and visited there, so the walk
	// visits each node written once.
	AliasLeaf Aliases = iota
	// AliasTarget visits what an alias names in its place, every time, as the
	// parser's model builds a copy of it at each alias. An alias whose target
	// is nil is visited as a leaf.
	AliasTarget
)

type Outcome

type Outcome struct {
	// Visited counts the nodes handed to Visit.
	Visited int
	// Cut reports that a bound, or the walk's context, left nodes unvisited,
	// so whatever the walk answers is partial.
	Cut bool
	// Stopped reports that Visit ended the walk.
	Stopped bool
}

Outcome is how a walk ended.

type Pair

type Pair struct {
	Key string
	Val *yaml.Node
}

Pair is one effective key/value pair of a mapping node, after alias and merge-key resolution: the key as KeyOf names it, and the value with its alias followed.

func Pairs

func Pairs(n *yaml.Node) []Pair

Pairs is MappingPairs read by a view of its own, for a caller reading one mapping once, a document node unwrapped first: the view a walk shares is what keeps a merge chain from going cubic when every level of it is read.

type Step

type Step uint8

Step is what a Walk's visitor asks of the node it was handed.

const (
	// Descend visits the node's children next.
	Descend Step = iota
	// Prune leaves the node's children unvisited.
	Prune
	// Stop ends the walk.
	Stop
)

type View

type View struct {
	// contains filtered or unexported fields
}

View reads a raw yaml.Node tree as speakeasy's unmarshaller does, dereferencing aliases and expanding `<<` merge keys (yml.ResolveAlias, yml.ResolveMergeKeys). A cycle the scan misses because it reads a different tree than the resolver faults the process (GitHub #26), so every mapping read in this file goes through a View.

It memoizes each mapping's expansion, since otherwise a merge chain goes cubic. The memo is a pure cache, answering as a fresh view would at the same depth, so one view can be shared across walks (see expansion and View.serves). MergeDepthLimit and maxCachedPairs bound it. keyIndex adds key maps for pointer walks.

func New

func New() *View

New returns an empty view; a view must not outlive the node tree whose expansions it caches.

func (*View) ChildByToken

func (v *View) ChildByToken(n *yaml.Node, token string) *yaml.Node

ChildByToken returns the child of a mapping (by key) or sequence (by index) node named by one JSON pointer token, or nil when absent. The mapping arm reads through the view, so pointer navigation resolves an alias key and an aliased or merged value as MappingPairs reads them.

n itself is not dereferenced, unlike MappingPairs: an alias handed here matches neither arm and answers nil. Every caller walks with a dereference at each hop, as DocumentPath does, so the difference is unreachable; it is written down because that sibling promises the opposite.

func (*View) DocumentPath

func (v *View) DocumentPath(root *yaml.Node, pointer jsontext.Pointer) (path []*yaml.Node, complete bool)

DocumentPath walks pointer, a position in this document, from root as RFC 6901 reads it, returning the root and each node reached, aliases dereferenced. complete reports whether every token was followed; if not, the path ends at the last node reached. A lone '/' names the root's member keyed "", as ids.Ptr("") spells it, so a caller reading $id down a path sees one written there.

func (*View) Exhausted

func (v *View) Exhausted() bool

Exhausted reports whether the view stopped short of a full expansion at its merge-depth bound. A caller that refuses a document on incomplete information needs to say so rather than report a clean scan, which is the one thing the bound must not be allowed to hide.

func (*View) Expanded

func (v *View) Expanded(n *yaml.Node) bool

Expanded reports whether n's pairs are all its `<<` merges supply, read as a pointer walk reads them: false for a mapping whose merges run past MergeDepthLimit, where a key it lacks may lie past the bound. A node that is no mapping has nothing to expand.

func (*View) MappingPairs

func (v *View) MappingPairs(n *yaml.Node) []Pair

MappingPairs returns the effective pairs of a mapping node in the order the parser's model holds them (yml.ResolveMergeKeys): first those its `<<` keys merge in, an earlier source winning a shared key and none overriding a key the mapping writes itself, then its own, a key written twice at its last copy.

n is dereferenced, so an alias standing in for a whole mapping can be passed directly; a non-mapping node (including nil) yields no pairs. The returned slice is the view's own memo — callers must treat it as read-only.

func (*View) Repeat

func (v *View) Repeat(n *yaml.Node) (key string, in *yaml.Node, ok bool)

Repeat returns a key that the mapping n, or a mapping one of its `<<` keys merges in, writes more than once, with the mapping writing it, and whether there is one: n's own first, the one whose second copy comes first, then each source's in the order they merge. MappingPairs settles such a key by the library's rules, so a reader that must hold one copy faithfully, as a value does, asks this to refuse instead. n is dereferenced.

type Walk

type Walk struct {
	// Nodes bounds how many nodes the walk visits. A walk that would visit
	// more stops there and reports itself Cut; a bound below one visits none.
	// It is a cap, not a budget.Limit, whose zero is unbounded: a walk left
	// unbounded by omission is the one thing it rules out. A walk under a
	// budget passes the limit's Cap or Past.
	Nodes int
	// Depth, when above zero, bounds how deep the walk visits, the root at
	// depth zero: a node deeper is not visited, and the walk is Cut. Nodes
	// bounds the depth either way.
	Depth int
	// Aliases says what an alias stands for.
	Aliases Aliases
	// Visit is handed each node and its depth, and says whether to descend.
	// Unset, the walk descends everywhere, which counts a tree's nodes.
	Visit func(n *yaml.Node, depth int) Step
	// Leave, when set, is handed each node Visit descended into once its
	// children have all been visited, or at once for a node holding none.
	Leave func(n *yaml.Node, depth int)
}

Walk is a bounded, iterative walk over a raw YAML tree as written, through Content and in document order, visiting each node before its children. A reader that visits every node written runs one rather than keeping a stack and a bound of its own, so a cut short walk is reported rather than silent wherever one runs. A walk addressing positions as the parser reads them, where a merged pair's value is no child of the mapping merging it, keeps a frame per position instead.

func (Walk) Run

func (w Walk) Run(ctx context.Context, root *yaml.Node) Outcome

Run walks the tree under root. A nil root, or a nil node in a Content list, which no parse produces, is not visited. Once ctx is done the walk stops, within AskEvery nodes, and reports itself Cut.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL