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}