diff --git a/cli/js/40_lint.js b/cli/js/40_lint.js index 01b888dcd3..36a241d32e 100644 --- a/cli/js/40_lint.js +++ b/cli/js/40_lint.js @@ -236,10 +236,23 @@ export class Context { } /** - * @param {LintPlugin} plugin + * @param {LintPlugin[]} plugins * @param {string[]} exclude */ -export function installPlugin(plugin, exclude) { +export function installPlugins(plugins, exclude) { + if (Array.isArray(exclude)) { + for (let i = 0; i < exclude.length; i++) { + state.ignoredRules.add(exclude[i]); + } + } + + return plugins.map((plugin) => installPlugin(plugin)); +} + +/** + * @param {LintPlugin} plugin + */ +function installPlugin(plugin) { if (typeof plugin !== "object") { throw new Error("Linter plugin must be an object"); } @@ -255,14 +268,6 @@ export function installPlugin(plugin, exclude) { state.plugins.push(plugin); state.installedPlugins.add(plugin.name); - // TODO(@marvinhagemeister): This should be done once instead of - // for every plugin - if (Array.isArray(exclude)) { - for (let i = 0; i < exclude.length; i++) { - state.ignoredRules.add(exclude[i]); - } - } - return { name: plugin.name, ruleNames: Object.keys(plugin.rules), @@ -1280,7 +1285,7 @@ function _dump(ctx) { // These are captured by Rust and called when plugins need to be loaded // or run. -internals.installPlugin = installPlugin; +internals.installPlugins = installPlugins; internals.runPluginsForFile = runPluginsForFile; internals.resetState = resetState; @@ -1290,7 +1295,7 @@ internals.resetState = resetState; * @param {string} sourceText */ function runLintPlugin(plugin, fileName, sourceText) { - installPlugin(plugin, []); + installPlugin(plugin); const serializedAst = op_lint_create_serialized_ast(fileName, sourceText); const diagnostics = []; diff --git a/cli/tools/lint/plugins.rs b/cli/tools/lint/plugins.rs index 3f7dfdc91f..03da40dbd2 100644 --- a/cli/tools/lint/plugins.rs +++ b/cli/tools/lint/plugins.rs @@ -103,7 +103,8 @@ macro_rules! v8_static_strings { } v8_static_strings! { - INSTALL_PLUGIN = "installPlugin", + DEFAULT = "default", + INSTALL_PLUGINS = "installPlugins", RUN_PLUGINS_FOR_FILE = "runPluginsForFile", } @@ -133,7 +134,7 @@ impl PluginHostProxy { pub struct PluginHost { worker: MainWorker, - install_plugin_fn: Rc>, + install_plugins_fn: Rc>, run_plugins_for_file_fn: Rc>, tx: Sender, rx: Receiver, @@ -183,17 +184,17 @@ async fn create_plugin_runner_inner( let obj = runtime.execute_script("lint.js", "Deno[Deno.internal]")?; logger.log("After plugin loaded, capturing exports"); - let (install_plugin_fn, run_plugins_for_file_fn) = { + let (install_plugins_fn, run_plugins_for_file_fn) = { let scope = &mut runtime.handle_scope(); let module_exports: v8::Local = v8::Local::new(scope, obj).try_into().unwrap(); - let install_plugin_fn_name = INSTALL_PLUGIN.v8_string(scope).unwrap(); - let install_plugin_fn_val = module_exports - .get(scope, install_plugin_fn_name.into()) + let install_plugins_fn_name = INSTALL_PLUGINS.v8_string(scope).unwrap(); + let install_plugins_fn_val = module_exports + .get(scope, install_plugins_fn_name.into()) .unwrap(); - let install_plugin_fn: v8::Local = - install_plugin_fn_val.try_into().unwrap(); + let install_plugins_fn: v8::Local = + install_plugins_fn_val.try_into().unwrap(); let run_plugins_for_file_fn_name = RUN_PLUGINS_FOR_FILE.v8_string(scope).unwrap(); @@ -204,14 +205,14 @@ async fn create_plugin_runner_inner( run_plugins_for_file_fn_val.try_into().unwrap(); ( - Rc::new(v8::Global::new(scope, install_plugin_fn)), + Rc::new(v8::Global::new(scope, install_plugins_fn)), Rc::new(v8::Global::new(scope, run_plugins_for_file_fn)), ) }; Ok(PluginHost { worker, - install_plugin_fn, + install_plugins_fn, run_plugins_for_file_fn, tx: tx_res, rx: rx_req, @@ -407,42 +408,58 @@ impl PluginHost { .run_event_loop(PollEventLoopOptions::default()) .await?; - let mut infos = Vec::with_capacity(load_futures.len()); + let mut plugin_handles = Vec::with_capacity(load_futures.len()); for (fut, mod_id) in load_futures { fut.await?; let module = self.worker.js_runtime.get_module_namespace(mod_id).unwrap(); let scope = &mut self.worker.js_runtime.handle_scope(); let module_local = v8::Local::new(scope, module); - let default_export_str = v8::String::new(scope, "default").unwrap(); + let default_export_str = DEFAULT.v8_string(scope).unwrap(); let default_export = module_local.get(scope, default_export_str.into()).unwrap(); - let install_plugins_local = - v8::Local::new(scope, &*self.install_plugin_fn.clone()); - let undefined = v8::undefined(scope); - - let exclude_v8: v8::Local = - exclude.clone().map_or(v8::null(scope).into(), |v| { - let elems = v - .iter() - .map(|item| v8::String::new(scope, item).unwrap().into()) - .collect::>(); - - v8::Array::new_with_elements(scope, elems.as_slice()).into() - }); - - let args = &[default_export, exclude_v8]; - - self.logger.log("Installing plugin..."); - // TODO(bartlomieju): do it in a try/catch scope - let plugin_info = install_plugins_local - .call(scope, undefined.into(), args) - .unwrap(); - let info: PluginInfo = deno_core::serde_v8::from_v8(scope, plugin_info)?; - self.logger.log(&format!("Plugin installed: {}", info.name)); - infos.push(info); + let default_export_global = v8::Global::new(scope, default_export); + plugin_handles.push(default_export_global); } + let scope = &mut self.worker.js_runtime.handle_scope(); + let install_plugins_local = + v8::Local::new(scope, &*self.install_plugins_fn.clone()); + let exclude_v8: v8::Local = + exclude.map_or(v8::null(scope).into(), |v| { + let elems = v + .iter() + .map(|item| v8::String::new(scope, item).unwrap().into()) + .collect::>(); + + v8::Array::new_with_elements(scope, elems.as_slice()).into() + }); + + let undefined = v8::undefined(scope); + + let local_handles = { + let arr = v8::Array::new(scope, plugin_handles.len().try_into().unwrap()); + for (idx, plugin_handle) in plugin_handles.into_iter().enumerate() { + let handle = v8::Local::new(scope, plugin_handle); + arr + .set_index(scope, idx.try_into().unwrap(), handle) + .unwrap(); + } + arr + }; + let args = &[local_handles.into(), exclude_v8]; + + self.logger.log("Installing plugins..."); + // TODO(bartlomieju): do it in a try/catch scope, or not? Seems to surface errors properly. + let plugins_info = install_plugins_local + .call(scope, undefined.into(), args) + .unwrap(); + let infos: Vec = + deno_core::serde_v8::from_v8(scope, plugins_info)?; + self + .logger + .log(&format!("Plugins installed: {}", infos.len())); + Ok(infos) } }