rquickjs-extension 0.0.3

An extension system for rquickjs
Documentation
use rquickjs::{
    async_with, AsyncContext, AsyncRuntime, CatchResultExt, Function, Module, Object, Result,
};
use rquickjs_extension::{Extension, ExtensionBuilder, ModuleImpl};

use self::common::{Printer, PrinterOptions};

mod common;

struct PrinterExtension {
    options: PrinterOptions,
}

impl PrinterExtension {
    pub fn new<T: Into<String>>(target: T) -> Self {
        Self {
            options: PrinterOptions {
                target: target.into(),
            },
        }
    }
}

impl Extension<PrinterOptions> for PrinterExtension {
    type Implementation = ModuleImpl<PrinterOptions>;

    fn implementation() -> &'static Self::Implementation {
        &ModuleImpl {
            declare: |decl| {
                decl.declare("default")?;
                Ok(())
            },
            evaluate: |_ctx, exports, options| {
                exports.export("default", Printer::new(options.target.clone()))?;
                Ok(())
            },
            name: "printer",
        }
    }

    fn options(self) -> PrinterOptions {
        self.options
    }

    fn globals(globals: &Object<'_>, options: &PrinterOptions) -> Result<()> {
        globals.set("global_printer", Printer::new(options.target.clone()))?;
        Ok(())
    }
}

#[tokio::test]
async fn test_extension() {
    let rt = AsyncRuntime::new().unwrap();

    let (loader, resolver, initalizer) = ExtensionBuilder::new()
        .with_extension(PrinterExtension::new("john"))
        .build();

    rt.set_loader(resolver, loader).await;

    let ctx = AsyncContext::full(&rt).await.unwrap();

    async_with!(ctx => |ctx| {
        initalizer.init(&ctx).unwrap();

        let (module, module_eval) = Module::declare(ctx.clone(), "test", r#"
            import printer from "printer";
            export function testFunc() {
                return printer.print();
            }
        "#).unwrap().eval().unwrap();
        module_eval.into_future::<()>().await.unwrap();
        let result = module.get::<_, Function>("testFunc").unwrap().call::<_, String>(()).unwrap();
        assert_eq!(result, "hello john");
    })
    .await;
}

#[tokio::test]
async fn test_extension_named() {
    let rt = AsyncRuntime::new().unwrap();

    let (loader, resolver, initalizer) = ExtensionBuilder::new()
        .with_extension_named(PrinterExtension::new("arnold"), "custom_printer")
        .build();

    rt.set_loader(resolver, loader).await;

    let ctx = AsyncContext::full(&rt).await.unwrap();

    async_with!(ctx => |ctx| {
        initalizer.init(&ctx).unwrap();

        let (module, module_eval) = Module::declare(ctx.clone(), "test", r#"
            import printer from "custom_printer";
            export function testFunc() {
                return printer.print();
            }
        "#).unwrap().eval().unwrap();
        module_eval.into_future::<()>().await.unwrap();
        let result = module.get::<_, Function>("testFunc").unwrap().call::<_, String>(()).unwrap();
        assert_eq!(result, "hello arnold");
    })
    .await;
}

#[tokio::test]
async fn test_extension_global() {
    let rt = AsyncRuntime::new().unwrap();

    let (loader, resolver, initalizer) = ExtensionBuilder::new()
        .with_extension(PrinterExtension::new("david"))
        .build();

    rt.set_loader(resolver, loader).await;

    let ctx = AsyncContext::full(&rt).await.unwrap();

    async_with!(ctx => |ctx| {
        initalizer.init(&ctx).unwrap();

        let result = ctx.eval::<String,_>(r#"
            global_printer.print()
        "#).catch(&ctx).unwrap();
        assert_eq!(result, "hello david");
    })
    .await;
}