A typescript library for executing ShapePaths
This is a monorepo which holds:
- the shape-path-core module and
- a playground (live webapp | source)
2021-07-17 ericP: changed predicate separator for ::thisTripleExpr from . to ~ because . is legal in localNames
2026-08-22: thisTripleExpr:: follows an Inclusion. ShExC's &<#label>
compiles to a bare label where a triple expression would be, and it means the
expression that label names is part of this body -- which is how the matcher
reads it. The axis stopped there, so ~<iri>, which is built on it, reported
a shape's body as smaller than the matcher does: a constraint a shape included
by reference could not be addressed through that shape at all.
An expression the walk has already reported is not reported again, so an
expression that includes itself, and one included twice, are each that
expression once. Note that an included expression is one expression however
many bodies take it in: @<#A>~<p> and @<#B>~<p> reach the same node when
both include it, and something hung there is hung there for both.
2026-08-20: $<label> selects the triple expression declared with that label,
joining @<label> (a shape expression) and ~<iri> (the triple constraint on
a predicate). ShExJ has no top-level list of triple expressions the way it has
shapes, and a label may sit on an EachOf, a OneOf or a TripleConstraint at
any depth -- including inside the inline shape of some constraint's value
expression -- so the lookup walks the whole schema. $ is the sigil ShExC
uses to declare one.
2026-08-19: [N] selects the node at position N, counting from 0.
It is the grammar's shorthand for [index() = N] (filterExpr -> Filter(index, [numericExpr])), and index() has always reported the 0-based position, so
the two have to agree. This is not XPath's [1]-is-first: XPath's aggregate
is position(), ShapePath's is index(), and the rename is the signal. If
ShapePath would rather count from 1, index() moves with it.
Until this was written down, [N] ignored N and passed every node whose
position was truthy, so [0], [1] and [2] all selected the same thing --
everything but the first.