=begin rakudoc

=TITLE Adding Tree Navigators

=SUBTITLE Teaching the generic tree walker about new tree-shaped data

=head1 Overview

Tree navigators adapt concrete tree-shaped values to Qwiratry's generic tree
operations.

Use this extension point when the existing tree walker semantics are right, but
Qwiratry needs to learn how to inspect a new node model. A navigator answers
questions such as:

=item Which types or roles it supports.

=item Which direct children a node has.

=item Which parent a node has, either from the node model or by walking from an
origin.

=item Which attribute-like values a node exposes.

Do not add a new walker just because a tree uses custom node objects. Add a
walker when traversal or query execution semantics change.

=head1 When To Add A Navigator

Add a C<TreeNavigator> when:

=item A format parses into custom node objects rather than ordinary hashes and
arrays.

=item An external object model, such as C<RakuAST::Node>, already owns parsing
and rendering but still needs Qwiratry traversal.

=item The default container navigator cannot identify children or parents for
the data.

Do not add one when the data is already ordinary C<Positional> or C<Associative>
values that expose child values in the default shape.

=head1 Contract

A tree navigator does C<Qwiratry::Tree::Navigator::Base>.

Prefer typed multi candidates so multiple dispatch selects the relevant
implementation. Broad C<Mu> candidates should only be empty fallbacks.

When overriding C<tree-children> in a custom navigator, also override the
C<Positional> and/or C<Associative> candidates you care about. A C<Mu>-only
override does not hide the base typed candidates from the multi dispatch set.

=begin code :lang<raku>
use Qwiratry::Tree::Navigator::Base;

