1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-21 13:00:36 -05:00

update for deno_lint changes

This commit is contained in:
Bartek Iwańczuk 2025-01-02 19:07:55 +01:00
parent 321e37bf2e
commit 2edd30904a
No known key found for this signature in database
GPG key ID: 0C6BCDDC3B3AD750
6 changed files with 120 additions and 61 deletions

2
Cargo.lock generated
View file

@ -1875,8 +1875,6 @@ dependencies = [
[[package]]
name = "deno_lint"
version = "0.68.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce713d564f76efd90535061113210bdc6b942ed6327b33eb1d5f76a5daf8e7a5"
dependencies = [
"anyhow",
"deno_ast",

View file

@ -350,3 +350,4 @@ opt-level = 3
[patch.crates-io]
deno_config = { git = "https://github.com/denoland/deno_config.git", branch = "deno_lint_rules" }
deno_lint = { path = "../deno_lint" }

View file

@ -213,6 +213,11 @@ export function installPlugin(plugin) {
}
state.plugins.push(plugin);
state.installedPlugins.add(plugin.name);
return {
name: plugin.name,
ruleNames: Object.keys(plugin.rules),
};
}
/**

View file

@ -15,6 +15,8 @@ use deno_core::futures::FutureExt as _;
use deno_core::parking_lot::Mutex;
use deno_graph::ModuleGraph;
use deno_lint::diagnostic::LintDiagnostic;
use deno_lint::linter::ExternalLinterCb;
use deno_lint::linter::ExternalLinterResult;
use deno_lint::linter::LintConfig as DenoLintConfig;
use deno_lint::linter::LintFileOptions;
use deno_lint::linter::Linter as DenoLintLinter;
@ -75,18 +77,6 @@ impl CliLinter {
}
}
pub fn run_plugins(
&self,
parsed_source: ParsedSource,
file_path: PathBuf,
) -> Result<Vec<LintDiagnostic>, AnyError> {
let Some(plugin_runner) = self.maybe_plugin_runner.clone() else {
return Ok(vec![]);
};
run_plugins(plugin_runner, parsed_source, file_path)
}
pub fn has_package_rules(&self) -> bool {
!self.package_rules.is_empty()
}
@ -107,22 +97,23 @@ impl CliLinter {
&self,
parsed_source: &ParsedSource,
) -> Vec<LintDiagnostic> {
let mut diagnostics = self
.linter
.lint_with_ast(parsed_source, self.deno_lint_config.clone());
let file_path = parsed_source.specifier().to_file_path().unwrap();
// TODO(bartlomieju): surface error is running plugin fails
// TODO(bartlomieju): plugins don't support fixing for now.
let run_plugin_result = self.run_plugins(parsed_source.clone(), file_path);
if let Err(err) = run_plugin_result.as_ref() {
eprintln!("run plugin result {:#?}", err);
}
let maybe_plugin_diagnostics = run_plugin_result.ok();
if let Some(plugin_diagnostics) = maybe_plugin_diagnostics {
diagnostics.extend_from_slice(&plugin_diagnostics);
}
let external_linter: Option<ExternalLinterCb> =
if let Some(plugin_runner) = self.maybe_plugin_runner.clone() {
Some(Arc::new(move |parsed_source: ParsedSource| {
// TODO: clean this up
let file_path = parsed_source.specifier().to_file_path().unwrap();
run_plugins(plugin_runner.clone(), parsed_source, file_path)
}))
} else {
None
};
diagnostics
self.linter.lint_with_ast(
parsed_source,
self.deno_lint_config.clone(),
external_linter,
)
}
pub fn lint_file(
@ -140,22 +131,37 @@ impl CliLinter {
MediaType::from_specifier(&specifier)
};
// TODO(bartlomieju): surface error is running plugin fails
let external_linter: Option<ExternalLinterCb> =
if let Some(plugin_runner) = self.maybe_plugin_runner.clone() {
Some(Arc::new(move |parsed_source: ParsedSource| {
// TODO: clean this up
let file_path = parsed_source.specifier().to_file_path().unwrap();
run_plugins(plugin_runner.clone(), parsed_source, file_path)
}))
} else {
None
};
if self.fix {
self.lint_file_and_fix(&specifier, media_type, source_code, file_path)
self.lint_file_and_fix(
&specifier,
media_type,
source_code,
file_path,
external_linter,
)
} else {
let (source, mut diagnostics) = self
let (source, diagnostics) = self
.linter
.lint_file(LintFileOptions {
specifier,
media_type,
source_code,
config: self.deno_lint_config.clone(),
external_linter,
})
.map_err(AnyError::from)?;
let plugin_diagnostics =
self.run_plugins(source.clone(), file_path.to_path_buf())?;
diagnostics.extend_from_slice(&plugin_diagnostics);
Ok((source, diagnostics))
}
@ -167,20 +173,17 @@ impl CliLinter {
media_type: MediaType,
source_code: String,
file_path: &Path,
external_linter: Option<ExternalLinterCb>,
) -> Result<(ParsedSource, Vec<LintDiagnostic>), deno_core::anyhow::Error> {
// initial lint
let (source, mut diagnostics) = self.linter.lint_file(LintFileOptions {
let (source, diagnostics) = self.linter.lint_file(LintFileOptions {
specifier: specifier.clone(),
media_type,
source_code,
config: self.deno_lint_config.clone(),
external_linter: external_linter.clone(),
})?;
let plugin_diagnostics =
self.run_plugins(source.clone(), file_path.to_path_buf())?;
diagnostics.extend_from_slice(&plugin_diagnostics);
// Try applying fixes repeatedly until the file has none left or
// a maximum number of iterations is reached. This is necessary
// because lint fixes may overlap and so we can't always apply
@ -196,6 +199,7 @@ impl CliLinter {
self.deno_lint_config.clone(),
source.text_info_lazy(),
&diagnostics,
external_linter.clone(),
)?;
match change {
Some(change) => {
@ -241,6 +245,7 @@ fn apply_lint_fixes_and_relint(
config: DenoLintConfig,
text_info: &SourceTextInfo,
diagnostics: &[LintDiagnostic],
external_linter: Option<ExternalLinterCb>,
) -> Result<Option<(ParsedSource, Vec<LintDiagnostic>)>, AnyError> {
let Some(new_text) = apply_lint_fixes(text_info, diagnostics) else {
return Ok(None);
@ -251,6 +256,7 @@ fn apply_lint_fixes_and_relint(
source_code: new_text,
media_type,
config,
external_linter,
})
.map(Some)
.context(
@ -309,8 +315,10 @@ fn run_plugins(
plugin_runner: Arc<Mutex<PluginHostProxy>>,
parsed_source: ParsedSource,
file_path: PathBuf,
) -> Result<Vec<LintDiagnostic>, AnyError> {
) -> Result<ExternalLinterResult, AnyError> {
let source_text_info = parsed_source.text_info_lazy().clone();
let plugin_info = plugin_runner.lock().get_plugin_rules();
#[allow(clippy::await_holding_lock)]
let fut = async move {
let mut plugin_runner = plugin_runner.lock();
@ -328,5 +336,8 @@ fn run_plugins(
let plugin_diagnostics = tokio_util::create_and_run_current_thread(fut)?;
Ok(plugin_diagnostics)
Ok(ExternalLinterResult {
diagnostics: plugin_diagnostics,
rules: plugin_info,
})
}

View file

@ -1,11 +1,17 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use std::path::Path;
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::Arc;
use deno_ast::ModuleSpecifier;
use deno_ast::ParsedSource;
use deno_ast::SourceTextInfo;
use deno_core::error::custom_error;
use deno_core::error::AnyError;
use deno_core::futures::FutureExt;
use deno_core::parking_lot::Mutex;
use deno_core::resolve_url_or_path;
use deno_core::v8;
use deno_core::PollEventLoopOptions;
@ -15,10 +21,6 @@ use deno_runtime::deno_permissions::PermissionsContainer;
use deno_runtime::tokio_util;
use deno_runtime::worker::MainWorker;
use deno_runtime::WorkerExecutionMode;
use std::path::Path;
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::Arc;
use tokio::sync::mpsc::channel;
use tokio::sync::mpsc::Receiver;
use tokio::sync::mpsc::Sender;
@ -37,7 +39,7 @@ pub enum PluginHostRequest {
}
pub enum PluginHostResponse {
LoadPlugin(Result<(), AnyError>),
LoadPlugin(Result<Vec<PluginInfo>, AnyError>),
Run(Result<Vec<LintDiagnostic>, AnyError>),
}
@ -99,11 +101,26 @@ v8_static_strings! {
pub struct PluginHostProxy {
tx: Sender<PluginHostRequest>,
rx: Arc<tokio::sync::Mutex<Receiver<PluginHostResponse>>>,
pub(crate) plugin_info: Arc<Mutex<Vec<PluginInfo>>>,
#[allow(unused)]
join_handle: std::thread::JoinHandle<Result<(), AnyError>>,
logger: PluginLogger,
}
impl PluginHostProxy {
pub fn get_plugin_rules(&self) -> Vec<String> {
let infos = self.plugin_info.lock();
let mut all_names = vec![];
for info in infos.iter() {
all_names.extend_from_slice(&info.get_rules());
}
all_names
}
}
pub struct PluginHost {
worker: MainWorker,
install_plugin_fn: Rc<v8::Global<v8::Function>>,
@ -123,17 +140,16 @@ async fn create_plugin_runner_inner(
..Default::default()
};
let flags = Arc::new(flags);
let factory = CliFactory::from_flags(flags);
let factory = CliFactory::from_flags(flags.clone());
let cli_options = factory.cli_options()?;
let main_module =
resolve_url_or_path("./$deno$lint.mts", cli_options.initial_cwd()).unwrap();
// TODO(bartlomieju): should we run with all permissions?
// TODO(bartlomieju): use none permissions, but with it, the JSR plugin doesn't work
// anymore
let permissions = PermissionsContainer::allow_all(
factory.permission_desc_parser()?.clone(),
// Permissions::none(false),
);
let perm_parser = factory.permission_desc_parser()?;
let permissions = Permissions::from_options(
perm_parser.as_ref(),
&flags.permissions.to_options(&[]),
)?;
let permissions = PermissionsContainer::new(perm_parser.clone(), permissions);
// let npm_resolver = factory.npm_resolver().await?.clone();
// let resolver = factory.resolver().await?.clone();
let worker_factory = factory.create_cli_main_worker_factory().await?;
@ -193,6 +209,25 @@ async fn create_plugin_runner_inner(
})
}
#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PluginInfo {
pub name: String,
pub rule_names: Vec<String>,
}
impl PluginInfo {
pub fn get_rules(&self) -> Vec<String> {
let mut rules = Vec::with_capacity(self.rule_names.len());
for rule_name in &self.rule_names {
rules.push(format!("{}/{}", self.name, rule_name));
}
rules
}
}
impl PluginHost {
fn create(logger: PluginLogger) -> Result<PluginHostProxy, AnyError> {
let (tx_req, rx_req) = channel(10);
@ -224,6 +259,7 @@ impl PluginHost {
let proxy = PluginHostProxy {
tx: tx_req,
rx: Arc::new(tokio::sync::Mutex::new(rx_res)),
plugin_info: Arc::new(Mutex::new(vec![])),
join_handle,
logger,
};
@ -325,7 +361,7 @@ impl PluginHost {
async fn load_plugins(
&mut self,
plugin_specifiers: Vec<ModuleSpecifier>,
) -> Result<(), AnyError> {
) -> Result<Vec<PluginInfo>, AnyError> {
let mut load_futures = Vec::with_capacity(plugin_specifiers.len());
for specifier in plugin_specifiers {
let mod_id = self
@ -344,6 +380,8 @@ impl PluginHost {
.run_event_loop(PollEventLoopOptions::default())
.await?;
let mut infos = 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();
@ -358,11 +396,15 @@ impl PluginHost {
let args = &[default_export];
self.logger.log("Installing plugin...");
// TODO(bartlomieju): do it in a try/catch scope
install_plugins_local.call(scope, undefined.into(), args);
self.logger.log("Plugin installed");
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);
}
Ok(())
Ok(infos)
}
}
@ -384,6 +426,8 @@ impl PluginHostProxy {
self
.logger
.error(&format!("load plugins response {:#?}", result));
let infos = result?;
*self.plugin_info.lock() = infos;
return Ok(());
}
Err(custom_error("AlreadyClosed", "Plugin host has closed"))

View file

@ -125,7 +125,7 @@ impl CliLintRule {
#[derive(Debug)]
pub struct ConfiguredRules {
pub all_rule_codes: HashSet<&'static str>,
pub all_rule_codes: HashSet<Cow<'static, str>>,
pub rules: Vec<CliLintRule>,
}
@ -195,7 +195,7 @@ impl LintRuleProvider {
.chain(cli_lint_rules)
.chain(cli_graph_rules)
.inspect(|rule| {
all_rule_names.insert(rule.code());
all_rule_names.insert(rule.code().into());
});
let rules = filtered_rules(
all_rules,