cli/lib/compiler/plugins/
plugins_loader.rs1use std::path::PathBuf;
5
6use serde_json::Value;
7
8use crate::configuration::Plugin;
9
10pub const PLUGIN_ENTRY_FILENAME: &str = "plugin";
11
12#[derive(Clone, Debug, Default, PartialEq, Eq)]
13pub struct NestCompilerPlugin {
14 pub name: String,
15 pub resolved_path: PathBuf,
16 pub options: serde_json::Map<String, Value>,
17 pub has_before_hook: bool,
18 pub has_after_hook: bool,
19 pub has_after_declarations_hook: bool,
20 pub has_readonly_visitor: bool,
21 pub path_to_source: Option<PathBuf>,
22}
23
24#[derive(Clone, Debug, Default, PartialEq, Eq)]
25pub struct MultiNestCompilerPlugins {
26 pub before_hooks: Vec<NestCompilerPlugin>,
27 pub after_hooks: Vec<NestCompilerPlugin>,
28 pub after_declarations_hooks: Vec<NestCompilerPlugin>,
29 pub readonly_visitors: Vec<NestCompilerPlugin>,
30 pub unresolved_plugins: Vec<String>,
31}
32
33impl MultiNestCompilerPlugins {
34 pub fn is_any_plugin_registered(&self) -> bool {
35 !self.before_hooks.is_empty()
36 || !self.after_hooks.is_empty()
37 || !self.after_declarations_hooks.is_empty()
38 }
39}
40
41#[derive(Clone, Debug, PartialEq, Eq)]
42pub struct PluginsLoader {
43 cwd: PathBuf,
44 module_paths: Vec<PathBuf>,
45}
46
47impl Default for PluginsLoader {
48 fn default() -> Self {
49 Self::new(std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")))
50 }
51}
52
53impl PluginsLoader {
54 pub fn new(cwd: impl Into<PathBuf>) -> Self {
55 let cwd = cwd.into();
56 let module_paths = vec![cwd.join("node_modules")];
57 Self { cwd, module_paths }
58 }
59
60 pub fn with_module_paths(cwd: impl Into<PathBuf>, module_paths: Vec<PathBuf>) -> Self {
61 Self {
62 cwd: cwd.into(),
63 module_paths,
64 }
65 }
66
67 pub fn load(
68 &self,
69 plugins: &[Plugin],
70 path_to_source: Option<PathBuf>,
71 ) -> Result<MultiNestCompilerPlugins, String> {
72 let mut multi = MultiNestCompilerPlugins::default();
73 for plugin in plugins {
74 let (name, _) = plugin_entry_parts(plugin);
75 multi.unresolved_plugins.push(name);
76 }
77 let _ = path_to_source;
78 Ok(multi)
79 }
80
81 pub fn resolve_plugin_reference(&self, name: &str) -> Option<PathBuf> {
82 self.node_module_paths()
83 .into_iter()
84 .flat_map(|module_path| {
85 [
86 module_path.join(name).join(PLUGIN_ENTRY_FILENAME),
87 module_path
88 .join(name)
89 .join(format!("{PLUGIN_ENTRY_FILENAME}.js")),
90 module_path.join(name),
91 self.cwd.join(name),
92 ]
93 })
94 .find(|candidate| candidate.exists())
95 }
96
97 pub fn node_module_paths(&self) -> Vec<PathBuf> {
98 let mut paths = vec![self.cwd.join("node_modules")];
99 paths.extend(self.module_paths.clone());
100 paths.sort();
101 paths.dedup();
102 paths
103 }
104}
105
106fn plugin_entry_parts(plugin: &Plugin) -> (String, serde_json::Map<String, Value>) {
107 match plugin {
108 Plugin::Name(name) => (name.clone(), serde_json::Map::new()),
109 Plugin::Options(options) => {
110 let mut merged_options = serde_json::Map::new();
111 for option_group in &options.options {
112 for (key, value) in option_group {
113 merged_options.insert(key.clone(), value.clone());
114 }
115 }
116 (options.name.clone(), merged_options)
117 }
118 }
119}