1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// Copyright (c) 2020-2021 Jan Haller. zlib/libpng license.
// Note: the crate documentation is copied to ReadMe.md using cargo-readme: cargo readme --no-license > ReadMe.md
// 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
//! `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::eval_json("console.log('Hello Rust from JS')").expect("JS runs");
//! }
//! ```
//!
//! ## Call a JS function
//!
//! A very basic application calls a JavaScript function `triple()` from Rust. It passes an argument and accepts a return value, both serialized via JSON:
//!
//! ```rust
//! use js_sandbox::{Script, AnyError};
//!
//! fn main() -> Result<(), AnyError> {
//! let js_code = "function triple(a) { return 3 * a; }";
//! let mut script = Script::from_string(js_code)?;
//!
//! let arg = 7;
//! let result: i32 = script.call("triple", &arg)?;
//!
//! assert_eq!(result, 21);
//! Ok(())
//! }
//! ```
//!
//! An example that serializes a JSON object (Rust -> JS) and formats a string (JS -> Rust):
//!
//! ```rust
//! use js_sandbox::{Script, AnyError};
//! use serde::Serialize;
//!
//! #[derive(Serialize, PartialEq)]
//! 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)
//! .expect("Initialization succeeds");
//!
//! let person = Person { name: "Roger".to_string(), age: 42 };
//! let result: String = script.call("toString", &person).unwrap();
//!
//! assert_eq!(result, "A person named Roger of age 42");
//! Ok(())
//! }
//! ```
//!
//! ## 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::{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)
//! .expect("Initialization succeeds");
//!
//! let _: () = script.call("append", &"hello").unwrap();
//! let _: () = script.call("append", &" world").unwrap();
//! let result: String = script.call("get", &()).unwrap();
//!
//! assert_eq!(result, "hello world");
//! Ok(())
//! }
//! ```
//!
//! [Deno]: https://deno.land/
//! [serde_json]: https://docs.serde.rs/serde_json
pub use Script;
pub use eval_json;
/// Represents a value passed to or from JavaScript.
///
/// Currently aliased as serde_json's Value type.
pub type JsValue = Value;
/// Polymorphic error type able to represent different error domains.
///
/// Currently reusing [anyhow::Error](../anyhow/enum.Error.html), this type may change slightly in the future depending on js-sandbox's needs.
// use through deno_core, to make sure same version of anyhow crate is used
pub type AnyError = AnyError;