0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-03-04 09:57:11 -05:00

feat: support excluding rules from lint plugins

This commit is contained in:
Marvin Hagemeister 2025-01-03 11:03:09 +01:00
parent 9685d713fc
commit adc25f85a1
9 changed files with 178 additions and 119 deletions

View file

@ -63,6 +63,7 @@ const PropFlags = {
const state = { const state = {
plugins: [], plugins: [],
installedPlugins: new Set(), installedPlugins: new Set(),
ignoredRules: new Set(),
}; };
/** /**
@ -197,8 +198,9 @@ export class Context {
/** /**
* @param {LintPlugin} plugin * @param {LintPlugin} plugin
* @param {string[]} exclude
*/ */
export function installPlugin(plugin) { export function installPlugin(plugin, exclude) {
if (typeof plugin !== "object") { if (typeof plugin !== "object") {
throw new Error("Linter plugin must be an object"); throw new Error("Linter plugin must be an object");
} }
@ -214,6 +216,12 @@ export function installPlugin(plugin) {
state.plugins.push(plugin); state.plugins.push(plugin);
state.installedPlugins.add(plugin.name); state.installedPlugins.add(plugin.name);
// TODO(@marvinhagemeister): This should be done once instead of
// for every plugin
for (let i = 0; i < exclude.length; i++) {
state.ignoredRules.add(exclude[i]);
}
return { return {
name: plugin.name, name: plugin.name,
ruleNames: Object.keys(plugin.rules), ruleNames: Object.keys(plugin.rules),
@ -921,6 +929,12 @@ export function runPluginsForFile(fileName, serializedAst) {
for (const name of Object.keys(plugin.rules)) { for (const name of Object.keys(plugin.rules)) {
const rule = plugin.rules[name]; const rule = plugin.rules[name];
const id = `${plugin.name}/${name}`; const id = `${plugin.name}/${name}`;
// Check if this rule is excluded
if (state.ignoredRules.has(id)) {
continue;
}
const ctx = new Context(id, fileName); const ctx = new Context(id, fileName);
const visitor = rule.create(ctx); const visitor = rule.create(ctx);

View file

@ -70,6 +70,8 @@ export interface LintPlugin {
export interface LintState { export interface LintState {
plugins: LintPlugin[]; plugins: LintPlugin[];
installedPlugins: Set<string>; installedPlugins: Set<string>;
/** format: `<plugin>/<rule>` */
ignoredRules: Set<string>;
} }
export type VisitorFn = (node: unknown) => void; export type VisitorFn = (node: unknown) => void;

View file

@ -1643,6 +1643,7 @@ impl ConfigData {
crate::tools::lint::create_runner_and_load_plugins( crate::tools::lint::create_runner_and_load_plugins(
plugin_specifiers, plugin_specifiers,
logger, logger,
lint_options.rules.exclude.clone(),
) )
.await; .await;
// eprintln!("plugin load result {:#?}", plugin_load_result); // eprintln!("plugin load result {:#?}", plugin_load_result);

View file

@ -1,5 +1,11 @@
{ {
"$schema": "http://json-schema.org/draft-07/schema#", "$schema": "http://json-schema.org/draft-07/schema#",
"oneOf": [
{
"type": "string",
"pattern": "^[a-z0-9-]+\\/[a-z0-9-]+$"
},
{
"enum": [ "enum": [
"adjacent-overload-signatures", "adjacent-overload-signatures",
"ban-ts-comment", "ban-ts-comment",
@ -109,4 +115,6 @@
"valid-typeof", "valid-typeof",
"verbatim-module-syntax" "verbatim-module-syntax"
] ]
}
]
} }

View file

@ -286,6 +286,8 @@ impl WorkspaceLinter {
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
self.file_count += paths.len(); self.file_count += paths.len();
let exclude = lint_options.rules.exclude.clone();
let maybe_plugin_specifiers = lint_options.resolve_lint_plugins()?; let maybe_plugin_specifiers = lint_options.resolve_lint_plugins()?;
let lint_rules = self.lint_rule_provider.resolve_lint_rules_err_empty( let lint_rules = self.lint_rule_provider.resolve_lint_rules_err_empty(
lint_options.rules, lint_options.rules,
@ -311,8 +313,11 @@ impl WorkspaceLinter {
let mut plugin_runner = None; let mut plugin_runner = None;
if let Some(plugin_specifiers) = maybe_plugin_specifiers { if let Some(plugin_specifiers) = maybe_plugin_specifiers {
let logger = plugins::PluginLogger::new(logger_printer, true); let logger = plugins::PluginLogger::new(logger_printer, true);
let runner = let runner = plugins::create_runner_and_load_plugins(
plugins::create_runner_and_load_plugins(plugin_specifiers, logger) plugin_specifiers,
logger,
exclude,
)
.await?; .await?;
plugin_runner = Some(Arc::new(Mutex::new(runner))); plugin_runner = Some(Arc::new(Mutex::new(runner)));
} }

View file

@ -34,7 +34,7 @@ use crate::tools::lint::serialize_ast_to_buffer;
#[derive(Debug)] #[derive(Debug)]
pub enum PluginHostRequest { pub enum PluginHostRequest {
LoadPlugins(Vec<ModuleSpecifier>), LoadPlugins(Vec<ModuleSpecifier>, Option<Vec<String>>),
Run(Vec<u8>, PathBuf, SourceTextInfo), Run(Vec<u8>, PathBuf, SourceTextInfo),
} }
@ -272,8 +272,8 @@ impl PluginHost {
while let Some(req) = self.rx.recv().await { while let Some(req) = self.rx.recv().await {
self.logger.log("received message"); self.logger.log("received message");
match req { match req {
PluginHostRequest::LoadPlugins(specifiers) => { PluginHostRequest::LoadPlugins(specifiers, exclude) => {
let r = self.load_plugins(specifiers).await; let r = self.load_plugins(specifiers, exclude).await;
let _ = self.tx.send(PluginHostResponse::LoadPlugin(r)).await; let _ = self.tx.send(PluginHostResponse::LoadPlugin(r)).await;
} }
PluginHostRequest::Run(serialized_ast, specifier, source_text_info) => { PluginHostRequest::Run(serialized_ast, specifier, source_text_info) => {
@ -361,6 +361,7 @@ impl PluginHost {
async fn load_plugins( async fn load_plugins(
&mut self, &mut self,
plugin_specifiers: Vec<ModuleSpecifier>, plugin_specifiers: Vec<ModuleSpecifier>,
exclude: Option<Vec<String>>,
) -> Result<Vec<PluginInfo>, AnyError> { ) -> Result<Vec<PluginInfo>, AnyError> {
let mut load_futures = Vec::with_capacity(plugin_specifiers.len()); let mut load_futures = Vec::with_capacity(plugin_specifiers.len());
for specifier in plugin_specifiers { for specifier in plugin_specifiers {
@ -393,7 +394,19 @@ impl PluginHost {
let install_plugins_local = let install_plugins_local =
v8::Local::new(scope, &*self.install_plugin_fn.clone()); v8::Local::new(scope, &*self.install_plugin_fn.clone());
let undefined = v8::undefined(scope); let undefined = v8::undefined(scope);
let args = &[default_export];
let exclude_v8: v8::Local<v8::Value> =
exclude.clone().map_or(v8::null(scope).into(), |v| {
let elems = v
.iter()
.map(|item| v8::String::new(scope, item).unwrap().into())
.collect::<Vec<_>>();
v8::Array::new_with_elements(scope, elems.as_slice()).into()
});
let args = &[default_export, exclude_v8];
self.logger.log("Installing plugin..."); self.logger.log("Installing plugin...");
// TODO(bartlomieju): do it in a try/catch scope // TODO(bartlomieju): do it in a try/catch scope
let plugin_info = install_plugins_local let plugin_info = install_plugins_local
@ -412,10 +425,11 @@ impl PluginHostProxy {
pub async fn load_plugins( pub async fn load_plugins(
&self, &self,
plugin_specifiers: Vec<ModuleSpecifier>, plugin_specifiers: Vec<ModuleSpecifier>,
exclude: Option<Vec<String>>,
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
self self
.tx .tx
.send(PluginHostRequest::LoadPlugins(plugin_specifiers)) .send(PluginHostRequest::LoadPlugins(plugin_specifiers, exclude))
.await?; .await?;
let mut rx = self.rx.lock().await; let mut rx = self.rx.lock().await;
self.logger.log("receiving load plugins"); self.logger.log("receiving load plugins");
@ -472,9 +486,10 @@ impl PluginHostProxy {
pub async fn create_runner_and_load_plugins( pub async fn create_runner_and_load_plugins(
plugin_specifiers: Vec<ModuleSpecifier>, plugin_specifiers: Vec<ModuleSpecifier>,
logger: PluginLogger, logger: PluginLogger,
exclude: Option<Vec<String>>,
) -> Result<PluginHostProxy, AnyError> { ) -> Result<PluginHostProxy, AnyError> {
let host_proxy = PluginHost::create(logger)?; let host_proxy = PluginHost::create(logger)?;
host_proxy.load_plugins(plugin_specifiers).await?; host_proxy.load_plugins(plugin_specifiers, exclude).await?;
Ok(host_proxy) Ok(host_proxy)
} }

View file

@ -1,11 +1,14 @@
{ {
"tempDir": true,
"steps": [ "steps": [
{ {
"args": "lint a.ts", "args": "lint a.ts",
"output": "lint.out", "output": "lint.out",
"exitCode": 1 "exitCode": 1
}, },
{
"args": "lint -c deno_exclude.json a.ts",
"output": "lint_exclude.out"
},
{ {
"args": "lint --fix a.ts", "args": "lint --fix a.ts",
"output": "lint_fixed.out" "output": "lint_fixed.out"

View file

@ -0,0 +1,10 @@
{
"lint": {
"plugins": ["./plugin.ts"],
"rules": {
"exclude": [
"test-plugin/my-rule"
]
}
}
}

View file

@ -0,0 +1 @@
Checked 1 file