wit_bindgen_core/
path.rs

1use heck::ToSnakeCase;
2use wit_parser::{PackageId, Resolve};
3
4/// If the package `id` is the only package with its namespace/name combo
5/// then pass through the name unmodified. If, however, there are multiple
6/// versions of this package then the package module is going to get version
7/// information.
8pub fn name_package_module(resolve: &Resolve, id: PackageId) -> String {
9    let pkg = &resolve.packages[id];
10    let versions_with_same_name = resolve
11        .packages
12        .iter()
13        .filter_map(|(_, p)| {
14            if p.name.namespace == pkg.name.namespace && p.name.name == pkg.name.name {
15                Some(&p.name.version)
16            } else {
17                None
18            }
19        })
20        .collect::<Vec<_>>();
21    let base = pkg.name.name.to_snake_case();
22    if versions_with_same_name.len() == 1 {
23        return base;
24    }
25
26    let version = match &pkg.name.version {
27        Some(version) => version,
28        // If this package didn't have a version then don't mangle its name
29        // and other packages with the same name but with versions present
30        // will have their names mangled.
31        None => return base,
32    };
33
34    // Here there's multiple packages with the same name that differ only in
35    // version, so the version needs to be mangled into the Rust module name
36    // that we're generating. This in theory could look at all of
37    // `versions_with_same_name` and produce a minimal diff, e.g. for 0.1.0
38    // and 0.2.0 this could generate "foo1" and "foo2", but for now
39    // a simpler path is chosen to generate "foo0_1_0" and "foo0_2_0".
40    let version = version
41        .to_string()
42        .replace('.', "_")
43        .replace('-', "_")
44        .replace('+', "_")
45        .to_snake_case();
46    format!("{base}{version}")
47}