0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-02-12 16:59:32 -05:00

first diagnostic from a plugin!

This commit is contained in:
Bartek Iwańczuk 2024-12-02 02:27:30 +01:00
parent bc00517f9e
commit 7f45875211
No known key found for this signature in database
GPG key ID: 0C6BCDDC3B3AD750
3 changed files with 116 additions and 44 deletions

View file

@ -1,4 +1,4 @@
import { op_lint_get_rule } from "ext:core/ops"; import { op_lint_get_rule, op_lint_report } from "ext:core/ops";
export class Context { export class Context {
id; id;
@ -10,8 +10,8 @@ export class Context {
this.fileName = fileName; this.fileName = fileName;
} }
report() { report(data) {
console.log("Not implemented report"); op_lint_report(this.id, this.fileName, data.message);
} }
} }

View file

@ -380,39 +380,45 @@ impl WorkspaceLinter {
} }
} }
let r = linter.lint_file( let mut r = linter.lint_file(
&file_path, &file_path,
file_text, file_text,
cli_options.ext_flag().as_deref(), cli_options.ext_flag().as_deref(),
); );
if let Ok((file_source, file_diagnostics)) = &r { let r = match r {
let file_source_ = file_source.clone(); Ok((file_source, mut file_diagnostics)) => {
tokio_util::create_and_run_current_thread( let file_source_ = file_source.clone();
async move { let plugin_diagnostics =
let plugin_runner = linter.get_plugin_runner().unwrap(); tokio_util::create_and_run_current_thread(
let mut plugin_runner = plugin_runner.lock(); async move {
let serialized_ast = let plugin_runner = linter.get_plugin_runner().unwrap();
plugins::get_estree_from_parsed_source(file_source_)?; let mut plugin_runner = plugin_runner.lock();
plugins::run_rules_for_ast( let serialized_ast =
&mut *plugin_runner, plugins::get_estree_from_parsed_source(file_source_)?;
serialized_ast, plugins::run_rules_for_ast(
) &mut *plugin_runner,
.await serialized_ast,
} )
.boxed_local(), .await
)?; }
.boxed_local(),
)?;
if let Some(incremental_cache) = &maybe_incremental_cache { file_diagnostics.extend_from_slice(&plugin_diagnostics);
if file_diagnostics.is_empty() { if let Some(incremental_cache) = &maybe_incremental_cache {
// update the incremental cache if there were no diagnostics if file_diagnostics.is_empty() {
incremental_cache.update_file( // update the incremental cache if there were no diagnostics
&file_path, incremental_cache.update_file(
// ensure the returned text is used here as it may have been modified via --fix &file_path,
file_source.text(), // ensure the returned text is used here as it may have been modified via --fix
) file_source.text(),
)
}
} }
Ok((file_source, file_diagnostics))
} }
} Err(err) => Err(err),
};
let success = handle_lint_result( let success = handle_lint_result(
&file_path.to_string_lossy(), &file_path.to_string_lossy(),

View file

@ -15,6 +15,8 @@ use deno_core::JsRuntime;
use deno_core::OpState; use deno_core::OpState;
use deno_core::PollEventLoopOptions; use deno_core::PollEventLoopOptions;
use deno_core::RuntimeOptions; use deno_core::RuntimeOptions;
use deno_lint::diagnostic::LintDiagnostic;
use deno_lint::diagnostic::LintDiagnosticDetails;
use deno_runtime::tokio_util; use deno_runtime::tokio_util;
use indexmap::IndexMap; use indexmap::IndexMap;
use std::rc::Rc; use std::rc::Rc;
@ -31,11 +33,18 @@ pub enum PluginRunnerRequest {
Run(String), Run(String),
} }
#[derive(Debug)]
pub enum PluginRunnerResponse { pub enum PluginRunnerResponse {
LoadPlugin(Result<(), AnyError>), LoadPlugin(Result<(), AnyError>),
// TODO: should return diagnostics Run(Result<Vec<LintDiagnostic>, AnyError>),
Run(Result<(), AnyError>), }
impl std::fmt::Debug for PluginRunnerResponse {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::LoadPlugin(_arg0) => f.debug_tuple("LoadPlugin").finish(),
Self::Run(_arg0) => f.debug_tuple("Run").finish(),
}
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -57,17 +66,24 @@ impl PluginRunner {
let (tx_req, rx_req) = channel(10); let (tx_req, rx_req) = channel(10);
let (tx_res, rx_res) = channel(10); let (tx_res, rx_res) = channel(10);
eprintln!("spawning thread");
let join_handle = std::thread::spawn(move || { let join_handle = std::thread::spawn(move || {
eprintln!("thread spawned");
let mut runtime = JsRuntime::new(RuntimeOptions { let mut runtime = JsRuntime::new(RuntimeOptions {
extensions: vec![deno_lint_ext::init_ops()], extensions: vec![deno_lint_ext::init_ops()],
module_loader: Some(Rc::new(deno_core::FsModuleLoader)), module_loader: Some(Rc::new(deno_core::FsModuleLoader)),
..Default::default() ..Default::default()
}); });
let obj = runtime.lazy_load_es_module_with_code( eprintln!("before loaded");
let obj_result = runtime.lazy_load_es_module_with_code(
"ext:cli/lint.js", "ext:cli/lint.js",
deno_core::ascii_str_include!(concat!("lint.js")), deno_core::ascii_str_include!(concat!("lint.js")),
)?; );
eprintln!("after loaded {}", obj_result.is_err());
let obj = obj_result?;
let run_plugin_rule_fn = { let run_plugin_rule_fn = {
let scope = &mut runtime.handle_scope(); let scope = &mut runtime.handle_scope();
@ -85,10 +101,13 @@ impl PluginRunner {
tx: tx_res, tx: tx_res,
rx: rx_req, rx: rx_req,
}; };
// TODO(bartlomieju): send "host ready" message to the proxy
runner.run_loop() eprintln!("running host loop");
runner.run_loop()?;
Ok(())
}); });
eprintln!("is thread finished {}", join_handle.is_finished());
let proxy = PluginRunnerProxy { let proxy = PluginRunnerProxy {
tx: tx_req, tx: tx_req,
rx: Arc::new(tokio::sync::Mutex::new(rx_res)), rx: Arc::new(tokio::sync::Mutex::new(rx_res)),
@ -100,7 +119,9 @@ impl PluginRunner {
fn run_loop(mut self) -> Result<(), AnyError> { fn run_loop(mut self) -> Result<(), AnyError> {
let fut = async move { let fut = async move {
eprintln!("waiting for message");
while let Some(req) = self.rx.recv().await { while let Some(req) = self.rx.recv().await {
eprintln!("received message");
match req { match req {
PluginRunnerRequest::LoadPlugins(specifiers) => { PluginRunnerRequest::LoadPlugins(specifiers) => {
let r = self.load_plugins(specifiers).await; let r = self.load_plugins(specifiers).await;
@ -117,17 +138,28 @@ impl PluginRunner {
} }
} }
let r = self.run_rules(rules_to_run, serialized_ast).await; let r = match self.run_rules(rules_to_run, serialized_ast).await {
Ok(()) => Ok(self.take_diagnostics()),
Err(err) => Err(err),
};
let _ = self.tx.send(PluginRunnerResponse::Run(r)).await; let _ = self.tx.send(PluginRunnerResponse::Run(r)).await;
} }
} }
} }
eprintln!("breaking loop");
Ok(()) Ok(())
} }
.boxed_local(); .boxed_local();
tokio_util::create_and_run_current_thread(fut) tokio_util::create_and_run_current_thread(fut)
} }
fn take_diagnostics(&mut self) -> Vec<LintDiagnostic> {
let op_state = self.runtime.op_state();
let mut state = op_state.borrow_mut();
let mut container = state.borrow_mut::<LintPluginContainer>();
std::mem::take(&mut container.diagnostics)
}
fn get_rules_to_run(&mut self) -> IndexMap<String, Vec<String>> { fn get_rules_to_run(&mut self) -> IndexMap<String, Vec<String>> {
let op_state = self.runtime.op_state(); let op_state = self.runtime.op_state();
let state = op_state.borrow(); let state = op_state.borrow();
@ -227,6 +259,7 @@ impl PluginRunnerProxy {
.send(PluginRunnerRequest::LoadPlugins(plugin_specifiers)) .send(PluginRunnerRequest::LoadPlugins(plugin_specifiers))
.await?; .await?;
let mut rx = self.rx.lock().await; let mut rx = self.rx.lock().await;
eprintln!("receiving load plugins");
if let Some(_val) = rx.recv().await { if let Some(_val) = rx.recv().await {
return Ok(()); return Ok(());
} }
@ -236,14 +269,16 @@ impl PluginRunnerProxy {
pub async fn run_rules( pub async fn run_rules(
&self, &self,
serialized_ast: String, serialized_ast: String,
) -> Result<(), AnyError> { ) -> Result<Vec<LintDiagnostic>, AnyError> {
self self
.tx .tx
.send(PluginRunnerRequest::Run(serialized_ast)) .send(PluginRunnerRequest::Run(serialized_ast))
.await?; .await?;
let mut rx = self.rx.lock().await; let mut rx = self.rx.lock().await;
if let Some(_val) = rx.recv().await { eprintln!("receiving diagnostics");
return Ok(()); if let Some(PluginRunnerResponse::Run(diagnostics_result)) = rx.recv().await
{
return diagnostics_result;
} }
Err(custom_error("AlreadyClosed", "Plugin host has closed")) Err(custom_error("AlreadyClosed", "Plugin host has closed"))
} }
@ -260,9 +295,9 @@ pub async fn create_runner_and_load_plugins(
pub async fn run_rules_for_ast( pub async fn run_rules_for_ast(
runner_proxy: &mut PluginRunnerProxy, runner_proxy: &mut PluginRunnerProxy,
serialized_ast: String, serialized_ast: String,
) -> Result<(), AnyError> { ) -> Result<Vec<LintDiagnostic>, AnyError> {
runner_proxy.run_rules(serialized_ast).await?; let d = runner_proxy.run_rules(serialized_ast).await?;
Ok(()) Ok(d)
} }
pub fn get_estree_from_parsed_source( pub fn get_estree_from_parsed_source(
@ -299,6 +334,7 @@ struct LintPluginDesc {
#[derive(Default)] #[derive(Default)]
struct LintPluginContainer { struct LintPluginContainer {
plugins: IndexMap<String, LintPluginDesc>, plugins: IndexMap<String, LintPluginDesc>,
diagnostics: Vec<LintDiagnostic>,
} }
impl LintPluginContainer { impl LintPluginContainer {
@ -317,6 +353,24 @@ impl LintPluginContainer {
self.plugins.insert(name, desc); self.plugins.insert(name, desc);
Ok(()) Ok(())
} }
fn report(&mut self, id: String, specifier: String, message: String) {
let lint_diagnostic = LintDiagnostic {
// TODO: fix
specifier: ModuleSpecifier::parse(&format!("file:///{}", specifier))
.unwrap(),
range: None,
details: LintDiagnosticDetails {
message,
code: id,
hint: None,
fixes: vec![],
custom_docs_url: None,
info: vec![],
},
};
self.diagnostics.push(lint_diagnostic);
}
} }
deno_core::extension!( deno_core::extension!(
@ -324,7 +378,8 @@ deno_core::extension!(
ops = [ ops = [
op_lint_register_lint_plugin, op_lint_register_lint_plugin,
op_lint_register_lint_plugin_rule, op_lint_register_lint_plugin_rule,
op_lint_get_rule op_lint_get_rule,
op_lint_report,
], ],
state = |state| { state = |state| {
state.put(LintPluginContainer::default()); state.put(LintPluginContainer::default());
@ -385,3 +440,14 @@ fn op_lint_get_rule(
}; };
Ok(rule.clone()) Ok(rule.clone())
} }
#[op2(fast)]
fn op_lint_report(
state: &mut OpState,
#[string] id: String,
#[string] specifier: String,
#[string] message: String,
) {
let mut container = state.borrow_mut::<LintPluginContainer>();
container.report(id, specifier, message);
}