Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

npx ezno check does not check code? #204

Open
rotu opened this issue Sep 1, 2024 · 9 comments
Open

npx ezno check does not check code? #204

rotu opened this issue Sep 1, 2024 · 9 comments
Labels
bug Something isn't working cli Command line interface

Comments

@rotu
Copy link
Contributor

rotu commented Sep 1, 2024

I'm trying to get started with ezno and npx ezno check file.ts does not print anything and exits with code 0.

$ npx ezno info
ezno@0.0.22 (#10617350335)

A JavaScript type checker and compiler. For use as a library or through the CLI
Repository: https://github.com/kaleidawave/ezno, License: MIT

For help run --help

$ cat file.ts
const k: number = "abc"
$ npx ezno check file.ts
$

I'm using ezno@0.0.22 installed via npm on Mac OS.

@rotu
Copy link
Contributor Author

rotu commented Sep 1, 2024

Building with cargo and running does produce the expected output, so it seems this is a problem with the npm package itself.

$ /Users/dan/Source/ezno/target/debug/ezno check ./file.ts 
error: 
  ┌─ file.ts:1:19

1 │ const k: number = "abc"
  │          ------   ^^^^^ Type "abc" is not assignable to type number
  │          │         
  │          Variable declared with type number

@rotu
Copy link
Contributor Author

rotu commented Sep 1, 2024

I don't know how to debug this. I get as far as this call:

run_cli(cliArguments, readFile, writeFile, readFromCLI);

where cliArguments is ["check","file.ts"]

And after that, it steps into wasm code, which I don't know how to debug.

@rotu rotu changed the title Ezno check doesn't seem to do anything? npx ezno check does not check code? Sep 1, 2024
@kaleidawave
Copy link
Owner

Hmm yes maybe a problem with the bin field in package.json.

I presume npx ezno info does nothing as well.

NPM and related is a nightmare for packaging platform specific code and binaries 😡

@rotu
Copy link
Contributor Author

rotu commented Sep 2, 2024

I presume npx ezno info does nothing as well.

As show above, npx ezno info does show info about ezno. So I don't think it's the bin field.

Additionally, even running this module with deno exits silently:

deno --allow-all /Users/dan/Source/try-ezno/node_modules/ezno/dist/cli.mjs check ./file.ts

Or via npm imports, also exits silently:

deno --allow-all 'npm:ezno' check file.ts

NPM and related is a nightmare for packaging platform specific code and binaries 😡

I bet! If you know a way to get sourcemaps working so that I can step into the Rust code, that would certainly help!

@kaleidawave
Copy link
Owner

Sorry misread the last message. Ah that is good npx ezno info works, so it is an issue with the check command for the CLI in the WASM edition.

Looking at the code: I think it is maybe due to the glob support for checking files, which has been added since the last release.

ezno/src/cli.rs

Line 215 in cd8e961

Err(_) => return ExitCode::FAILURE,

If you add a similar print_to_cli message with the error under that branch then that might be the cause. I forgot to check how the glob library worked under WASM.

I don't know if you can do WASM source maps? rustwasm/wasm-pack#824

@rotu
Copy link
Contributor Author

rotu commented Sep 6, 2024

Looking at the code: I think it is maybe due to the glob support for checking files, which has been added since the last release.

Indeed the glob support is the cause of failure.

ezno/src/cli.rs

Lines 467 to 469 in cd8e961

if files.is_empty() {
eprintln!("Input {input:?} matched no files");
Err(())

  1. Execution enters the files.is_empty branch.
  2. It appears nothing is printed by the line eprintln!("Input {input:?} matched no files"); nor a print_to_cli statement after, so I think that line panics.
  3. While glob() admits relative paths, I suspect filesystem access is broken since env::current_dir() gives me Err(Error { kind: Unsupported, message: "operation not supported on this platform" })

@rotu
Copy link
Contributor Author

rotu commented Sep 6, 2024

Okay I think I'm starting to understand Rust, WASM, and wasm-pack. In particular, just about any sort of system call is going to fail. If filesystem access and stdio is needed, it seems prudent to use wasi for this.

WASI is a set of APIs defined for the WebAssembly Component Model to help components interact with the outside world. Core WebAssembly has no intrinsic ability to access the host, for example println! don’t work, but WASI defines how to do so with the wasi:cli/stdio package.

@kaleidawave
Copy link
Owner

Yep WASM by itself just implements standard instructions. WASI adds more functions for handling system things etc.

However with just base WASM you can import functions in two ways.

Either with an extern block which pulls a global function from JS environment. Which is good for global things

#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
pub(crate) fn log(s: &str);
}

Or using &js_sys::Function where the exposed function takes a function from an argument check((path) => { return readFileSync(path) }) which is good when you have different functions rather than a global

#[wasm_bindgen(js_name = check, skip_typescript)]
pub fn check_wasm(entry_path: String, fs_resolver_js: &js_sys::Function) -> WASMCheckOutput {

and this is how the CLI works

ezno/src/wasm_bindings.rs

Lines 125 to 140 in cd8e961

#[wasm_bindgen(typescript_custom_section)]
const TYPES_RUN_CLI: &str = r#"
export function run_cli(
cli_arguments: string[],
read_from_file: (path: string) => string | undefined,
write_to_file: (path: string, content: string) => void,
cli_input_resolver: (prompt: string) => string | undefined
): void
"#;
#[wasm_bindgen(js_name = run_cli, skip_typescript)]
pub fn run_cli_wasm(
cli_arguments: Box<[JsValue]>,
read_from_file: &js_sys::Function,
write_to_file: &js_sys::Function,
cli_input_resolver_js: &js_sys::Function,
) {


Having another look at the CLI and especially the glob as input support it uses eprintln! rather than the print_to_cli function, which works with WASM.

ezno/src/cli.rs

Lines 457 to 479 in cd8e961

fn get_entry_points(input: String) -> Result<Vec<PathBuf>, ()> {
match glob::glob(&input) {
Ok(files) => {
let files = files
.into_iter()
.collect::<Result<Vec<PathBuf>, glob::GlobError>>()
.map_err(|err| {
eprintln!("{err:?}");
})?;
if files.is_empty() {
eprintln!("Input {input:?} matched no files");
Err(())
} else {
Ok(files)
}
}
Err(err) => {
eprintln!("{err:?}");
Err(())
}
}
}

and unfortunately the rustc WASM build (which wasm-pack wraps) just compiles eprintln! to a no-op rather than producing a warning at compile or runtime :(.

Changing the eprintln! to print_to_cli for the above will help in figuring out this issue!

@kaleidawave kaleidawave added bug Something isn't working cli Command line interface labels Sep 7, 2024
@rotu
Copy link
Contributor Author

rotu commented Sep 8, 2024

My impression is that you either inject the effectful code you need as JS callbacks (which is what you’ve done with wasm_bindgen) OR you use a runtime adapter that does those things for you (which is the goal of wasi).

I believe that:

  1. You should be using the Rust-provided wasm32-wasip2 target.
  2. Your run_cli should not exist. WASI already specifies how to give your module access to input and output. Admittedly, the callbacks are more complicated, since they use stream abstractions, but you don’t have to worry too much about that because…
  3. Things like println! are automatically wired up in the wasm32-wasi* targets, with no need to rewrite for special wasi-aware APIs.1
  4. At the end of the day, the emitted module is still WASM. You may need to inject the missing system calls to actually get it to run in the browser, but that is doable2.

Footnotes

  1. https://wasmbyexample.dev/examples/wasi-hello-world/wasi-hello-world.rust.en-us.html

  2. https://github.com/taybenlor/runno/tree/main/packages/wasi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working cli Command line interface
Projects
None yet
Development

No branches or pull requests

2 participants