From 7f663e81505e58d8f36e0ed3d9f2ca37acbe2edf Mon Sep 17 00:00:00 2001 From: Samuel Gomez Date: Tue, 26 Nov 2024 09:18:30 +0000 Subject: [PATCH 1/2] chore: update deno core and Cargo.lock --- README.md | 0 ReadMe.md | 150 ----------------------------------- cfg/{ReadMe.in => README.in} | 4 +- js-sandbox-macros/Cargo.toml | 8 +- js-sandbox/Cargo.toml | 12 +-- js-sandbox/src/lib.rs | 32 ++++---- js-sandbox/src/script.rs | 12 +-- publish.sh | 4 +- 8 files changed, 37 insertions(+), 185 deletions(-) create mode 100644 README.md delete mode 100644 ReadMe.md rename cfg/{ReadMe.in => README.in} (94%) mode change 100644 => 100755 publish.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/ReadMe.md b/ReadMe.md deleted file mode 100644 index fd52f3a..0000000 --- a/ReadMe.md +++ /dev/null @@ -1,150 +0,0 @@ - - -# js-sandbox-ios - -[crates.io](https://crates.io/crates/js-sandbox) -[docs.rs](https://docs.rs/js-sandbox) - -`js-sandbox` is a Rust library for executing JavaScript code from Rust in a secure sandbox. It is based on the [Deno] project and uses [serde_json] -for serialization. - -This library's primary focus is **embedding JS as a scripting language into Rust**. It does not provide all possible integrations between the two -languages, and is not tailored to JS's biggest domain as a client/server side language of the web. - -Instead, `js-sandbox` focuses on calling standalone JS code from Rust, and tries to remain as simple as possible in doing so. -The typical use case is a core Rust application that integrates with scripts from external users, for example a plugin system or a game that runs -external mods. - -This library is in early development, with a basic but powerful API. The API may still evolve considerably. - -## Examples - -### Print from JavaScript - -The _Hello World_ example -- print something using JavaScript -- is one line, as it should be: -```rust -fn main() { - js_sandbox_ios::eval_json("console.log('Hello Rust from JS')").expect("JS runs"); -} -``` - -### Call a JS function - -A very basic application calls a JavaScript function `sub()` from Rust. It passes an argument and accepts a return value, both serialized via JSON: - -```rust -use js_sandbox_ios::{Script, AnyError}; - -fn main() -> Result<(), AnyError> { - let js_code = "function sub(a, b) { return a - b; }"; - let mut script = Script::from_string(js_code)?; - - let result: i32 = script.call("sub", (7, 5))?; - - assert_eq!(result, 2); - Ok(()) -} -``` - -An example that serializes a JSON object (Rust -> JS) and formats a string (JS -> Rust): - -```rust -use js_sandbox_ios::{Script, AnyError}; -use serde::Serialize; - -#[derive(Serialize)] -struct Person { - name: String, - age: u8, -} - -fn main() -> Result<(), AnyError> { - let src = r#" - function toString(person) { - return "A person named " + person.name + " of age " + person.age; - }"#; - - let mut script = Script::from_string(src)?; - - let person = Person { name: "Roger".to_string(), age: 42 }; - let result: String = script.call("toString", (person,))?; - - assert_eq!(result, "A person named Roger of age 42"); - Ok(()) -} -``` - -### Load JS file - -JavaScript files can be loaded from any `Path` at runtime (e.g. 3rd party mods). - -If you want to statically embed UTF-8 encoded files in the Rust binary, you can alternatively use the -[`std::include_str`](https://doc.rust-lang.org/std/macro.include_str.html) macro. - -```rust -use js_sandbox_ios::Script; - -fn main() { - // (1) at runtime: - let mut script = Script::from_file("script.js").expect("load + init succeeds"); - - // (2) at compile time: - let code: &'static str = include_str!("script.js"); - let mut script = Script::from_string(code).expect("init succeeds"); - - // use script as usual -} -``` - -### Maintain state in JavaScript - -It is possible to initialize a stateful JS script, and then use functions to modify that state over time. -This example appends a string in two calls, and then gets the result in a third call: - -```rust -use js_sandbox_ios::{Script, AnyError}; - -fn main() -> Result<(), AnyError> { - let src = r#" - var total = ''; - function append(str) { total += str; } - function get() { return total; }"#; - - let mut script = Script::from_string(src)?; - - let _: () = script.call("append", ("hello",))?; - let _: () = script.call("append", (" world",))?; - let result: String = script.call("get", ())?; - - assert_eq!(result, "hello world"); - Ok(()) -} -``` - -### Call a script with timeout - -The JS code may contain long- or forever-running loops that block Rust code. It is possible to set -a timeout, after which JavaScript execution is aborted. - -```rust -use js_sandbox_ios::{Script, JsError}; - -fn main() -> Result<(), JsError> { - use std::time::Duration; - let js_code = "function run_forever() { for(;;) {} }"; - let mut script = Script::from_string(js_code)? - .with_timeout(Duration::from_millis(1000)); - - let result: Result = script.call("run_forever", ()); - - assert_eq!( - result.unwrap_err().to_string(), - "Uncaught Error: execution terminated".to_string() - ); - - Ok(()) -} -``` - -[Deno]: https://deno.land -[serde_json]: https://docs.serde.rs/serde_json diff --git a/cfg/ReadMe.in b/cfg/README.in similarity index 94% rename from cfg/ReadMe.in rename to cfg/README.in index ac41c22..ab4f29f 100644 --- a/cfg/ReadMe.in +++ b/cfg/README.in @@ -1,4 +1,4 @@ - + # {{crate}} @@ -6,3 +6,5 @@ [docs.rs](https://docs.rs/js-sandbox) {{readme}} + +License: {{license}} diff --git a/js-sandbox-macros/Cargo.toml b/js-sandbox-macros/Cargo.toml index 16f2cbb..09943f8 100644 --- a/js-sandbox-macros/Cargo.toml +++ b/js-sandbox-macros/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "js-sandbox-macros" -version = "0.2.0-rc.1" +version = "0.2.0" description = "Procedural macros for js-sandbox" repository = "https://github.com/Bromeon/js-sandbox" documentation = "https://docs.rs/js-sandbox-macros/0.2.0-rc.1" @@ -14,6 +14,6 @@ edition = "2021" proc-macro = true [dependencies] -syn = { version = "2.0.32", features = ["full"] } -quote = "1.0.33" -proc-macro2 = "1.0.66" +syn = { version = "2.0.89", features = ["full"] } +quote = "1.0.37" +proc-macro2 = "1.0.92" diff --git a/js-sandbox/Cargo.toml b/js-sandbox/Cargo.toml index 47a8e96..a6f6daa 100644 --- a/js-sandbox/Cargo.toml +++ b/js-sandbox/Cargo.toml @@ -2,18 +2,18 @@ [package] name = "js-sandbox-ios" -version = "0.1.1" +version = "0.2.0" description = "Execute JavaScript code from Rust in a secure sandbox, and transport data to/from JS plug-ins." repository = "https://github.com/Bromeon/js-sandbox" documentation = "https://docs.rs/js-sandbox/0.2.0-rc.1" authors = ["Jan Haller "] license = "Zlib" edition = "2021" -readme = "../ReadMe.md" +readme = "../Readme.md" [dependencies] -js-sandbox-macros = { path = "../js-sandbox-macros", version = "=0.2.0-rc.1" } -deno_core = "0.238.0" -serde_json = "1.0.106" -serde = { version = "1.0.188", features = ["derive"] } +js-sandbox-macros = { path = "../js-sandbox-macros", version = "=0.2.0" } +deno_core = "0.322.0" +serde_json = "1.0.133" +serde = { version = "1.0.215", features = ["derive"] } tracing = "0.1.40" diff --git a/js-sandbox/src/lib.rs b/js-sandbox/src/lib.rs index d73563b..863ee95 100644 --- a/js-sandbox/src/lib.rs +++ b/js-sandbox/src/lib.rs @@ -1,9 +1,9 @@ // Copyright (c) 2020-2023 js-sandbox contributors. Zlib license. -// Note: the crate documentation is copied to ReadMe.md using cargo-readme (see CI) +// Note: the crate documentation is copied to README.md using cargo-readme (see CI) // Alternatives: -// * once stable: #![feature(external_doc)] #![doc(include = "../ReadMe.md")] -// * doc_comment crate + doctest!("../ReadMe.md"); -- works for running doc-tests, but not for doc on crate level +// * once stable: #![feature(external_doc)] #![doc(include = "../README.md")] +// * doc_comment crate + doctest!("../README.md"); -- works for running doc-tests, but not for doc on crate level //! `js-sandbox` is a Rust library for executing JavaScript code from Rust in a secure sandbox. It is based on the [Deno] project and uses [serde_json] //! for serialization. @@ -37,13 +37,13 @@ //! use js_sandbox_ios::{Script, AnyError}; //! //! fn main() -> Result<(), AnyError> { -//! let js_code = "function sub(a, b) { return a - b; }"; -//! let mut script = Script::from_string(js_code)?; +//! let js_code = "function sub(a, b) { return a - b; }"; +//! let mut script = Script::from_string(js_code)?; //! -//! let result: i32 = script.call("sub", (7, 5))?; +//! let result: i32 = script.call("sub", (7, 5))?; //! -//! assert_eq!(result, 2); -//! Ok(()) +//! assert_eq!(result, 2); +//! Ok(()) //! } //! ``` //! @@ -55,23 +55,23 @@ //! //! #[derive(Serialize)] //! struct Person { -//! name: String, -//! age: u8, +//! name: String, +//! age: u8, //! } //! //! fn main() -> Result<(), AnyError> { -//! let src = r#" +//! let src = r#" //! function toString(person) { //! return "A person named " + person.name + " of age " + person.age; //! }"#; //! -//! let mut script = Script::from_string(src)?; +//! let mut script = Script::from_string(src)?; //! -//! let person = Person { name: "Roger".to_string(), age: 42 }; -//! let result: String = script.call("toString", (person,))?; +//! let person = Person { name: "Roger".to_string(), age: 42 }; +//! let result: String = script.call("toString", (person,))?; //! -//! assert_eq!(result, "A person named Roger of age 42"); -//! Ok(()) +//! assert_eq!(result, "A person named Roger of age 42"); +//! Ok(()) //! } //! ``` //! diff --git a/js-sandbox/src/script.rs b/js-sandbox/src/script.rs index 80a8b0c..8bd157c 100644 --- a/js-sandbox/src/script.rs +++ b/js-sandbox/src/script.rs @@ -9,7 +9,7 @@ use std::{thread, time::Duration}; use deno_core::anyhow::Context; use deno_core::v8::{Global, Value}; -use deno_core::{op2, serde_v8, v8, Extension, FastString, JsBuffer, JsRuntime, Op, OpState}; +use deno_core::{op2, serde_v8, v8, Extension, FastString, JsBuffer, JsRuntime, OpDecl, OpState}; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; @@ -82,8 +82,9 @@ impl Script { } pub fn new() -> Self { + const DECL: OpDecl = op_return(); let ext = Extension { - ops: Cow::Owned(vec![op_return::DECL]), + ops: Cow::Owned(vec![DECL]), ..Default::default() }; @@ -133,7 +134,7 @@ impl Script { // We cannot provide a dynamic filename because execute_script() requires a &'static str let global = self .runtime - .execute_script(Self::DEFAULT_FILENAME, js_code.into())?; + .execute_script(Self::DEFAULT_FILENAME, js_code)?; self.added_namespaces.insert(namespace.to_string(), global); @@ -296,7 +297,7 @@ impl Script { }; // 'undefined' will cause JSON serialization error, so it needs to be treated as null - let js_code = format!( + let js_code: String = format!( "(async () => {{ let __rust_result = {fn_name}.constructor.name === 'AsyncFunction' ? await {fn_name}({json_args}) @@ -307,8 +308,7 @@ impl Script { Deno.core.ops.op_return(__rust_result); }})()" - ) - .into(); + ); if let Some(timeout) = self.timeout { let handle = self.runtime.v8_isolate().thread_safe_handle(); diff --git a/publish.sh b/publish.sh old mode 100644 new mode 100755 index 686eb35..53d0dda --- a/publish.sh +++ b/publish.sh @@ -1,2 +1,2 @@ -cargo readme --template cfg/ReadMe.in > ReadMe.md -cargo publish \ No newline at end of file +cargo readme --template cfg/README.in > README.md +cargo publish From 5ecaf3bb5450886724aec118caf48b31bb82c827 Mon Sep 17 00:00:00 2001 From: Samuel Gomez Date: Tue, 26 Nov 2024 09:26:21 +0000 Subject: [PATCH 2/2] chore: regenerating README --- .github/workflows/publish.yaml | 18 ---- README.md | 152 +++++++++++++++++++++++++++++++++ publish.sh | 2 - 3 files changed, 152 insertions(+), 20 deletions(-) delete mode 100644 .github/workflows/publish.yaml delete mode 100755 publish.sh diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml deleted file mode 100644 index a3b7832..0000000 --- a/.github/workflows/publish.yaml +++ /dev/null @@ -1,18 +0,0 @@ -name: Publish -on: - push: - tags: - - "*" - workflow_dispatch: -jobs: - publish: - name: Publish - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v3 - - - name: Install stable toolchain - uses: dtolnay/rust-toolchain@stable - - - run: cd js-sandbox && cargo publish --token ${{ secrets.CRATES_TOKEN }} diff --git a/README.md b/README.md index e69de29..0c0c5d2 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,152 @@ + + +# js-sandbox-ios + +[crates.io](https://crates.io/crates/js-sandbox) +[docs.rs](https://docs.rs/js-sandbox) + +`js-sandbox` is a Rust library for executing JavaScript code from Rust in a secure sandbox. It is based on the [Deno] project and uses [serde_json] +for serialization. + +This library's primary focus is **embedding JS as a scripting language into Rust**. It does not provide all possible integrations between the two +languages, and is not tailored to JS's biggest domain as a client/server side language of the web. + +Instead, `js-sandbox` focuses on calling standalone JS code from Rust, and tries to remain as simple as possible in doing so. +The typical use case is a core Rust application that integrates with scripts from external users, for example a plugin system or a game that runs +external mods. + +This library is in early development, with a basic but powerful API. The API may still evolve considerably. + +## Examples + +### Print from JavaScript + +The _Hello World_ example -- print something using JavaScript -- is one line, as it should be: +```rust +fn main() { + js_sandbox_ios::eval_json("console.log('Hello Rust from JS')").expect("JS runs"); +} +``` + +### Call a JS function + +A very basic application calls a JavaScript function `sub()` from Rust. It passes an argument and accepts a return value, both serialized via JSON: + +```rust +use js_sandbox_ios::{Script, AnyError}; + +fn main() -> Result<(), AnyError> { + let js_code = "function sub(a, b) { return a - b; }"; + let mut script = Script::from_string(js_code)?; + + let result: i32 = script.call("sub", (7, 5))?; + + assert_eq!(result, 2); + Ok(()) +} +``` + +An example that serializes a JSON object (Rust -> JS) and formats a string (JS -> Rust): + +```rust +use js_sandbox_ios::{Script, AnyError}; +use serde::Serialize; + +#[derive(Serialize)] +struct Person { + name: String, + age: u8, +} + +fn main() -> Result<(), AnyError> { + let src = r#" + function toString(person) { + return "A person named " + person.name + " of age " + person.age; + }"#; + + let mut script = Script::from_string(src)?; + + let person = Person { name: "Roger".to_string(), age: 42 }; + let result: String = script.call("toString", (person,))?; + + assert_eq!(result, "A person named Roger of age 42"); + Ok(()) +} +``` + +### Load JS file + +JavaScript files can be loaded from any `Path` at runtime (e.g. 3rd party mods). + +If you want to statically embed UTF-8 encoded files in the Rust binary, you can alternatively use the +[`std::include_str`](https://doc.rust-lang.org/std/macro.include_str.html) macro. + +```rust +use js_sandbox_ios::Script; + +fn main() { + // (1) at runtime: + let mut script = Script::from_file("script.js").expect("load + init succeeds"); + + // (2) at compile time: + let code: &'static str = include_str!("script.js"); + let mut script = Script::from_string(code).expect("init succeeds"); + + // use script as usual +} +``` + +### Maintain state in JavaScript + +It is possible to initialize a stateful JS script, and then use functions to modify that state over time. +This example appends a string in two calls, and then gets the result in a third call: + +```rust +use js_sandbox_ios::{Script, AnyError}; + +fn main() -> Result<(), AnyError> { + let src = r#" + var total = ''; + function append(str) { total += str; } + function get() { return total; }"#; + + let mut script = Script::from_string(src)?; + + let _: () = script.call("append", ("hello",))?; + let _: () = script.call("append", (" world",))?; + let result: String = script.call("get", ())?; + + assert_eq!(result, "hello world"); + Ok(()) +} +``` + +### Call a script with timeout + +The JS code may contain long- or forever-running loops that block Rust code. It is possible to set +a timeout, after which JavaScript execution is aborted. + +```rust +use js_sandbox_ios::{Script, JsError}; + +fn main() -> Result<(), JsError> { + use std::time::Duration; + let js_code = "function run_forever() { for(;;) {} }"; + let mut script = Script::from_string(js_code)? + .with_timeout(Duration::from_millis(1000)); + + let result: Result = script.call("run_forever", ()); + + assert_eq!( + result.unwrap_err().to_string(), + "Uncaught Error: execution terminated".to_string() + ); + + Ok(()) +} +``` + +[Deno]: https://deno.land +[serde_json]: https://docs.serde.rs/serde_json + +License: Zlib diff --git a/publish.sh b/publish.sh deleted file mode 100755 index 53d0dda..0000000 --- a/publish.sh +++ /dev/null @@ -1,2 +0,0 @@ -cargo readme --template cfg/README.in > README.md -cargo publish