Skip to content

Commit

Permalink
Add support for global functions (#47)
Browse files Browse the repository at this point in the history
* feat: add support for global functions

* feat: update crate to v0.8.0

* feat: add v8 re-export
  • Loading branch information
Valerioageno authored Dec 15, 2024
1 parent 800a268 commit cbb6a24
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ssr_rs"
version = "0.7.0"
version = "0.8.0"
authors = ["Valerio <[email protected]>"]
edition = "2021"
description = "Server side rendering with the v8 engine for parse and evaluate the javascript code"
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,4 @@
mod ssr;

pub use ssr::{Ssr, SsrError};
pub use v8;
66 changes: 66 additions & 0 deletions src/ssr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ pub enum SsrError {
InvalidJs(&'static str),
FailedToParseJs(&'static str),
FailedJsExecution(&'static str),
InvalidFunctionName,
InvalidFunction,
}

impl fmt::Display for SsrError {
Expand Down Expand Up @@ -158,6 +160,31 @@ where
})
}

/// Add a global function to the V8 runtime.
/// Any function defined here can be executed within any js scope
pub fn add_global_fn(
&self,
name: &'static str,
callback: impl v8::MapFnTo<v8::FunctionCallback>,
) -> Result<(), SsrError> {
let scope = unsafe { &mut *self.scope };
let ctx = scope.get_current_context();
let global = ctx.global(scope);

let name = match v8::String::new(scope, name) {
Some(val) => val,
None => return Err(SsrError::InvalidFunctionName),
};

let callback = match v8::Function::new(scope, callback) {
Some(val) => val,
None => return Err(SsrError::InvalidFunction),
};
global.set(scope, name.into(), callback.into());

Ok(())
}

/// Execute the Javascript functions and return the result as string.
pub fn render_to_string(&mut self, params: Option<&str>) -> Result<String, SsrError> {
let scope = unsafe { &mut *self.scope };
Expand Down Expand Up @@ -387,4 +414,43 @@ mod tests {
"Hello world"
);
}

#[test]
#[should_panic(expected = "FailedJsExecution")]
fn it_should_fail_to_call_missing_global_fn() {
init_test();

let mut js = Ssr::from(
r##"var testGlobalFn = { globalSumFnCall: () => globalSum(2, 5)};"##.to_string(),
"testGlobalFn",
)
.unwrap();

assert_eq!(js.render_to_string(None).unwrap(), "7");
}

#[test]
fn it_should_call_a_custom_global_fn() {
init_test();

let mut js = Ssr::from(
r##"var testGlobalFn = { globalSumFnCall: () => globalSum(2, 5)};"##.to_string(),
"testGlobalFn",
)
.unwrap();

let global_sum = |scope: &mut v8::HandleScope,
args: v8::FunctionCallbackArguments,
mut rv: v8::ReturnValue| {
let first = args.get(0).number_value(scope).unwrap();
let second = args.get(1).number_value(scope).unwrap();
let sum = first + second;
rv.set(v8::Number::new(scope, sum).into());
};

js.add_global_fn("globalSum", global_sum)
.expect("Failed to bind global_sum fn");

assert_eq!(js.render_to_string(None).unwrap(), "7");
}
}

0 comments on commit cbb6a24

Please sign in to comment.