Skip to content

Commit

Permalink
feat(cli): nodejs loader (#515)
Browse files Browse the repository at this point in the history
<!--
Pull requests are squash merged using:
- their title as the commit message
- their description as the commit body

Having a good title and description is important for the users to get
readable changelog and understand when they need to update his code and
how.
-->

### Describe your change

Add support for using nodejs runtime to execute and serialize typescript
based typegraphs. This also adds support for `MCLI_LOADER_CMD` that can
be used to override the command to exec the typegraphs.

### Motivation and context

Previously, `meta-cli` either used the and `python` & `deno` runtimes to
serialize the typegraphs. Now that `@typegraph/sdk` also supports
Node.js, users might be developing in environments wher `deno` runtime
is not availaible but `node` is. This PR provides a way fwd in those
cases.

### Migration notes

<!-- Explain HOW users should update their code when required -->

### Checklist

- [ ] The change come with new or modified tests
- [x] Hard-to-understand functions have explanatory comments
- [ ] End-user documentation is updated to reflect the change
  • Loading branch information
Yohe-Am authored Dec 7, 2023
1 parent 32394d9 commit 747919d
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 15 deletions.
3 changes: 2 additions & 1 deletion examples/templates/node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"type": "module",
"version": "1.0.0",
"scripts": {
"start": "tsx api.ts"
"load-tgraph": "tsx",
"dev": "MCLI_LOADER_CMD='npm load-tgraph' meta-cli dev"
},
"dependencies": {
"@typegraph/sdk": "^0.2.4"
Expand Down
5 changes: 3 additions & 2 deletions meta-cli/src/codegen/deno.rs
Original file line number Diff line number Diff line change
Expand Up @@ -506,8 +506,9 @@ mod tests {
));

let mut event_rx = event_rx;
let LoaderEvent::Typegraph(tg) = event_rx.recv().await.unwrap() else {
bail!("error");
let tg = match event_rx.recv().await.unwrap() {
LoaderEvent::Typegraph(tg) => tg,
evt => bail!("unexpected loader evt: {evt:?}"),
};
let module_codes = Codegen::new(&tg, &typegraph_test).codegen()?;
assert_eq!(module_codes.len(), 1);
Expand Down
142 changes: 130 additions & 12 deletions meta-cli/src/typegraph/loader/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ impl Loader {
});
}
}
let command = Self::get_load_command(ModuleType::try_from(&*path).unwrap(), &path)?;
let command = Self::get_load_command(ModuleType::try_from(&*path).unwrap(), &path).await?;
self.load_command(command, &path).await
}

Expand Down Expand Up @@ -138,7 +138,22 @@ impl Loader {
}
}

fn get_load_command(module_type: ModuleType, path: &Path) -> Result<Command, LoaderError> {
async fn get_load_command(
module_type: ModuleType,
path: &Path,
) -> Result<Command, LoaderError> {
let vars: HashMap<_, _> = env::vars().collect();

if let Ok(argv_str) = std::env::var("MCLI_LOADER_CMD") {
let argv = argv_str.split(' ').collect::<Vec<_>>();
let mut command = Command::new(argv[0]);
command
.args(&argv[1..])
.arg(path.to_str().unwrap())
.envs(vars);
return Ok(command);
}

match module_type {
ModuleType::Python => {
ensure_venv(path).map_err(|e| LoaderError::PythonVenvNotFound {
Expand All @@ -157,19 +172,122 @@ impl Loader {
Ok(command)
}
ModuleType::Deno => {
let vars: HashMap<_, _> = env::vars().collect();
let mut command = Command::new("deno");
command
.arg("run")
.arg("--unstable")
.arg("--allow-all")
.arg("--check")
.arg(path.to_str().unwrap())
.envs(vars);
Ok(command)
// TODO cache result?
match detect_deno_loader_cmd(path)
.await
.map_err(|error| LoaderError::Unknown {
path: path.into(),
error,
})? {
TsLoaderRt::Deno => {
let mut command = Command::new("deno");
command
.arg("run")
.arg("--unstable")
.arg("--allow-all")
.arg("--check")
.arg(path.to_str().unwrap())
.envs(vars);
Ok(command)
}
TsLoaderRt::Node => {
log::debug!("loading typegraph using npm x tsx, make sure npm packages have been installed");
let mut command = Command::new("npm");
command
.arg("x")
.arg("tsx")
.current_dir(path.parent().unwrap())
.arg(path.to_str().unwrap())
.envs(vars);
Ok(command)
}
TsLoaderRt::Bun => {
log::debug!("loading typegraph using bun x tsx, make sure npm packages have been installed");
let mut command = Command::new("bun");
command
.arg("x")
.arg("tsx")
.current_dir(path.parent().unwrap())
.arg(path.to_str().unwrap())
.envs(vars);
Ok(command)
}
}
}
}
}
}

enum TsLoaderRt {
Deno,
Node,
Bun,
}
async fn detect_deno_loader_cmd(tg_path: &Path) -> Result<TsLoaderRt> {
use TsLoaderRt::*;
let test_deno_exec = || async {
Command::new("deno")
.arg("--version")
.output()
.await
.map(|out| out.status.success())
.map_err(|err| anyhow!(err))
};
let test_node_exec = || async {
Command::new("node")
.arg("-v")
.output()
.await
.map(|out| out.status.success())
.map_err(|err| anyhow!(err))
};
let test_bun_exec = || async {
Command::new("deno")
.arg("--version")
.output()
.await
.map(|out| out.status.success())
.map_err(|err| anyhow!(err))
};
let mut maybe_parent_dir = tg_path.parent();
// try to detect runtime in use by checking for package.json/deno.json
// files first
loop {
let Some(parent_dir) = maybe_parent_dir else {
break;
};
use tokio::fs::try_exists;
if try_exists(parent_dir.join("deno.json")).await.is_ok()
|| try_exists(parent_dir.join("deno.jsonc")).await.is_ok()
{
return Ok(Deno);
}
if try_exists(parent_dir.join("package.json")).await.is_ok() {
// TODO: cache the test values without making a spaghetti mess
// lazy async result values are hard to Once/LazyCell :/
if test_node_exec().await? {
return Ok(Node);
}
if test_bun_exec().await? {
return Ok(Bun);
}
}
maybe_parent_dir = parent_dir.parent();
}
// if no package manifest found, just use the first runtime found in the
// following order
if test_deno_exec().await? {
return Ok(Deno);
}
if test_node_exec().await? {
return Ok(Node);
}
if test_bun_exec().await? {
return Ok(Bun);
}
Err(anyhow::format_err!(
"unable to find deno, node or bun runtimes"
))
}

#[derive(Debug)]
Expand Down

0 comments on commit 747919d

Please sign in to comment.