Skip to content

Combinators define relationships between packages in the dependency graph. They work similarly to CSS combinators but describe dependency relationships instead of DOM hierarchy.

Syntax

CombinatorNameDescription
>ChildDirect dependencies of the previously selected nodes
(space)DescendantAll direct & transitive dependencies
~SiblingDirect dependencies of all dependents of the previously selected nodes

Child combinator >

Matches packages that are direct dependencies of the previously selected nodes. Only one level deep.

Terminal
$ vlt query ':root > *'

Given this dependency graph:

my-app
├── react@18.2.0
│ └── loose-envify@1.4.0
│ └── js-tokens@4.0.0
└── typescript@5.3.0

:root > * selects only direct dependencies:

my-app
├── react@18.2.0 ✅ direct dependency of root
│ └── loose-envify@1.4.0
│ └── js-tokens@4.0.0
└── typescript@5.3.0 ✅ direct dependency of root

Chaining child combinators

You can chain > to select at specific depths:

Terminal
$ vlt query ':root > * > *'
my-app
├── react@18.2.0
│ └── loose-envify@1.4.0 ✅ grandchild of root
│ └── js-tokens@4.0.0
└── typescript@5.3.0

Descendant combinator (space)

Matches all packages that are direct or transitive dependencies of the previously selected nodes. Any depth.

Terminal
$ vlt query ':root [name=js-tokens]'
my-app
├── react@18.2.0
│ └── loose-envify@1.4.0
│ └── js-tokens@4.0.0 ✅ transitive dependency of root
└── typescript@5.3.0

Descendant vs. child

Terminal
# Direct deps only
$ vlt query ':root > [name=js-tokens]'
# → no results (js-tokens is not a direct dependency)
# All transitive deps
$ vlt query ':root [name=js-tokens]'
# → js-tokens@4.0.0 (found transitively)

Sibling combinator ~

Matches packages that are direct dependencies of all dependents of the previously selected nodes. In other words: “other packages that share the same parent.”

Terminal
$ vlt query '[name=react] ~ *'

Given:

my-app
├── react@18.2.0
├── react-dom@18.2.0
└── typescript@5.3.0

[name=react] ~ * selects siblings of react (other direct deps of the same parent):

my-app
├── react@18.2.0
├── react-dom@18.2.0 ✅ sibling of react
└── typescript@5.3.0 ✅ sibling of react

Combining with selectors

Combinators are most powerful when combined with attribute selectors and pseudo-classes:

Find all direct dependencies that are outdated:

Terminal
$ vlt query ':root > :outdated'

Find workspaces that depend on packages with CVEs:

Terminal
$ vlt query ':workspace > :cve(*)'

Find all transitive dependencies of a specific package:

Terminal
$ vlt query '[name=react] *'

See also