use std::sync::Arc;
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
use super::{
hooks::freeze_module::PluginFreezeModuleHookParam, Plugin, PluginAnalyzeDepsHookParam,
PluginFinalizeModuleHookParam, PluginFinalizeResourcesHookParam,
PluginGenerateResourcesHookResult, PluginHandleEntryResourceHookParam, PluginHookContext,
PluginLoadHookParam, PluginLoadHookResult, PluginModuleGraphUpdatedHookParam,
PluginParseHookParam, PluginProcessModuleHookParam, PluginResolveHookParam,
PluginResolveHookResult, PluginTransformHookParam, PluginUpdateModulesHookParam,
};
use crate::{
config::Config,
context::CompilationContext,
error::Result,
module::{
module_graph::ModuleGraph, module_group::ModuleGroupGraph, Module, ModuleId, ModuleMetaData,
ModuleType,
},
resource::{meta_data::ResourcePotMetaData, resource_pot::ResourcePot},
stats::{CompilationModuleGraphStats, CompilationPluginHookStats, Stats},
};
use std::time::SystemTime;
use std::time::UNIX_EPOCH;
pub struct PluginDriver {
pub plugins: Vec<Arc<dyn Plugin>>,
record: bool,
}
macro_rules! hook_first {
(
$func_name:ident,
$ret_ty:ty,
$($arg:ident: $ty:ty),*
) => {
pub fn $func_name(&self, $($arg: $ty),*) -> $ret_ty {
for plugin in &self.plugins {
let ret = plugin.$func_name($($arg),*)?;
if ret.is_some() {
return Ok(ret);
}
}
Ok(None)
}
};
(
$func_name:ident,
$ret_ty:ty,
$callback:expr,
$($arg:ident: $ty:ty),*
) => {
pub fn $func_name(&self, $($arg: $ty),*) -> $ret_ty {
for plugin in &self.plugins {
if self.record {
let start_time = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.as_millis();
let ret = plugin.$func_name($($arg),*)?;
let end_time = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("hook_first get end_time failed")
.as_millis();
if ret.is_some() {
let plugin_name = plugin.name().to_string();
$callback(&ret, plugin_name, start_time, end_time, $($arg),*);
return Ok(ret);
}
}else {
let ret = plugin.$func_name($($arg),*)?;
if ret.is_some() {
return Ok(ret);
}
}
}
Ok(None)
}
};
}
macro_rules! hook_serial {
($func_name:ident, $param_ty:ty) => {
pub fn $func_name(&self, param: $param_ty, context: &Arc<CompilationContext>) -> Result<()> {
for plugin in &self.plugins {
plugin.$func_name(param, context)?;
}
Ok(())
}
};
($func_name:ident, $param_ty:ty, $before_transformer:expr, $after_transformer:expr, $callback:expr) => {
pub fn $func_name(&self, param: $param_ty, context: &Arc<CompilationContext>) -> Result<()> {
for plugin in &self.plugins {
if self.record {
let start_time = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.as_millis();
let ret = plugin.$func_name(param, context)?;
let end_time = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("hook_first get end_time failed")
.as_millis();
if ret.is_some() {
let plugin_name = plugin.name().to_string();
let before = $before_transformer(param);
let after = $after_transformer(param);
$callback(
plugin_name,
start_time,
end_time,
before,
after,
param,
context,
);
}
} else {
plugin.$func_name(param, context)?;
}
}
Ok(())
}
};
}
macro_rules! hook_parallel {
($func_name:ident) => {
pub fn $func_name(&self, context: &Arc<CompilationContext>) -> Result<()> {
self
.plugins
.par_iter()
.try_for_each(|plugin| {
let ret = plugin.$func_name(context).map(|_| ());
return ret;
})
}
};
($func_name:ident, $callback:expr) => {
pub fn $func_name(&self, context: &Arc<CompilationContext>) -> Result<()> {
self
.plugins
.par_iter()
.try_for_each(|plugin| {
let ret = plugin.$func_name(context).map(|_| ());
if self.record {
let plugin_name = plugin.name().to_string();
$callback(plugin_name, context);
}
return ret;
})
}
};
($func_name:ident, $($arg:ident: $ty:ty),+) => {
pub fn $func_name(&self, $($arg: $ty),+, context: &Arc<CompilationContext>) -> Result<()> {
self
.plugins
.par_iter()
.try_for_each(|plugin| {
let ret = plugin.$func_name($($arg),+, context).map(|_| ());
return ret;
})
}
};
($func_name:ident, $($arg:ident: $ty:ty),+ ,$callback:expr) => {
pub fn $func_name(&self, $($arg: $ty),+, context: &Arc<CompilationContext>) -> Result<()> {
self
.plugins
.par_iter()
.try_for_each(|plugin| {
let ret = plugin.$func_name($($arg),+, context).map(|_| ());
if self.record {
let plugin_name = plugin.name().to_string();
$callback(plugin_name, context);
}
return ret;
})
}
};
}
impl PluginDriver {
pub fn new(mut plugins: Vec<Arc<dyn Plugin>>, record: bool) -> Self {
plugins.sort_by_key(|b| std::cmp::Reverse(b.priority()));
Self { plugins, record }
}
pub fn config(&self, config: &mut Config) -> Result<()> {
for plugin in &self.plugins {
plugin.config(config)?;
}
Ok(())
}
pub fn plugin_cache_loaded(&self, context: &Arc<CompilationContext>) -> Result<()> {
let start_time = if context.config.record {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.as_millis()
} else {
0
};
for plugin in &self.plugins {
if let Some(plugin_cache) = context.cache_manager.plugin_cache.read_cache(plugin.name()) {
plugin.plugin_cache_loaded(plugin_cache.value(), context)?;
if context.config.record {
let end_time = if context.config.record {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("hook_first get end_time failed")
.as_millis()
} else {
0
};
context
.stats
.add_plugin_hook_stats(CompilationPluginHookStats {
plugin_name: plugin.name().to_string(),
hook_name: "plugin_cache_loaded".to_string(),
hook_context: None,
module_id: "root".into(),
input: "".to_string(),
output: "".to_string(),
duration: end_time - start_time,
start_time,
end_time,
});
}
}
}
Ok(())
}
hook_parallel!(build_start);
hook_first!(
resolve,
Result<Option<PluginResolveHookResult>>,
|result: &Option<PluginResolveHookResult>,
plugin_name: String,
start_time: u128,
end_time: u128,
param: &PluginResolveHookParam,
context: &Arc<CompilationContext>,
hook_context: &PluginHookContext| {
if let Some(resolve_result) = result {
context.stats.add_plugin_hook_stats(CompilationPluginHookStats {
plugin_name: plugin_name.to_string(),
hook_name: "resolve".to_string(),
hook_context: Some(hook_context.clone()),
module_id: param.importer.clone().unwrap_or("root".into()),
input: serde_json::to_string(param).unwrap(),
output: serde_json::to_string(resolve_result).unwrap(),
duration: end_time - start_time,
start_time,
end_time
});
}
},
param: &PluginResolveHookParam,
context: &Arc<CompilationContext>,
_hook_context: &PluginHookContext
);
hook_first!(
load,
Result<Option<PluginLoadHookResult>>,
|result: &Option<PluginLoadHookResult>,
plugin_name: String,
start_time: u128,
end_time: u128,
param: &PluginLoadHookParam,
context: &Arc<CompilationContext>,
hook_context: &PluginHookContext| {
if let Some(load_result) = result {
context.stats.add_plugin_hook_stats(CompilationPluginHookStats {
plugin_name: plugin_name.to_string(),
hook_name: "load".to_string(),
hook_context: Some(hook_context.clone()),
module_id: param.module_id.clone().into(),
input: serde_json::to_string(param).unwrap(),
output: serde_json::to_string(load_result).unwrap(),
duration: end_time - start_time,
start_time,
end_time
});
}
},
param: &PluginLoadHookParam,
context: &Arc<CompilationContext>,
_hook_context: &PluginHookContext
);
pub fn transform(
&self,
mut param: PluginTransformHookParam<'_>,
context: &Arc<CompilationContext>,
) -> Result<PluginDriverTransformHookResult> {
let mut result = PluginDriverTransformHookResult {
content: String::new(),
source_map_chain: param.source_map_chain.clone(),
module_type: None,
};
fn transform_fn_with_hook() {}
let transform_fn = transform_fn_with_hook;
transform_fn();
for plugin in &self.plugins {
let start_time = if self.record {
Some(
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.as_millis(),
)
} else {
None
};
if let Some(plugin_result) = plugin.transform(¶m, context)? {
let end_time = if self.record {
Some(
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("hook_first get end_time failed")
.as_millis(),
)
} else {
None
};
if self.record {
let plugin_name = plugin.name().to_string();
let start_time = start_time.unwrap();
let end_time = end_time.unwrap();
context
.stats
.add_plugin_hook_stats(CompilationPluginHookStats {
plugin_name: plugin_name.to_string(),
hook_name: "transform".to_string(),
hook_context: None,
module_id: param.module_id.clone().into(),
input: serde_json::to_string(¶m).unwrap(),
output: serde_json::to_string(&plugin_result).unwrap(),
duration: end_time - start_time,
start_time,
end_time,
});
}
param.content = plugin_result.content;
param.module_type = plugin_result.module_type.unwrap_or(param.module_type);
if plugin_result.ignore_previous_source_map {
result.source_map_chain.clear();
}
if let Some(source_map) = plugin_result.source_map {
let sourcemap = Arc::new(source_map);
result.source_map_chain.push(sourcemap.clone());
param.source_map_chain.push(sourcemap);
}
}
}
result.content = param.content;
result.module_type = Some(param.module_type);
Ok(result)
}
hook_first!(
parse,
Result<Option<ModuleMetaData>>,
|_result: &Option<ModuleMetaData>,
plugin_name: String,
start_time: u128,
end_time: u128,
param: &PluginParseHookParam,
context: &Arc<CompilationContext>,
hook_context: &PluginHookContext| {
context.stats.add_plugin_hook_stats(
CompilationPluginHookStats {
plugin_name: plugin_name.to_string(),
hook_name: "parse".to_string(),
hook_context: Some(hook_context.clone()),
module_id: param.module_id.clone(),
input: serde_json::to_string(param).unwrap(),
output: "".to_string(),
duration: end_time - start_time,
start_time,
end_time,
},
);
},
param: &PluginParseHookParam,
context: &Arc<CompilationContext>,
_hook_context: &PluginHookContext
);
hook_serial!(
process_module,
&mut PluginProcessModuleHookParam,
|_: &mut PluginProcessModuleHookParam| { "".to_string() },
|_: &mut PluginProcessModuleHookParam| { "".to_string() },
|plugin_name: String,
start_time: u128,
end_time: u128,
input: String,
output: String,
param: &PluginProcessModuleHookParam,
context: &Arc<CompilationContext>| {
context
.stats
.add_plugin_hook_stats(CompilationPluginHookStats {
plugin_name: plugin_name.to_string(),
hook_name: "process_module".to_string(),
hook_context: None,
module_id: param.module_id.clone(),
input,
output,
duration: end_time - start_time,
start_time,
end_time,
})
}
);
hook_serial!(
analyze_deps,
&mut PluginAnalyzeDepsHookParam,
|before_param: &mut PluginAnalyzeDepsHookParam| {
serde_json::to_string(&before_param.deps).unwrap()
},
|after_param: &mut PluginAnalyzeDepsHookParam| {
serde_json::to_string(&after_param.deps).unwrap()
},
|plugin_name: String,
start_time: u128,
end_time: u128,
input: String,
output: String,
param: &PluginAnalyzeDepsHookParam,
context: &Arc<CompilationContext>| {
context
.stats
.add_plugin_hook_stats(CompilationPluginHookStats {
plugin_name: plugin_name.to_string(),
hook_name: "analyze_deps".to_string(),
hook_context: None,
module_id: param.module.id.clone(),
input,
output,
duration: end_time - start_time,
start_time,
end_time,
})
}
);
hook_serial!(finalize_module, &mut PluginFinalizeModuleHookParam);
hook_serial!(freeze_module, &mut PluginFreezeModuleHookParam);
hook_serial!(module_graph_build_end, &mut ModuleGraph);
hook_parallel!(build_end);
hook_parallel!(generate_start);
hook_serial!(
optimize_module_graph,
&mut ModuleGraph,
|before_param: &mut ModuleGraph| {
serde_json::to_string(&CompilationModuleGraphStats::from(&*before_param)).unwrap()
},
|after_param: &mut ModuleGraph| {
serde_json::to_string(&CompilationModuleGraphStats::from(&*after_param)).unwrap()
},
|plugin_name: String,
start_time: u128,
end_time: u128,
input: String,
output: String,
_: &mut ModuleGraph,
context: &Arc<CompilationContext>| {
context
.stats
.add_plugin_hook_stats(CompilationPluginHookStats {
plugin_name: plugin_name.to_string(),
hook_name: "optimize_module_graph".to_string(),
hook_context: None,
module_id: "".into(),
input,
output,
duration: end_time - start_time,
start_time,
end_time,
})
}
);
hook_serial!(
freeze_module_graph_meta,
&mut ModuleGraph,
|before_param: &mut ModuleGraph| {
serde_json::to_string(&CompilationModuleGraphStats::from(&*before_param)).unwrap()
},
|after_param: &mut ModuleGraph| {
serde_json::to_string(&CompilationModuleGraphStats::from(&*after_param)).unwrap()
},
|plugin_name: String,
start_time: u128,
end_time: u128,
input: String,
output: String,
_: &mut ModuleGraph,
context: &Arc<CompilationContext>| {
context
.stats
.add_plugin_hook_stats(CompilationPluginHookStats {
plugin_name: plugin_name.to_string(),
hook_name: "freeze_module_graph_meta".to_string(),
hook_context: None,
module_id: "".into(),
input,
output,
duration: end_time - start_time,
start_time,
end_time,
})
}
);
hook_first!(
analyze_module_graph,
Result<Option<ModuleGroupGraph>>,
|result: & Option<ModuleGroupGraph>,
plugin_name: String,
start_time: u128,
end_time: u128,
_param: &mut ModuleGraph,
context: &Arc<CompilationContext>,
hook_context: &PluginHookContext| {
if result.is_none() {
return;
}
context.stats.add_plugin_hook_stats(
CompilationPluginHookStats {
plugin_name: plugin_name.to_string(),
hook_name: "analyze_module_graph".to_string(),
hook_context: Some(hook_context.clone()),
module_id: "".into(),
input: "".to_string(),
output: serde_json::to_string(&result.as_ref().unwrap().print_graph()).unwrap(),
duration: end_time - start_time,
start_time,
end_time,
},
)
},
param: &mut ModuleGraph,
context: &Arc<CompilationContext>,
_hook_context: &PluginHookContext
);
hook_first!(
partial_bundling,
Result<Option<Vec<ResourcePot>>>,
|result: &Option<Vec<ResourcePot>>,
plugin_name: String,
start_time: u128,
end_time: u128,
modules: &Vec<ModuleId>,
context: &Arc<CompilationContext>,
hook_context: &PluginHookContext| {
if result.is_none() {
return;
}
context.stats.add_plugin_hook_stats(
CompilationPluginHookStats {
plugin_name: plugin_name.to_string(),
hook_name: "partial_bundling".to_string(),
hook_context: Some(hook_context.clone()),
module_id: "".into(),
input: serde_json::to_string(&modules).unwrap(),
output: serde_json::to_string(&result).unwrap(),
duration: end_time - start_time,
start_time,
end_time,
},
)
},
modules: &Vec<ModuleId>,
context: &Arc<CompilationContext>,
_hook_context: &PluginHookContext
);
hook_serial!(
process_resource_pots,
&mut Vec<&mut ResourcePot>,
|before_resource_pots: &mut Vec<&mut ResourcePot>| {
serde_json::to_string(&before_resource_pots).unwrap()
},
|after_resource_pots: &mut Vec<&mut ResourcePot>| {
serde_json::to_string(&after_resource_pots).unwrap()
},
|plugin_name: String,
start_time: u128,
end_time: u128,
input: String,
output: String,
_resource_pots: &mut Vec<&mut ResourcePot>,
context: &Arc<CompilationContext>| {
context
.stats
.add_plugin_hook_stats(CompilationPluginHookStats {
plugin_name: plugin_name.to_string(),
hook_name: "process_resource_pots".to_string(),
hook_context: None,
module_id: "".into(),
input,
output,
duration: end_time - start_time,
start_time,
end_time,
})
}
);
hook_serial!(render_start, &Config);
hook_first!(
render_resource_pot,
Result<Option<ResourcePotMetaData>>,
|result: &Option<ResourcePotMetaData>,
plugin_name: String,
start_time: u128,
end_time: u128,
resource_pot: &ResourcePot,
context: &Arc<CompilationContext>,
hook_context: &PluginHookContext| {
if result.is_none() {
return;
}
context.stats.add_plugin_hook_stats(
CompilationPluginHookStats {
plugin_name: plugin_name.to_string(),
hook_name: "render_resource_pot".to_string(),
hook_context: Some(hook_context.clone()),
module_id: "".into(),
input: serde_json::to_string(&resource_pot).unwrap(),
output: "".to_string(),
duration: end_time - start_time,
start_time,
end_time,
},
)
},
resource_pot: &ResourcePot,
context: &Arc<CompilationContext>,
_hook_context: &PluginHookContext
);
hook_serial!(
process_rendered_resource_pot,
&mut ResourcePot,
|before_resource_pot: &mut ResourcePot| {
serde_json::to_string(&before_resource_pot).unwrap()
},
|after_resource_pot: &mut ResourcePot| { serde_json::to_string(&after_resource_pot).unwrap() },
|plugin_name: String,
start_time: u128,
end_time: u128,
input: String,
output: String,
_resource_pot: &mut ResourcePot,
context: &Arc<CompilationContext>| {
context
.stats
.add_plugin_hook_stats(CompilationPluginHookStats {
plugin_name: plugin_name.to_string(),
hook_name: "process_rendered_resource_pot".to_string(),
hook_context: None,
module_id: "".into(),
input,
output,
duration: end_time - start_time,
start_time,
end_time,
})
}
);
pub fn augment_resource_pot_hash(
&self,
render_pot: &ResourcePot,
context: &Arc<CompilationContext>,
) -> Result<Option<String>> {
let mut result: Option<String> = None;
for plugin in &self.plugins {
if let Some(plugin_result) = plugin.augment_resource_pot_hash(render_pot, context)? {
match result {
Some(ref mut result) => {
result.push_str(plugin_result.as_str());
}
None => {
result = Some(plugin_result);
}
}
}
}
Ok(result)
}
hook_serial!(
optimize_resource_pot,
&mut ResourcePot,
|before_resource_pot: &mut ResourcePot| {
serde_json::to_string(&before_resource_pot).unwrap()
},
|after_resource_pot: &mut ResourcePot| { serde_json::to_string(&after_resource_pot).unwrap() },
|plugin_name: String,
start_time: u128,
end_time: u128,
input: String,
output: String,
_resource_pot: &mut ResourcePot,
context: &Arc<CompilationContext>| {
context
.stats
.add_plugin_hook_stats(CompilationPluginHookStats {
plugin_name: plugin_name.to_string(),
hook_name: "optimize_resource_pot".to_string(),
hook_context: None,
module_id: "".into(),
input,
output,
duration: end_time - start_time,
start_time,
end_time,
})
}
);
hook_first!(
generate_resources,
Result<Option<PluginGenerateResourcesHookResult>>,
|result: &Option<PluginGenerateResourcesHookResult>,
plugin_name: String,
start_time: u128,
end_time: u128,
resource_pot: &mut ResourcePot,
context: &Arc<CompilationContext>,
hook_context: &PluginHookContext| {
if let Some(resources) = result {
context.stats.add_plugin_hook_stats(
CompilationPluginHookStats {
plugin_name: plugin_name.to_string(),
hook_name: "generate_resources".to_string(),
hook_context: Some(hook_context.clone()),
module_id: "".into(),
input: serde_json::to_string(resource_pot).unwrap(),
output: serde_json::to_string(resources).unwrap(),
duration: end_time - start_time,
start_time,
end_time,
},
);
}
},
resource_pot: &mut ResourcePot,
context: &Arc<CompilationContext>,
_hook_context: &PluginHookContext
);
hook_serial!(
process_generated_resources,
&mut PluginGenerateResourcesHookResult
);
hook_serial!(
handle_entry_resource,
&mut PluginHandleEntryResourceHookParam
);
hook_serial!(finalize_resources, &mut PluginFinalizeResourcesHookParam);
hook_parallel!(generate_end);
hook_parallel!(
finish,
stat: &Stats,
|_plugin_name: String, _context: &Arc<CompilationContext>| {}
);
hook_serial!(
update_modules,
&mut PluginUpdateModulesHookParam,
|before_params: &mut PluginUpdateModulesHookParam| {
serde_json::to_string(&before_params).unwrap()
},
|after_params: &mut PluginUpdateModulesHookParam| {
serde_json::to_string(&after_params).unwrap()
},
|plugin_name: String,
start_time: u128,
end_time: u128,
input: String,
output: String,
_: &mut PluginUpdateModulesHookParam,
context: &Arc<CompilationContext>| {
context
.stats
.add_plugin_hook_stats(CompilationPluginHookStats {
plugin_name,
hook_name: "update_modules".to_string(),
hook_context: None,
module_id: "".into(),
input,
output,
duration: end_time - start_time,
start_time,
end_time,
})
}
);
hook_serial!(module_graph_updated, &PluginModuleGraphUpdatedHookParam);
hook_parallel!(update_finished);
hook_first!(
handle_persistent_cached_module,
Result<Option<bool>>,
|result: &Option<bool>,
plugin_name: String,
start_time: u128,
end_time: u128,
module: &Module,
context: &Arc<CompilationContext>| {
if let Some(res) = result {
context.stats.add_plugin_hook_stats(
CompilationPluginHookStats {
plugin_name: plugin_name.to_string(),
hook_name: "handle_persistent_cached_module".to_string(),
hook_context: None,
module_id: "".into(),
input: serde_json::to_string(&vec![module.id.to_string(), module.module_type.to_string()]).unwrap(),
output: serde_json::to_string(res).unwrap(),
duration: end_time - start_time,
start_time,
end_time,
},
);
};
},
module: &Module,
context: &Arc<CompilationContext>
);
pub fn write_plugin_cache(&self, context: &Arc<CompilationContext>) -> Result<()> {
for plugin in &self.plugins {
let start_time = if context.config.record {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.as_millis()
} else {
0
};
let plugin_cache = plugin.write_plugin_cache(context)?;
if let Some(plugin_cache) = plugin_cache {
context
.cache_manager
.plugin_cache
.set_cache(plugin.name(), plugin_cache);
if context.config.record {
let end_time = if context.config.record {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.as_millis()
} else {
0
};
context
.stats
.add_plugin_hook_stats(CompilationPluginHookStats {
plugin_name: plugin.name().to_string(),
hook_name: "write_plugin_cache".to_string(),
hook_context: None,
module_id: "".into(),
input: "".to_string(),
output: "".to_string(),
duration: end_time - start_time,
start_time,
end_time,
});
}
}
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct PluginDriverTransformHookResult {
pub content: String,
pub source_map_chain: Vec<Arc<String>>,
pub module_type: Option<ModuleType>,
}
#[cfg(test)]
mod tests {
use crate::HashMap;
use std::sync::Arc;
use crate::{
config::Config,
context::CompilationContext,
error::Result,
plugin::{
Plugin, PluginHookContext, PluginResolveHookParam, PluginResolveHookResult, ResolveKind,
},
};
use super::PluginDriver;
macro_rules! define_hook_first_plugin {
($plugin_name:ident, $should_return:expr) => {
struct $plugin_name {}
impl Plugin for $plugin_name {
fn name(&self) -> &str {
stringify!($plugin_name)
}
fn resolve(
&self,
_param: &PluginResolveHookParam,
_context: &Arc<CompilationContext>,
_hook_context: &PluginHookContext,
) -> Result<Option<PluginResolveHookResult>> {
if $should_return {
Ok(Some(PluginResolveHookResult {
resolved_path: stringify!($plugin_name).to_string(),
external: false,
side_effects: false,
query: vec![],
meta: HashMap::default(),
}))
} else {
Ok(None)
}
}
}
};
}
#[test]
fn hook_first() {
define_hook_first_plugin!(ResolvePlugin1, true);
define_hook_first_plugin!(ResolvePlugin2, true);
let plugin_driver = PluginDriver::new(
vec![Arc::new(ResolvePlugin1 {}), Arc::new(ResolvePlugin2 {})],
false,
);
let param = PluginResolveHookParam {
importer: None,
source: "./any".to_string(),
kind: ResolveKind::Import,
};
let context = Arc::new(CompilationContext::new(Config::default(), vec![]).unwrap());
let hook_context = PluginHookContext {
caller: None,
meta: HashMap::default(),
};
let resolved = plugin_driver
.resolve(¶m, &context, &hook_context)
.unwrap();
assert!(resolved.is_some());
assert_eq!(
resolved.unwrap().resolved_path,
String::from("ResolvePlugin1")
);
define_hook_first_plugin!(ResolvePlugin3, false);
define_hook_first_plugin!(ResolvePlugin4, true);
let plugin_driver = PluginDriver::new(
vec![Arc::new(ResolvePlugin3 {}), Arc::new(ResolvePlugin4 {})],
false,
);
let resolved = plugin_driver
.resolve(¶m, &context, &hook_context)
.unwrap();
assert!(resolved.is_some());
assert_eq!(
resolved.unwrap().resolved_path,
String::from("ResolvePlugin4")
);
define_hook_first_plugin!(ResolvePlugin5, false);
let plugin_driver = PluginDriver::new(vec![Arc::new(ResolvePlugin5 {})], false);
let resolved = plugin_driver
.resolve(¶m, &context, &hook_context)
.unwrap();
assert!(resolved.is_none());
}
#[test]
fn hook_serial() {}
#[test]
fn hook_parallel() {}
}