use std::path::PathBuf;
use serde_json::Value;
use crate::configuration::Plugin;
pub const PLUGIN_ENTRY_FILENAME: &str = "plugin";
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct NestCompilerPlugin {
pub name: String,
pub resolved_path: PathBuf,
pub options: serde_json::Map<String, Value>,
pub has_before_hook: bool,
pub has_after_hook: bool,
pub has_after_declarations_hook: bool,
pub has_readonly_visitor: bool,
pub path_to_source: Option<PathBuf>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct MultiNestCompilerPlugins {
pub before_hooks: Vec<NestCompilerPlugin>,
pub after_hooks: Vec<NestCompilerPlugin>,
pub after_declarations_hooks: Vec<NestCompilerPlugin>,
pub readonly_visitors: Vec<NestCompilerPlugin>,
pub unresolved_plugins: Vec<String>,
}
impl MultiNestCompilerPlugins {
pub fn is_any_plugin_registered(&self) -> bool {
!self.before_hooks.is_empty()
|| !self.after_hooks.is_empty()
|| !self.after_declarations_hooks.is_empty()
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PluginsLoader {
cwd: PathBuf,
module_paths: Vec<PathBuf>,
}
impl Default for PluginsLoader {
fn default() -> Self {
Self::new(std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")))
}
}
impl PluginsLoader {
pub fn new(cwd: impl Into<PathBuf>) -> Self {
let cwd = cwd.into();
let module_paths = vec![cwd.join("node_modules")];
Self { cwd, module_paths }
}
pub fn with_module_paths(cwd: impl Into<PathBuf>, module_paths: Vec<PathBuf>) -> Self {
Self {
cwd: cwd.into(),
module_paths,
}
}
pub fn load(
&self,
plugins: &[Plugin],
path_to_source: Option<PathBuf>,
) -> Result<MultiNestCompilerPlugins, String> {
let mut multi = MultiNestCompilerPlugins::default();
for plugin in plugins {
let (name, _) = plugin_entry_parts(plugin);
multi.unresolved_plugins.push(name);
}
let _ = path_to_source;
Ok(multi)
}
pub fn resolve_plugin_reference(&self, name: &str) -> Option<PathBuf> {
self.node_module_paths()
.into_iter()
.flat_map(|module_path| {
[
module_path.join(name).join(PLUGIN_ENTRY_FILENAME),
module_path
.join(name)
.join(format!("{PLUGIN_ENTRY_FILENAME}.js")),
module_path.join(name),
self.cwd.join(name),
]
})
.find(|candidate| candidate.exists())
}
pub fn node_module_paths(&self) -> Vec<PathBuf> {
let mut paths = vec![self.cwd.join("node_modules")];
paths.extend(self.module_paths.clone());
paths.sort();
paths.dedup();
paths
}
}
fn plugin_entry_parts(plugin: &Plugin) -> (String, serde_json::Map<String, Value>) {
match plugin {
Plugin::Name(name) => (name.clone(), serde_json::Map::new()),
Plugin::Options(options) => {
let mut merged_options = serde_json::Map::new();
for option_group in &options.options {
for (key, value) in option_group {
merged_options.insert(key.clone(), value.clone());
}
}
(options.name.clone(), merged_options)
}
}
}