Ic-wasm metadata did import service

Morning! Does ic-wasm resolve the import service from a .did file when it’s used to add a public metadata section from a file?

# a.did
import service "b.did";

ic-wasm "demo.wasm" -o "demo.wasm" metadata candid:service -f "a.did" -v public --keep-name-section

If not, what’s the common solution if there is one?

1 Like

ic-wasm metadata simply attaches the exact content to the designated metadata section. ic-wasm does not handle the candid:service section specially; it has no Candid-related logic, such as parsing or resolving import service statements.

In my opinion, the candid:service section should contain a self-contained Candid interface without referring to other Candid files. Ideally, a tool would convert a Candid file with import statements into one without them. Unfortunately, I don’t believe such a tool currently exists, and we should definitely consider creating one.

Thank you for your answer, @lwshang. It confirms my understanding.

we should definitely consider creating one.

Is this already being tracked? If not, should I open an issue somewhere in a repo, or can you take care of starting its tracking?

Nope, it’s not being tracked right now. So, if you could open an issue in the Candid repo, that would be super helpful.

1 Like

Sure thing!

Done :backhand_index_pointing_right: https://github.com/dfinity/candid/issues/613

1 Like

Cross posting for reference from Tool or function to convert Candid file with import statements · Issue #613 · dfinity/candid · GitHub.

I think you can already achieve what you need using the candid and candid_parser crates.

Assuming you have the following Candid declaration files:

// a.did
import service "b.did";

service : {
  greet : (text) -> (text);
};
// b.did
service : {
    greet_from_b : (text) -> (text)
}

and your Rust script looks like:

use std::path::Path;

use candid::{TypeEnv, pretty::candid::compile};
use candid_parser::{IDLProg, check_file, check_prog};

const FILE_PATH: &str = "./a.did";

fn main() {
    let (env, actor) = check_file(Path::new(FILE_PATH)).unwrap();
    let content = compile(&env, &actor);

    // This block checks that the output is valid candid, can be skipped
    {
        let ast = content.parse::<IDLProg>().unwrap();
        check_prog(&mut TypeEnv::new(), &ast).unwrap();
    }

    println!("{content}");
}

The output of this program will be:

service : { greet : (text) -> (text); greet_from_b : (text) -> (text) }

@peterparker is this what you need?

1 Like

Amazing @ilbert! This does indeed seem to be exactly what I need. Plus, I already have a custom wrapper around didcjunobuild-didc — which I use to generate TypeScript and JavaScript with the Juno CLI (mainly because I wanted something installable via cargo install, which isn’t the case with didc, and tailored arguments).

Long story short, I can extend it with your suggested code, as I just did in the following PR!

Thanks!

1 Like

Great!

As a side question, I’m interested in this choice: was it too complicated to contribute to the original didc tool to add such features? If yes, what made them so complicated?

More broadly, I think the IC ecosystem would benefit a lot if we all contributed together to making the dev experience better and better, by improving the existing tools and libraries as much as we can. Plus, your contributions are always so valuable!

I’m not sure if it was too complicated, but I definitely didn’t have the time to discuss, (try to) argue, or wait for the feature to be potentially prioritized when I needed those capabilities for a broader implementation — so I went with a custom-tailored wrapper.

The IC ecosystem benefits from it too: it’s available out of the box for anyone using Juno, and it’s open source.