javy_codegen/
plugin.rs

1use anyhow::{anyhow, Result};
2use std::{borrow::Cow, fs, path::Path, str};
3
4use super::bytecode;
5
6/// The kind of a plugin.
7// This is an internal detail of this module.
8#[derive(Default, PartialEq, Copy, Clone)]
9#[allow(dead_code)] // Suppresses warnings for feature-gated variants
10pub(crate) enum PluginKind {
11    #[default]
12    User,
13    Default,
14    V2,
15}
16
17impl PluginKind {
18    /// Determine the import namespace of a provided plugin.
19    pub(crate) fn import_namespace(self, plugin: &Plugin) -> Result<String> {
20        match self {
21            PluginKind::V2 => Ok("javy_quickjs_provider_v2".to_string()),
22            PluginKind::User | PluginKind::Default => {
23                // The import namespace to use for this plugin.
24                let module = walrus::Module::from_buffer(plugin.as_bytes())?;
25                let import_namespace: std::borrow::Cow<'_, [u8]> = module
26                    .customs
27                    .iter()
28                    .find_map(|(_, section)| {
29                        if section.name() == "import_namespace" {
30                            Some(section)
31                        } else {
32                            None
33                        }
34                    })
35                    .ok_or_else(|| anyhow!("Plugin is missing import_namespace custom section"))?
36                    .data(&Default::default()); // Argument is required but not actually used for anything.
37                Ok(str::from_utf8(&import_namespace)?.to_string())
38            }
39        }
40    }
41}
42
43/// A Javy plugin.
44#[derive(Clone, Debug, Default)]
45pub struct Plugin {
46    bytes: Cow<'static, [u8]>,
47}
48
49impl Plugin {
50    /// Constructs a new [`Plugin`].
51    pub fn new(bytes: Cow<'static, [u8]>) -> Self {
52        Plugin { bytes }
53    }
54
55    /// Constructs a new [`Plugin`] from a given path.
56    pub fn new_from_path<P: AsRef<Path>>(path: P) -> Result<Self> {
57        let bytes = fs::read(path)?;
58        Ok(Self::new(bytes.into()))
59    }
60
61    /// Returns the [`Plugin`] as bytes
62    pub fn as_bytes(&self) -> &[u8] {
63        &self.bytes
64    }
65
66    /// Generate valid QuickJS bytecode from Javascript source code.
67    pub(crate) fn compile_source(&self, js_source_code: &[u8]) -> Result<Vec<u8>> {
68        bytecode::compile_source(self.as_bytes(), js_source_code)
69    }
70}