ElementExtractor
Walks a document and emits the containers a set of paths stands for.
TermExtractor's sibling, and deliberately not a mode of it. That walk reaches its sink for scalars — a path landing on an object or an array reports nothing, which is why Exists($.items) over an array is false and has always been — and quietly widening it to report containers would change what every existing index and every existing predicate means. Two walks, one narrowing rule.
The narrowing, the budgets and the pruning are the same, and that is what has to stay true. This runs inside flush and compaction like the other one, so it carries IndexOptions.maxDepth and IndexOptions.maxChildren; a document that made the walk expensive would make the engine's background maintenance expensive. It is not CatalogPath.forEachNodeIn, which is a reader's walk with no budget at all and no ordinal in sight.
Public for the reason TermExtractor is. The recheck of a composite candidate has to be the code that built the term, not a second traversal that agrees with it today — so rabosh-query calls this class, and there is exactly one definition of "which containers does $.items[*] stand for in this document".