rquickjs_extra_console/
lib.rs1use std::fmt::Write;
2
3use rquickjs::{class::Trace, function::Rest, Ctx, Error, JsLifetime, Result, Value};
4
5pub use self::formatter::Formatter;
6
7mod formatter;
8
9const TARGET: &str = "console";
10
11#[derive(Clone, Trace, JsLifetime)]
32#[rquickjs::class(frozen)]
33pub struct Console {
34 target: String,
35 formatter: Formatter,
36}
37
38impl Console {
39 pub fn new(target: &str, formatter: Formatter) -> Self {
40 Self {
41 target: target.to_string(),
42 formatter,
43 }
44 }
45
46 fn print(&self, level: log::Level, values: Rest<Value<'_>>) -> Result<()> {
47 let mut message = String::new();
48 for (i, value) in values.0.into_iter().enumerate() {
49 if i > 0 {
50 write!(&mut message, ", ").map_err(|_| Error::Unknown)?
51 }
52 self.formatter.format(&mut message, value)?
53 }
54 log::log!(target: &self.target, level, "{message}");
55 Ok(())
56 }
57}
58
59#[rquickjs::methods]
60impl Console {
61 fn debug(&self, values: Rest<Value<'_>>) -> Result<()> {
62 self.print(log::Level::Debug, values)
63 }
64
65 fn log(&self, values: Rest<Value<'_>>) -> Result<()> {
66 self.print(log::Level::Info, values)
67 }
68
69 fn warn(&self, values: Rest<Value<'_>>) -> Result<()> {
70 self.print(log::Level::Warn, values)
71 }
72
73 fn error(&self, values: Rest<Value<'_>>) -> Result<()> {
74 self.print(log::Level::Error, values)
75 }
76}
77
78pub fn init(ctx: &Ctx<'_>) -> Result<()> {
79 let globals = ctx.globals();
80
81 globals.set(
82 "console",
83 Console::new(TARGET, Formatter::builder().max_depth(3).build()),
84 )?;
85
86 Ok(())
87}
88
89#[cfg(test)]
90mod tests {
91 use rquickjs_extra_test::test_with;
92
93 use super::*;
94
95 #[test]
96 fn test_console() {
97 test_with(|ctx| {
98 let console = Console::new("hello", Formatter::default());
99 ctx.globals().set("console", console).unwrap();
100
101 let result = ctx.eval::<(), _>("console.log('test')");
102 assert!(result.is_ok());
103 })
104 }
105}