diff --git a/compiler/forget/Cargo.lock b/compiler/forget/Cargo.lock index 3070b1b752..24b3d5345f 100644 --- a/compiler/forget/Cargo.lock +++ b/compiler/forget/Cargo.lock @@ -285,9 +285,14 @@ dependencies = [ name = "forget_napi" version = "0.1.0" dependencies = [ + "forget_diagnostics", + "forget_estree", + "forget_hermes_parser", + "forget_semantic_analysis", "napi", "napi-build", "napi-derive", + "serde_json", ] [[package]] diff --git a/compiler/forget/crates/forget_napi/Cargo.toml b/compiler/forget/crates/forget_napi/Cargo.toml index 9ad812ed18..a505598a81 100644 --- a/compiler/forget/crates/forget_napi/Cargo.toml +++ b/compiler/forget/crates/forget_napi/Cargo.toml @@ -14,8 +14,13 @@ repository.workspace = true crate-type = ["cdylib"] [dependencies] +forget_diagnostics = { workspace = true } +forget_hermes_parser = { workspace = true } +forget_estree = { workspace = true } +forget_semantic_analysis = { workspace = true } napi = { version = "2.13.3", features = ["serde-json", "async"] } napi-derive = { version = "2.12" } +serde_json = { workspace = true } [build-dependencies] napi-build = "2" \ No newline at end of file diff --git a/compiler/forget/crates/forget_napi/README.md b/compiler/forget/crates/forget_napi/README.md new file mode 100644 index 0000000000..bb02e25338 --- /dev/null +++ b/compiler/forget/crates/forget_napi/README.md @@ -0,0 +1,13 @@ +# forget_napi + +This crate uses [napi-rs](https://napi.rs/) to expose Forget's analysis to JavaScript via the [Node-API](https://nodejs.org/api/n-api.html#node-api). + +## Build + +Note that `napi-rs` is a bit finicky and doesn't offer full control over where its outputs are emitted. For consistency, be sure to build with + +``` +yarn build +``` + +To use the canonical build, which will ensure that all files are placed in the right location. \ No newline at end of file diff --git a/compiler/forget/crates/forget_napi/src/lib.rs b/compiler/forget/crates/forget_napi/src/lib.rs index e5e122fbf8..97b882cac7 100644 --- a/compiler/forget/crates/forget_napi/src/lib.rs +++ b/compiler/forget/crates/forget_napi/src/lib.rs @@ -1,17 +1,115 @@ +use forget_diagnostics::Diagnostic; +use forget_semantic_analysis::{analyze, AnalyzeOptions}; use napi_derive::napi; +pub const GLOBALS: &[&str] = &[ + "AggregateError", + "Array", + "ArrayBuffer", + "AsyncFunction", + "AsyncGenerator", + "AsyncGeneratorFunction", + "AsyncIterator", + "Atomics", + "BigInt", + "BigInt64Array", + "BigUint64Array", + "Boolean", + "DataView", + "Date", + "decodeURI", + "decodeURIComponent", + "encodeURI", + "encodeURIComponent", + "Error", + "escape", + "eval", + "EvalError", + "FinalizationRegistry", + "Float32Array", + "Float64Array", + "Function", + "Generator", + "GeneratorFunction", + "globalThis", + "Infinity", + "Int16Array", + "Int32Array", + "Int8Array", + // "InternalError", // non-standard + "Intl", + "isFinite", + "isNaN", + "Iterator", + "JSON", + "Map", + "Math", + "NaN", + "Number", + "Object", + "parseFloat", + "parseInt", + "Promise", + "Proxy", + "RangeError", + "ReferenceError", + "Reflect", + "RegExp", + "Set", + "SharedArrayBuffer", + "String", + "Symbol", + "SyntaxError", + "TypeError", + "Uint16Array", + "Uint32Array", + "Uint8Array", + "Uint8ClampedArray", + "undefined", + "unescape", + "URIError", + "WeakMap", + "WeakRef", + "WeakSet", +]; + #[napi] -pub fn add(left: i32, right: i32) -> i32 { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); +pub fn parse(source: String, options: ParseOptions) -> ParseResult { + let program = match forget_hermes_parser::parse(&source, &options.file) { + Ok(program) => program, + Err(diagnostics) => { + return ParseResult { + program: None, + diagnostics: convert_diagnostics(diagnostics), + }; + } + }; + let mut analysis = analyze( + &program, + AnalyzeOptions { + globals: GLOBALS.iter().map(|s| s.to_string()).collect(), + }, + ); + ParseResult { + program: Some(serde_json::to_string(&program).unwrap()), + diagnostics: convert_diagnostics(analysis.diagnostics()), } } + +fn convert_diagnostics(diagnostics: Vec) -> Vec { + diagnostics + .into_iter() + .map(|diagnostic| format!("{}", diagnostic)) + .collect() +} + +#[napi(object)] +pub struct ParseOptions { + pub file: String, +} + +#[napi(object)] +pub struct ParseResult { + pub program: Option, + pub diagnostics: Vec, +}