Add utility for retrieving full import paths
Closed this issue · 10 comments
As discussed in here: rust-lang/rust#104651 (comment)
It would be useful to provide a utility function to retrieve import paths for items.
As discussed in #5, I'd think this crate should remain as a pure reexport of rustdoc-json
. That said I think theirs room for a rustdoc-json-utils
(or similar) crate that would have common functionality like this (and probably also a loader that gives good errors on version mismatch)
That's a fair choice, anybody willing to take that crate on?
Just noticed this issue -- cargo-semver-checks
needed this functionality too, and I implemented it via a combination of crates:
trustfall-rustdoc-adapter
which wraps a particularrustdoc-types
and rustdoc JSON versiontrustfall-rustdoc
which wraps multiple major versions of the above, and dispatches to the correct one as needed based on the rustdoc JSON version we're seeing.
I don't have time to fully write up the cargo-semver-checks
architecture or its internal crates, but the functionality is there and I've described some of it in blog posts. It even accounts for glob imports, cases of ambiguity, and namespace-specific edge cases (e.g. function and type names are not in the same namespace).
You probably would need to use the Trustfall query engine to use it in the best way, unless you wanted to fork those crates and use the underlying code directly (which you are of course welcome to do if you don't mind maintaining a fork).
Any update on this? Is it possible to retrieve the full import paths now? :)
Only via trustfall-rustdoc-adapter
and/or trustfall-rustdoc
, AFAIK.
I would be very surprised if the algorithm ever ships as part of rustdoc-types
, since it's extremely complex and is subject to design decisions like "what to do about items with infinitely many paths." I don't think a one-size-fits-all approach is possible, so I don't think rustdoc-types
is likely to ship something here.
If you're interested in reusing some of my work, I'd be happy to point you in the right direction.
For completeness and future reference: The public-api crate also has this capability and is also an option for you.
@obi1kenobi Yes, I'd be very interested in this functionality, it's totally fine with me if I have to depend on trustfall crates for this, I'd really appreciate if you can point me in the right direction 🙂🙏
Oh neat, I didn't know that public-api
also computes full import paths! I wasn't able to find that functionality in the docs, but perhaps I just looked in the wrong place.
@obi1kenobi Yes, I'd be very interested in this functionality, it's totally fine with me if I have to depend on trustfall crates for this, I'd really appreciate if you can point me in the right direction 🙂🙏
If you know you are working with a specific rustdoc format version (e.g. v34), you'd use the corresponding major version of trustfall-rustdoc-adapter
(e.g. v34.x.y):
- After parsing with
rustdoc-types
, you'd pass a&rustdoc_types::Crate
to create the adapter'sIndexedCrate
type IndexedCrate
then has useful convenience methods, like getting full import paths (including deprecation anddoc(hidden)
data for each path!) and determining whether a trait is sealed per the (complex!) rules described in this post: https://predr.ag/blog/is-this-trait-sealed-or-not-sealed/
Of course now that you have Trustfall adapter, you can also use it to run Trustfall queries over the rustdoc as well — the same queries as in the playground.
And if you aren't sure which exact rustdoc format version you'll get, the trustfall-rustdoc
allows abstracting across multiple versions and running queries over whichever one you happen to get.
Two more notes:
- The "full import paths" functionality will protect you against cases like "items with infinite re-export loops," so it should be safe to call on an arbitrary rustdoc. In case of loops, it will return all paths that don't close any loop (i.e. no place appears more than once in the path).
doc(hidden)
is computed on a per-path level: some paths may be hidden, and others may be public. An item is public API if any of its paths are non-hidden. The canonical example of that is:
#[doc(hidden)]
mod hidden {
pub struct Example;
}
// Users can import this as `my_crate::Example`,
// which does not pass through any `doc(hidden)` components.
// So this is public API!
pub use hidden::Example;
To clarify: In the public-api
crate there is currently no API for "give me all paths to the item with ID foo", but if you list the public API you will get all paths to an item. (So maybe it's of no good use to you after all.)
Example
For this crate:
pub mod first_path {
pub fn the_item() {}
}
pub mod second_path {
pub use crate::first_path::the_item;
}
All (both) paths to the public item are listed:
$ cargo public-api
pub mod diff_test
pub mod diff_test::first_path
pub fn diff_test::first_path::the_item()
pub mod diff_test::second_path
pub fn diff_test::second_path::the_item()
And we also handle infinite export loops. But we currently don't handle doc(hidden)
properly.
(The example use the cargo public-api
CLI, but it is essentially a CLI for the public-api
crate.)