0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-02-01 20:25:12 -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 {
id;
@ -10,8 +10,8 @@ export class Context {
this.fileName = fileName;
}
report() {
console.log("Not implemented report");
report(data) {
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_text,
cli_options.ext_flag().as_deref(),
);
if let Ok((file_source, file_diagnostics)) = &r {
let file_source_ = file_source.clone();
tokio_util::create_and_run_current_thread(
async move {
let plugin_runner = linter.get_plugin_runner().unwrap();
let mut plugin_runner = plugin_runner.lock();
let serialized_ast =
plugins::get_estree_from_parsed_source(file_source_)?;
plugins::run_rules_for_ast(
&mut *plugin_runner,
serialized_ast,
)
.await
}
.boxed_local(),
)?;
let r = match r {
Ok((file_source, mut file_diagnostics)) => {
let file_source_ = file_source.clone();
let plugin_diagnostics =
tokio_util::create_and_run_current_thread(
async move {
let plugin_runner = linter.get_plugin_runner().unwrap();
let mut plugin_runner = plugin_runner.lock();
let serialized_ast =
plugins::get_estree_from_parsed_source(file_source_)?;
plugins::run_rules_for_ast(
&mut *plugin_runner,
serialized_ast,
)
.await
}
.boxed_local(),
)?;
if let Some(incremental_cache) = &maybe_incremental_cache {
if file_diagnostics.is_empty() {
// update the incremental cache if there were no diagnostics
incremental_cache.update_file(
&file_path,
// ensure the returned text is used here as it may have been modified via --fix
file_source.text(),
)
file_diagnostics.extend_from_slice(&plugin_diagnostics);
if let Some(incremental_cache) = &maybe_incremental_cache {
if file_diagnostics.is_empty() {
// update the incremental cache if there were no diagnostics
incremental_cache.update_file(
&file_path,
// 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(
&file_path.to_string_lossy(),

View file

@ -15,6 +15,8 @@ use deno_core::JsRuntime;
use deno_core::OpState;
use deno_core::PollEventLoopOptions;
use deno_core::RuntimeOptions;
use deno_lint::diagnostic::LintDiagnostic;
use deno_lint::diagnostic::LintDiagnosticDetails;
use deno_runtime::tokio_util;
use indexmap::IndexMap;
use std::rc::Rc;
@ -31,11 +33,18 @@ pub enum PluginRunnerRequest {
Run(String),
}
#[derive(Debug)]
pub enum PluginRunnerResponse {
LoadPlugin(Result<(), AnyError>),
// TODO: should return diagnostics
Run(Result<(), AnyError>),
Run(Result<Vec<LintDiagnostic>, 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)]
@ -57,17 +66,24 @@ impl PluginRunner {
let (tx_req, rx_req) = channel(10);
let (tx_res, rx_res) = channel(10);
eprintln!("spawning thread");
let join_handle = std::thread::spawn(move || {
eprintln!("thread spawned");
let mut runtime = JsRuntime::new(RuntimeOptions {
extensions: vec![deno_lint_ext::init_ops()],
module_loader: Some(Rc::new(deno_core::FsModuleLoader)),
..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",
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 scope = &mut runtime.handle_scope();
@ -85,10 +101,13 @@ impl PluginRunner {
tx: tx_res,
rx: rx_req,
};
runner.run_loop()
// TODO(bartlomieju): send "host ready" message to the proxy
eprintln!("running host loop");
runner.run_loop()?;
Ok(())
});
eprintln!("is thread finished {}", join_handle.is_finished());
let proxy = PluginRunnerProxy {
tx: tx_req,
rx: Arc::new(tokio::sync::Mutex::new(rx_res)),
@ -100,7 +119,9 @@ impl PluginRunner {
fn run_loop(mut self) -> Result<(), AnyError> {
let fut = async move {
eprintln!("waiting for message");
while let Some(req) = self.rx.recv().await {
eprintln!("received message");
match req {
PluginRunnerRequest::LoadPlugins(specifiers) => {
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;
}
}
}
eprintln!("breaking loop");
Ok(())
}
.boxed_local();
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>> {
let op_state = self.runtime.op_state();
let state = op_state.borrow();
@ -227,6 +259,7 @@ impl PluginRunnerProxy {
.send(PluginRunnerRequest::LoadPlugins(plugin_specifiers))
.await?;
let mut rx = self.rx.lock().await;
eprintln!("receiving load plugins");
if let Some(_val) = rx.recv().await {
return Ok(());
}
@ -236,14 +269,16 @@ impl PluginRunnerProxy {
pub async fn run_rules(
&self,
serialized_ast: String,
) -> Result<(), AnyError> {
) -> Result<Vec<LintDiagnostic>, AnyError> {
self
.tx
.send(PluginRunnerRequest::Run(serialized_ast))
.await?;
let mut rx = self.rx.lock().await;
if let Some(_val) = rx.recv().await {
return Ok(());
eprintln!("receiving diagnostics");
if let Some(PluginRunnerResponse::Run(diagnostics_result)) = rx.recv().await
{
return diagnostics_result;
}
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(
runner_proxy: &mut PluginRunnerProxy,
serialized_ast: String,
) -> Result<(), AnyError> {
runner_proxy.run_rules(serialized_ast).await?;
Ok(())
) -> Result<Vec<LintDiagnostic>, AnyError> {
let d = runner_proxy.run_rules(serialized_ast).await?;
Ok(d)
}
pub fn get_estree_from_parsed_source(
@ -299,6 +334,7 @@ struct LintPluginDesc {
#[derive(Default)]
struct LintPluginContainer {
plugins: IndexMap<String, LintPluginDesc>,
diagnostics: Vec<LintDiagnostic>,
}
impl LintPluginContainer {
@ -317,6 +353,24 @@ impl LintPluginContainer {
self.plugins.insert(name, desc);
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!(
@ -324,7 +378,8 @@ deno_core::extension!(
ops = [
op_lint_register_lint_plugin,
op_lint_register_lint_plugin_rule,
op_lint_get_rule
op_lint_get_rule,
op_lint_report,
],
state = |state| {
state.put(LintPluginContainer::default());
@ -385,3 +440,14 @@ fn op_lint_get_rule(
};
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);
}