class Qwiratry::Tree::Navigator::Example
		does Qwiratry::Tree::Navigator::Base {
	method supported-types(--> List) {
		(Example::Node,)
	}

	multi method tree-children(Example::Node $node --> List) {
		$node.children.list
	}

	multi method tree-child-results(Example::Node $node, Mu $selector, Int :$limit --> List) {
		# Prefer constrained lookup over fetching every child first.
		self.tree-children($node).grep({ ... }).head($limit // Inf).list
	}
}
=end code

=head2 C<supported-types>

=begin code :lang<raku>
method supported-types(--> List)
=end code

Returns the types or roles this navigator supports. C<Qwiratry::Tree::Navigator>
uses these to choose a navigator for a node.

=head2 C<tree-children>

=begin code :lang<raku>
multi method tree-children(Positional $node --> List)
multi method tree-children(Associative $node --> List)
multi method tree-children(Mu $node --> List)
=end code

Returns direct children of C<$node>.

The default associative behavior keeps demo trees that store a positional
C<children> key. Other associative maps expose nested containers only, so scalar
JSON fields are not treated as structural children. Use C<tree-child-results> or
C<tree-attribute-value> to follow or read those keys.

=head2 C<tree-child-results>

=begin code :lang<raku>
multi method tree-child-results(Positional $node, Mu $selector, Int :$limit --> List)
multi method tree-child-results(Associative $node, Mu $selector, Int :$limit --> List)
multi method tree-child-results(Mu $node, Mu $selector, Int :$limit --> List)
=end code

Returns children matching C<$selector>, optionally capped by C<$limit>.

Evaluators call this instead of fetching all children and filtering locally.
For ordinary associative maps, a string selector first tries hash-key lookup so
C<⪪ <owner>> follows JSON keys. XML/HTML navigators should override this to use
element-child semantics instead.

Descendant walks (C<< ⪪⪪ >>) are owned by the query evaluator
(C<DescendantEvaluator>), which composes this one-step lookup with
C<tree-children>. Navigators should not implement recursive descendant walks
for query matching; they may still expose multi-step helpers used by Cursors
and Evaluators (see below).

=head2 C<tree-parent>

=begin code :lang<raku>
method tree-parent(Mu $node, Mu :$origin --> Mu)
=end code

Returns the direct parent of C<$node> when known.

The base role first asks the node model for C<parent>, if available. If
C<origin> is supplied, it then falls back to walking from C<origin> using the
navigator's C<tree-children> method. Custom navigators only need to override
this when the node model has a better parent lookup.

=head2 C<tree-attributes>

=begin code :lang<raku>
multi method tree-attributes(Associative $node --> Associative)
multi method tree-attributes(Mu $node --> Associative)
=end code

Returns attribute-like values when the node model has them. The default returns
the node itself for associative values and an empty hash otherwise.

=head2 C<tree-attribute-value>

=begin code :lang<raku>
multi method tree-attribute-value(Associative $node, Mu $key --> Mu)
multi method tree-attribute-value(Mu $node, Mu $key --> Mu)
=end code

Return one attribute or key value from C<$node>. Attribute access goes through
the navigator so XML attributes and JSON keys can differ from child navigation.
C<⥷> uses C<tree-attribute-value>.

=head2 Multi-Step Helpers And Walk-Local Caches

C<Qwiratry::Tree::Navigator::Base> also provides multi-step sector helpers used
by L<Qwiratry::QueryCursor> and the Navigation Evaluator, including
C<tree-ancestors>, C<tree-descendants>, C<tree-sector-seq>, and related
following/preceding walks.

Registry / shared navigators stay cache-free. Cursors mint B<walk-local>
navigators via C<tree-navigator-walk-local> (or C<walk-local-copy>). Those
instances may cache; C<Tree::Replace> invalidates through
C<invalidate-caches> when C<$*QWIRATRY-WALK-NAVIGATOR> is set. Do not put
mutable walk caches on discovered registry instances.

=head1 Discovery

Navigator discovery is separate from format discovery. A navigator class lives
under the tree navigator namespace:

=begin code :lang<raku>
Qwiratry::Tree::Navigator::<NAVIGATOR>
=end code

Add the navigator module to C<META6.json> C<provides> so discovery can load it:

=begin code :lang<raku>
"Qwiratry::Tree::Navigator::Example": "lib/Qwiratry/Tree/Navigator/Example.rakumod"
=end code

Then callers can inspect or create the navigator:

=begin code :lang<raku>
my @navigators = Qwiratry::Tree::Navigator.navigators;
my $navigator = Qwiratry::Tree::Navigator.make(:navigator<Example>);
=end code

=head2 Selection Order

C<Qwiratry::Tree::Navigator.tree-navigator-for($node)> selects navigators in this order:

=item A caller-supplied navigator passed as C<:navigator>.

=item Discovered navigators under C<Qwiratry::Tree::Navigator::*>.

=item Domain-supplied navigators registered for metadata attached through
C<Qwiratry::Walker::Providing>.

=item Explicitly registered navigators selected by their C<supported-types>.

=item The built-in default navigator for ordinary C<Positional> and
C<Associative> values.

Pass C<:origin> when domain metadata or parent fallback should be resolved from
the traversal root:

=begin code :lang<raku>
my $navigator = Qwiratry::Tree::Navigator.tree-navigator-for($node, :origin($root));
=end code

=head2 Explicit Registration

Register a navigator directly when it is not supplied by a format module:

=begin code :lang<raku>
Qwiratry::Tree::Navigator.register-tree-navigator($navigator);
=end code

The navigator is selected for nodes matching one of its C<supported-types>.

Register a navigator for one exact type or role when the registration site
should own the mapping:

=begin code :lang<raku>
Qwiratry::Tree::Navigator.register-tree-navigator-for-type(Example::Node, $navigator);
=end code

=head2 Domain Registration

Register a navigator for roots or nodes carrying a domain label:

=begin code :lang<raku>
Qwiratry::Tree::Navigator.register-tree-navigator-for-domain('xml', $navigator);
=end code

Domain labels come from C<Qwiratry::Walker::Providing>. This keeps navigator
domain metadata aligned with existing walker and schema metadata.

=head1 Navigator-Only Models

Some representations do not need Qwiratry parse or render classes. C<RakuAST> is
the built-in example: the compiler owns parsing and rendering, but Qwiratry can
still provide C<Qwiratry::Tree::Navigator::RakuAST>.

A navigator-only model should provide C<Qwiratry::Tree::Navigator::<NAVIGATOR>>
without format C<::Parse> or C<::Render> classes.

=head1 Testing

Add tests that prove:

=item C<Qwiratry::Tree::Navigator.navigators> discovers the navigator.

=item C<Qwiratry::Tree::Navigator.make(:navigator<NAVIGATOR>)> returns a
navigator that does C<Qwiratry::Tree::Navigator::Base>.

=item C<supported-types> includes the intended node type or role.

=item C<Qwiratry::Tree::Navigator.tree-navigator-for($node)> selects the navigator.

=item Caller-supplied, domain-registered, and explicitly type-registered
navigators are selected in the documented order.

=item C<tree-children> exposes direct children.

=item C<tree-parent($node, :origin($root))> works when parent lookup is required.

=head1 Reference Material

=head2 Main Types

=item C<Qwiratry::Tree::Navigator::Base>

Role implemented by tree navigators, and the built-in navigator for ordinary
C<Positional> and C<Associative> tree-shaped values.

=item C<Qwiratry::Tree::Navigator>

Discovery service and registry for tree navigator implementations.

=end rakudoc
