mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
feat(linter): implement n/handle-callback-err rule (#19616)
this PR implements `n/handle-callback-err` rule, passes all tests from original [rule](https://github.com/eslint-community/eslint-plugin-n/blob/master/tests/lib/rules/handle-callback-err.js) issue #493 --------- Signed-off-by: Mikhail Baev <baev2m@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Cameron Clark <cameron.clark@hey.com>
This commit is contained in:
5 files changed
+453
-1
No files matched your search
@@ -4310,6 +4310,12 @@ impl RuleRunner for crate::rules::node::global_require::GlobalRequire {
|
||||
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
|
||||
}
|
||||
|
||||
impl RuleRunner for crate::rules::node::handle_callback_err::HandleCallbackErr {
|
||||
const NODE_TYPES: Option<&AstTypesBitset> =
|
||||
Some(&AstTypesBitset::from_types(&[AstType::ArrowFunctionExpression, AstType::Function]));
|
||||
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
|
||||
}
|
||||
|
||||
impl RuleRunner for crate::rules::node::no_exports_assign::NoExportsAssign {
|
||||
const NODE_TYPES: Option<&AstTypesBitset> =
|
||||
Some(&AstTypesBitset::from_types(&[AstType::AssignmentExpression]));
|
||||
|
||||
+25
-1
@@ -335,6 +335,7 @@ pub use crate::rules::nextjs::no_title_in_document_head::NoTitleInDocumentHead a
|
||||
pub use crate::rules::nextjs::no_typos::NoTypos as NextjsNoTypos;
|
||||
pub use crate::rules::nextjs::no_unwanted_polyfillio::NoUnwantedPolyfillio as NextjsNoUnwantedPolyfillio;
|
||||
pub use crate::rules::node::global_require::GlobalRequire as NodeGlobalRequire;
|
||||
pub use crate::rules::node::handle_callback_err::HandleCallbackErr as NodeHandleCallbackErr;
|
||||
pub use crate::rules::node::no_exports_assign::NoExportsAssign as NodeNoExportsAssign;
|
||||
pub use crate::rules::node::no_new_require::NoNewRequire as NodeNoNewRequire;
|
||||
pub use crate::rules::node::no_path_concat::NoPathConcat as NodeNoPathConcat;
|
||||
@@ -1396,6 +1397,7 @@ pub enum RuleEnum {
|
||||
),
|
||||
VitestWarnTodo(VitestWarnTodo),
|
||||
NodeGlobalRequire(NodeGlobalRequire),
|
||||
NodeHandleCallbackErr(NodeHandleCallbackErr),
|
||||
NodeNoExportsAssign(NodeNoExportsAssign),
|
||||
NodeNoNewRequire(NodeNoNewRequire),
|
||||
NodeNoPathConcat(NodeNoPathConcat),
|
||||
@@ -2178,7 +2180,8 @@ const VITEST_REQUIRE_LOCAL_TEST_CONTEXT_FOR_CONCURRENT_SNAPSHOTS_ID: usize =
|
||||
const VITEST_WARN_TODO_ID: usize =
|
||||
VITEST_REQUIRE_LOCAL_TEST_CONTEXT_FOR_CONCURRENT_SNAPSHOTS_ID + 1usize;
|
||||
const NODE_GLOBAL_REQUIRE_ID: usize = VITEST_WARN_TODO_ID + 1usize;
|
||||
const NODE_NO_EXPORTS_ASSIGN_ID: usize = NODE_GLOBAL_REQUIRE_ID + 1usize;
|
||||
const NODE_HANDLE_CALLBACK_ERR_ID: usize = NODE_GLOBAL_REQUIRE_ID + 1usize;
|
||||
const NODE_NO_EXPORTS_ASSIGN_ID: usize = NODE_HANDLE_CALLBACK_ERR_ID + 1usize;
|
||||
const NODE_NO_NEW_REQUIRE_ID: usize = NODE_NO_EXPORTS_ASSIGN_ID + 1usize;
|
||||
const NODE_NO_PATH_CONCAT_ID: usize = NODE_NO_NEW_REQUIRE_ID + 1usize;
|
||||
const NODE_NO_PROCESS_ENV_ID: usize = NODE_NO_PATH_CONCAT_ID + 1usize;
|
||||
@@ -2987,6 +2990,7 @@ impl RuleEnum {
|
||||
}
|
||||
Self::VitestWarnTodo(_) => VITEST_WARN_TODO_ID,
|
||||
Self::NodeGlobalRequire(_) => NODE_GLOBAL_REQUIRE_ID,
|
||||
Self::NodeHandleCallbackErr(_) => NODE_HANDLE_CALLBACK_ERR_ID,
|
||||
Self::NodeNoExportsAssign(_) => NODE_NO_EXPORTS_ASSIGN_ID,
|
||||
Self::NodeNoNewRequire(_) => NODE_NO_NEW_REQUIRE_ID,
|
||||
Self::NodeNoPathConcat(_) => NODE_NO_PATH_CONCAT_ID,
|
||||
@@ -3785,6 +3789,7 @@ impl RuleEnum {
|
||||
}
|
||||
Self::VitestWarnTodo(_) => VitestWarnTodo::NAME,
|
||||
Self::NodeGlobalRequire(_) => NodeGlobalRequire::NAME,
|
||||
Self::NodeHandleCallbackErr(_) => NodeHandleCallbackErr::NAME,
|
||||
Self::NodeNoExportsAssign(_) => NodeNoExportsAssign::NAME,
|
||||
Self::NodeNoNewRequire(_) => NodeNoNewRequire::NAME,
|
||||
Self::NodeNoPathConcat(_) => NodeNoPathConcat::NAME,
|
||||
@@ -4627,6 +4632,7 @@ impl RuleEnum {
|
||||
}
|
||||
Self::VitestWarnTodo(_) => VitestWarnTodo::CATEGORY,
|
||||
Self::NodeGlobalRequire(_) => NodeGlobalRequire::CATEGORY,
|
||||
Self::NodeHandleCallbackErr(_) => NodeHandleCallbackErr::CATEGORY,
|
||||
Self::NodeNoExportsAssign(_) => NodeNoExportsAssign::CATEGORY,
|
||||
Self::NodeNoNewRequire(_) => NodeNoNewRequire::CATEGORY,
|
||||
Self::NodeNoPathConcat(_) => NodeNoPathConcat::CATEGORY,
|
||||
@@ -5428,6 +5434,7 @@ impl RuleEnum {
|
||||
}
|
||||
Self::VitestWarnTodo(_) => VitestWarnTodo::FIX,
|
||||
Self::NodeGlobalRequire(_) => NodeGlobalRequire::FIX,
|
||||
Self::NodeHandleCallbackErr(_) => NodeHandleCallbackErr::FIX,
|
||||
Self::NodeNoExportsAssign(_) => NodeNoExportsAssign::FIX,
|
||||
Self::NodeNoNewRequire(_) => NodeNoNewRequire::FIX,
|
||||
Self::NodeNoPathConcat(_) => NodeNoPathConcat::FIX,
|
||||
@@ -6423,6 +6430,7 @@ impl RuleEnum {
|
||||
}
|
||||
Self::VitestWarnTodo(_) => VitestWarnTodo::documentation(),
|
||||
Self::NodeGlobalRequire(_) => NodeGlobalRequire::documentation(),
|
||||
Self::NodeHandleCallbackErr(_) => NodeHandleCallbackErr::documentation(),
|
||||
Self::NodeNoExportsAssign(_) => NodeNoExportsAssign::documentation(),
|
||||
Self::NodeNoNewRequire(_) => NodeNoNewRequire::documentation(),
|
||||
Self::NodeNoPathConcat(_) => NodeNoPathConcat::documentation(),
|
||||
@@ -8372,6 +8380,8 @@ impl RuleEnum {
|
||||
.or_else(|| VitestWarnTodo::schema(generator)),
|
||||
Self::NodeGlobalRequire(_) => NodeGlobalRequire::config_schema(generator)
|
||||
.or_else(|| NodeGlobalRequire::schema(generator)),
|
||||
Self::NodeHandleCallbackErr(_) => NodeHandleCallbackErr::config_schema(generator)
|
||||
.or_else(|| NodeHandleCallbackErr::schema(generator)),
|
||||
Self::NodeNoExportsAssign(_) => NodeNoExportsAssign::config_schema(generator)
|
||||
.or_else(|| NodeNoExportsAssign::schema(generator)),
|
||||
Self::NodeNoNewRequire(_) => NodeNoNewRequire::config_schema(generator)
|
||||
@@ -9112,6 +9122,7 @@ impl RuleEnum {
|
||||
Self::VitestRequireLocalTestContextForConcurrentSnapshots(_) => "vitest",
|
||||
Self::VitestWarnTodo(_) => "vitest",
|
||||
Self::NodeGlobalRequire(_) => "node",
|
||||
Self::NodeHandleCallbackErr(_) => "node",
|
||||
Self::NodeNoExportsAssign(_) => "node",
|
||||
Self::NodeNoNewRequire(_) => "node",
|
||||
Self::NodeNoPathConcat(_) => "node",
|
||||
@@ -11315,6 +11326,9 @@ impl RuleEnum {
|
||||
Self::NodeGlobalRequire(_) => {
|
||||
Ok(Self::NodeGlobalRequire(NodeGlobalRequire::from_configuration(value)?))
|
||||
}
|
||||
Self::NodeHandleCallbackErr(_) => {
|
||||
Ok(Self::NodeHandleCallbackErr(NodeHandleCallbackErr::from_configuration(value)?))
|
||||
}
|
||||
Self::NodeNoExportsAssign(_) => {
|
||||
Ok(Self::NodeNoExportsAssign(NodeNoExportsAssign::from_configuration(value)?))
|
||||
}
|
||||
@@ -12063,6 +12077,7 @@ impl RuleEnum {
|
||||
}
|
||||
Self::VitestWarnTodo(rule) => rule.to_configuration(),
|
||||
Self::NodeGlobalRequire(rule) => rule.to_configuration(),
|
||||
Self::NodeHandleCallbackErr(rule) => rule.to_configuration(),
|
||||
Self::NodeNoExportsAssign(rule) => rule.to_configuration(),
|
||||
Self::NodeNoNewRequire(rule) => rule.to_configuration(),
|
||||
Self::NodeNoPathConcat(rule) => rule.to_configuration(),
|
||||
@@ -12765,6 +12780,7 @@ impl RuleEnum {
|
||||
Self::VitestRequireLocalTestContextForConcurrentSnapshots(rule) => rule.run(node, ctx),
|
||||
Self::VitestWarnTodo(rule) => rule.run(node, ctx),
|
||||
Self::NodeGlobalRequire(rule) => rule.run(node, ctx),
|
||||
Self::NodeHandleCallbackErr(rule) => rule.run(node, ctx),
|
||||
Self::NodeNoExportsAssign(rule) => rule.run(node, ctx),
|
||||
Self::NodeNoNewRequire(rule) => rule.run(node, ctx),
|
||||
Self::NodeNoPathConcat(rule) => rule.run(node, ctx),
|
||||
@@ -13467,6 +13483,7 @@ impl RuleEnum {
|
||||
Self::VitestRequireLocalTestContextForConcurrentSnapshots(rule) => rule.run_once(ctx),
|
||||
Self::VitestWarnTodo(rule) => rule.run_once(ctx),
|
||||
Self::NodeGlobalRequire(rule) => rule.run_once(ctx),
|
||||
Self::NodeHandleCallbackErr(rule) => rule.run_once(ctx),
|
||||
Self::NodeNoExportsAssign(rule) => rule.run_once(ctx),
|
||||
Self::NodeNoNewRequire(rule) => rule.run_once(ctx),
|
||||
Self::NodeNoPathConcat(rule) => rule.run_once(ctx),
|
||||
@@ -14269,6 +14286,7 @@ impl RuleEnum {
|
||||
}
|
||||
Self::VitestWarnTodo(rule) => rule.run_on_jest_node(jest_node, ctx),
|
||||
Self::NodeGlobalRequire(rule) => rule.run_on_jest_node(jest_node, ctx),
|
||||
Self::NodeHandleCallbackErr(rule) => rule.run_on_jest_node(jest_node, ctx),
|
||||
Self::NodeNoExportsAssign(rule) => rule.run_on_jest_node(jest_node, ctx),
|
||||
Self::NodeNoNewRequire(rule) => rule.run_on_jest_node(jest_node, ctx),
|
||||
Self::NodeNoPathConcat(rule) => rule.run_on_jest_node(jest_node, ctx),
|
||||
@@ -14971,6 +14989,7 @@ impl RuleEnum {
|
||||
Self::VitestRequireLocalTestContextForConcurrentSnapshots(rule) => rule.should_run(ctx),
|
||||
Self::VitestWarnTodo(rule) => rule.should_run(ctx),
|
||||
Self::NodeGlobalRequire(rule) => rule.should_run(ctx),
|
||||
Self::NodeHandleCallbackErr(rule) => rule.should_run(ctx),
|
||||
Self::NodeNoExportsAssign(rule) => rule.should_run(ctx),
|
||||
Self::NodeNoNewRequire(rule) => rule.should_run(ctx),
|
||||
Self::NodeNoPathConcat(rule) => rule.should_run(ctx),
|
||||
@@ -15965,6 +15984,7 @@ impl RuleEnum {
|
||||
}
|
||||
Self::VitestWarnTodo(_) => VitestWarnTodo::IS_TSGOLINT_RULE,
|
||||
Self::NodeGlobalRequire(_) => NodeGlobalRequire::IS_TSGOLINT_RULE,
|
||||
Self::NodeHandleCallbackErr(_) => NodeHandleCallbackErr::IS_TSGOLINT_RULE,
|
||||
Self::NodeNoExportsAssign(_) => NodeNoExportsAssign::IS_TSGOLINT_RULE,
|
||||
Self::NodeNoNewRequire(_) => NodeNoNewRequire::IS_TSGOLINT_RULE,
|
||||
Self::NodeNoPathConcat(_) => NodeNoPathConcat::IS_TSGOLINT_RULE,
|
||||
@@ -16836,6 +16856,7 @@ impl RuleEnum {
|
||||
}
|
||||
Self::VitestWarnTodo(_) => VitestWarnTodo::HAS_CONFIG,
|
||||
Self::NodeGlobalRequire(_) => NodeGlobalRequire::HAS_CONFIG,
|
||||
Self::NodeHandleCallbackErr(_) => NodeHandleCallbackErr::HAS_CONFIG,
|
||||
Self::NodeNoExportsAssign(_) => NodeNoExportsAssign::HAS_CONFIG,
|
||||
Self::NodeNoNewRequire(_) => NodeNoNewRequire::HAS_CONFIG,
|
||||
Self::NodeNoPathConcat(_) => NodeNoPathConcat::HAS_CONFIG,
|
||||
@@ -17540,6 +17561,7 @@ impl RuleEnum {
|
||||
Self::VitestRequireLocalTestContextForConcurrentSnapshots(rule) => rule.types_info(),
|
||||
Self::VitestWarnTodo(rule) => rule.types_info(),
|
||||
Self::NodeGlobalRequire(rule) => rule.types_info(),
|
||||
Self::NodeHandleCallbackErr(rule) => rule.types_info(),
|
||||
Self::NodeNoExportsAssign(rule) => rule.types_info(),
|
||||
Self::NodeNoNewRequire(rule) => rule.types_info(),
|
||||
Self::NodeNoPathConcat(rule) => rule.types_info(),
|
||||
@@ -18242,6 +18264,7 @@ impl RuleEnum {
|
||||
Self::VitestRequireLocalTestContextForConcurrentSnapshots(rule) => rule.run_info(),
|
||||
Self::VitestWarnTodo(rule) => rule.run_info(),
|
||||
Self::NodeGlobalRequire(rule) => rule.run_info(),
|
||||
Self::NodeHandleCallbackErr(rule) => rule.run_info(),
|
||||
Self::NodeNoExportsAssign(rule) => rule.run_info(),
|
||||
Self::NodeNoNewRequire(rule) => rule.run_info(),
|
||||
Self::NodeNoPathConcat(rule) => rule.run_info(),
|
||||
@@ -19062,6 +19085,7 @@ pub static RULES: std::sync::LazyLock<Vec<RuleEnum>> = std::sync::LazyLock::new(
|
||||
),
|
||||
RuleEnum::VitestWarnTodo(VitestWarnTodo::default()),
|
||||
RuleEnum::NodeGlobalRequire(NodeGlobalRequire::default()),
|
||||
RuleEnum::NodeHandleCallbackErr(NodeHandleCallbackErr::default()),
|
||||
RuleEnum::NodeNoExportsAssign(NodeNoExportsAssign::default()),
|
||||
RuleEnum::NodeNoNewRequire(NodeNoNewRequire::default()),
|
||||
RuleEnum::NodeNoPathConcat(NodeNoPathConcat::default()),
|
||||
|
||||
@@ -722,6 +722,7 @@ pub(crate) mod vitest {
|
||||
|
||||
pub(crate) mod node {
|
||||
pub mod global_require;
|
||||
pub mod handle_callback_err;
|
||||
pub mod no_exports_assign;
|
||||
pub mod no_new_require;
|
||||
pub mod no_path_concat;
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use lazy_regex::Regex;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use oxc_ast::{AstKind, ast::FormalParameters};
|
||||
use oxc_diagnostics::OxcDiagnostic;
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{
|
||||
AstNode,
|
||||
context::LintContext,
|
||||
rule::{DefaultRuleConfig, Rule},
|
||||
};
|
||||
|
||||
fn handle_callback_err_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Expected error to be handled.")
|
||||
.with_help("Handle the error or rename the parameter if it's not an error.")
|
||||
.with_label(span)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, JsonSchema)]
|
||||
enum ErrorPattern {
|
||||
Plain(String),
|
||||
Regex(Regex),
|
||||
}
|
||||
|
||||
impl Default for ErrorPattern {
|
||||
fn default() -> Self {
|
||||
Self::Plain("err".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl ErrorPattern {
|
||||
fn matches(&self, name: &str) -> bool {
|
||||
match self {
|
||||
Self::Plain(s) => name == s,
|
||||
Self::Regex(r) => r.is_match(name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_error_pattern<'de, D>(deserializer: D) -> Result<Box<ErrorPattern>, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let s = <Cow<str>>::deserialize(deserializer)?;
|
||||
|
||||
let pattern = {
|
||||
if s.starts_with('^') {
|
||||
Regex::new(&s).map_or_else(|_| ErrorPattern::Plain(s.to_string()), ErrorPattern::Regex)
|
||||
} else {
|
||||
ErrorPattern::Plain(s.to_string())
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Box::new(pattern))
|
||||
}
|
||||
|
||||
/// The rule takes a single string option: the name of the error parameter.
|
||||
///
|
||||
/// This can be either:
|
||||
/// - an exact name (e.g. `"err"`, `"error"`)
|
||||
/// - a regexp pattern (e.g. `"^(err|error)$"`)
|
||||
///
|
||||
/// If the configured name of the error variable begins with a `^` it is considered to be a regexp pattern.
|
||||
///
|
||||
/// Default: `"err"`.
|
||||
#[derive(Debug, Clone, Default, JsonSchema, Deserialize)]
|
||||
#[serde(rename_all = "camelCase", default)]
|
||||
pub struct HandleCallbackErrConfig(String);
|
||||
|
||||
#[derive(Debug, Default, Clone, JsonSchema, Deserialize)]
|
||||
pub struct HandleCallbackErr(
|
||||
#[serde(deserialize_with = "deserialize_error_pattern")] Box<ErrorPattern>,
|
||||
);
|
||||
|
||||
declare_oxc_lint!(
|
||||
/// ### What it does
|
||||
///
|
||||
/// This rule expects that when you're using the callback pattern in Node.js you'll handle the error.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
///
|
||||
/// In Node.js, a common pattern for dealing with asynchronous behavior is called the callback pattern.
|
||||
/// This pattern expects an `Error` object or `null` as the first argument of the callback.
|
||||
/// Forgetting to handle these errors can lead to some really strange behavior in your application.
|
||||
///
|
||||
/// ```js
|
||||
/// function loadData (err, data) {
|
||||
/// doSomething(); // forgot to handle error
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ### Examples
|
||||
///
|
||||
/// Examples of **incorrect** code for this rule with the default `"err"` parameter name:
|
||||
/// ```js
|
||||
/// function loadData (err, data) {
|
||||
/// doSomething();
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Examples of **correct** code for this rule with the default `"err"` parameter name:
|
||||
/// ```js
|
||||
/// function loadData (err, data) {
|
||||
/// if (err) {
|
||||
/// console.log(err.stack);
|
||||
/// }
|
||||
/// doSomething();
|
||||
/// }
|
||||
///
|
||||
/// function generateError (err) {
|
||||
/// if (err) {}
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Examples of correct code for this rule with a sample `"error"` parameter name:
|
||||
///```js
|
||||
/// function loadData (error, data) {
|
||||
/// if (error) {
|
||||
/// console.log(error.stack);
|
||||
/// }
|
||||
/// doSomething();
|
||||
/// }
|
||||
///```
|
||||
HandleCallbackErr,
|
||||
node,
|
||||
restriction,
|
||||
config = HandleCallbackErrConfig,
|
||||
);
|
||||
|
||||
impl Rule for HandleCallbackErr {
|
||||
fn from_configuration(value: serde_json::Value) -> Result<Self, serde_json::error::Error> {
|
||||
serde_json::from_value::<DefaultRuleConfig<Self>>(value).map(DefaultRuleConfig::into_inner)
|
||||
}
|
||||
|
||||
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
|
||||
match node.kind() {
|
||||
AstKind::Function(func) => {
|
||||
self.check_for_error(&func.params, ctx);
|
||||
}
|
||||
AstKind::ArrowFunctionExpression(arrow_func) => {
|
||||
self.check_for_error(&arrow_func.params, ctx);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HandleCallbackErr {
|
||||
fn check_for_error(&self, params: &FormalParameters, ctx: &LintContext) {
|
||||
if let Some(first_param) = params.items.first()
|
||||
&& let Some(ident) = first_param.pattern.get_binding_identifier()
|
||||
&& self.0.matches(&ident.name)
|
||||
&& ctx.symbol_references(ident.symbol_id()).count() == 0
|
||||
{
|
||||
ctx.diagnostic(handle_callback_err_diagnostic(ident.span));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
use crate::tester::Tester;
|
||||
|
||||
let pass = vec![
|
||||
("function test(error) {}", None),
|
||||
("function test(err) {console.log(err);}", None),
|
||||
("function test(err, data) {if(err){ data = 'ERROR';}}", None),
|
||||
("var test = function(err) {console.log(err);};", None),
|
||||
("var test = function(err) {if(err){/* do nothing */}};", None),
|
||||
("var test = function(err) {if(!err){doSomethingHere();}else{};}", None),
|
||||
("var test = function(err, data) {if(!err) { good(); } else { bad(); }}", None),
|
||||
("try { } catch(err) {}", None),
|
||||
(
|
||||
"getData(function(err, data) {if (err) {}getMoreDataWith(data, function(err, moreData) {if (err) {}getEvenMoreDataWith(moreData, function(err, allOfTheThings) {if (err) {}});});});",
|
||||
None,
|
||||
),
|
||||
("var test = function(err) {if(! err){doSomethingHere();}};", None),
|
||||
(
|
||||
"function test(err, data) {if (data) {doSomething(function(err) {console.error(err);});} else if (err) {console.log(err);}}",
|
||||
None,
|
||||
),
|
||||
(
|
||||
"function handler(err, data) {if (data) {doSomethingWith(data);} else if (err) {console.log(err);}}",
|
||||
None,
|
||||
),
|
||||
(
|
||||
"function handler(err) {logThisAction(function(err) {if (err) {}}); console.log(err);}",
|
||||
None,
|
||||
),
|
||||
("function userHandler(err) {process.nextTick(function() {if (err) {}})}", None),
|
||||
(
|
||||
"function help() { function userHandler(err) {function tester() { err; process.nextTick(function() { err; }); } } }",
|
||||
None,
|
||||
),
|
||||
("function help(done) { var err = new Error('error'); done(); }", None),
|
||||
("var test = err => err;", None),
|
||||
("var test = err => !err;", None),
|
||||
("var test = err => err.message;", None),
|
||||
(
|
||||
"var test = function(error) {if(error){/* do nothing */}};",
|
||||
Some(serde_json::json!(["error"])),
|
||||
),
|
||||
(
|
||||
"var test = (error) => {if(error){/* do nothing */}};",
|
||||
Some(serde_json::json!(["error"])),
|
||||
),
|
||||
(
|
||||
"var test = function(error) {if(! error){doSomethingHere();}};",
|
||||
Some(serde_json::json!(["error"])),
|
||||
),
|
||||
(
|
||||
"var test = function(err) { console.log(err); };",
|
||||
Some(serde_json::json!(["^(err|error)$"])),
|
||||
),
|
||||
(
|
||||
"var test = function(error) { console.log(error); };",
|
||||
Some(serde_json::json!(["^(err|error)$"])),
|
||||
),
|
||||
(
|
||||
"var test = function(anyError) { console.log(anyError); };",
|
||||
Some(serde_json::json!(["^.+Error$"])),
|
||||
),
|
||||
(
|
||||
"var test = function(any_error) { console.log(anyError); };",
|
||||
Some(serde_json::json!(["^.+Error$"])),
|
||||
),
|
||||
(
|
||||
"var test = function(any_error) { console.log(any_error); };",
|
||||
Some(serde_json::json!(["^.+(e|E)rror$"])), // spellchecker:disable-line
|
||||
),
|
||||
];
|
||||
|
||||
let fail = vec![
|
||||
("function test(err) {}", None),
|
||||
("function test(err, data) {}", None),
|
||||
("function test(err) {errorLookingWord();}", None),
|
||||
("function test(err) {try{} catch(err) {}}", None),
|
||||
("function test(err, callback) { foo(function(err, callback) {}); }", None),
|
||||
("var test = (err) => {};", None),
|
||||
("var test = function(err) {};", None),
|
||||
("var test = function test(err, data) {};", None),
|
||||
("var test = function test(err) {/* if(err){} */};", None),
|
||||
("function test(err) {doSomethingHere(function(err){console.log(err);})}", None),
|
||||
("function test(error) {}", Some(serde_json::json!(["error"]))),
|
||||
(
|
||||
"getData(function(err, data) {getMoreDataWith(data, function(err, moreData) {if (err) {}getEvenMoreDataWith(moreData, function(err, allOfTheThings) {if (err) {}});}); });",
|
||||
None,
|
||||
),
|
||||
(
|
||||
"getData(function(err, data) {getMoreDataWith(data, function(err, moreData) {getEvenMoreDataWith(moreData, function(err, allOfTheThings) {if (err) {}});}); });",
|
||||
None,
|
||||
),
|
||||
(
|
||||
"function userHandler(err) {logThisAction(function(err) {if (err) { console.log(err); } })}",
|
||||
None,
|
||||
),
|
||||
(
|
||||
"function help() { function userHandler(err) {function tester(err) { err; process.nextTick(function() { err; }); } } }",
|
||||
None,
|
||||
),
|
||||
(
|
||||
"var test = function(anyError) { console.log(otherError); };",
|
||||
Some(serde_json::json!(["^.+Error$"])),
|
||||
),
|
||||
("var test = function(anyError) { };", Some(serde_json::json!(["^.+Error$"]))),
|
||||
(
|
||||
"var test = function(err) { console.log(error); };",
|
||||
Some(serde_json::json!(["^(err|error)$"])),
|
||||
),
|
||||
];
|
||||
|
||||
Tester::new(HandleCallbackErr::NAME, HandleCallbackErr::PLUGIN, pass, fail).test_and_snapshot();
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
---
|
||||
source: crates/oxc_linter/src/tester.rs
|
||||
---
|
||||
|
||||
⚠ eslint-plugin-node(handle-callback-err): Expected error to be handled.
|
||||
╭─[handle_callback_err.tsx:1:15]
|
||||
1 │ function test(err) {}
|
||||
· ───
|
||||
╰────
|
||||
help: Handle the error or rename the parameter if it's not an error.
|
||||
|
||||
⚠ eslint-plugin-node(handle-callback-err): Expected error to be handled.
|
||||
╭─[handle_callback_err.tsx:1:15]
|
||||
1 │ function test(err, data) {}
|
||||
· ───
|
||||
╰────
|
||||
help: Handle the error or rename the parameter if it's not an error.
|
||||
|
||||
⚠ eslint-plugin-node(handle-callback-err): Expected error to be handled.
|
||||
╭─[handle_callback_err.tsx:1:15]
|
||||
1 │ function test(err) {errorLookingWord();}
|
||||
· ───
|
||||
╰────
|
||||
help: Handle the error or rename the parameter if it's not an error.
|
||||
|
||||
⚠ eslint-plugin-node(handle-callback-err): Expected error to be handled.
|
||||
╭─[handle_callback_err.tsx:1:15]
|
||||
1 │ function test(err) {try{} catch(err) {}}
|
||||
· ───
|
||||
╰────
|
||||
help: Handle the error or rename the parameter if it's not an error.
|
||||
|
||||
⚠ eslint-plugin-node(handle-callback-err): Expected error to be handled.
|
||||
╭─[handle_callback_err.tsx:1:15]
|
||||
1 │ function test(err, callback) { foo(function(err, callback) {}); }
|
||||
· ───
|
||||
╰────
|
||||
help: Handle the error or rename the parameter if it's not an error.
|
||||
|
||||
⚠ eslint-plugin-node(handle-callback-err): Expected error to be handled.
|
||||
╭─[handle_callback_err.tsx:1:45]
|
||||
1 │ function test(err, callback) { foo(function(err, callback) {}); }
|
||||
· ───
|
||||
╰────
|
||||
help: Handle the error or rename the parameter if it's not an error.
|
||||
|
||||
⚠ eslint-plugin-node(handle-callback-err): Expected error to be handled.
|
||||
╭─[handle_callback_err.tsx:1:13]
|
||||
1 │ var test = (err) => {};
|
||||
· ───
|
||||
╰────
|
||||
help: Handle the error or rename the parameter if it's not an error.
|
||||
|
||||
⚠ eslint-plugin-node(handle-callback-err): Expected error to be handled.
|
||||
╭─[handle_callback_err.tsx:1:21]
|
||||
1 │ var test = function(err) {};
|
||||
· ───
|
||||
╰────
|
||||
help: Handle the error or rename the parameter if it's not an error.
|
||||
|
||||
⚠ eslint-plugin-node(handle-callback-err): Expected error to be handled.
|
||||
╭─[handle_callback_err.tsx:1:26]
|
||||
1 │ var test = function test(err, data) {};
|
||||
· ───
|
||||
╰────
|
||||
help: Handle the error or rename the parameter if it's not an error.
|
||||
|
||||
⚠ eslint-plugin-node(handle-callback-err): Expected error to be handled.
|
||||
╭─[handle_callback_err.tsx:1:26]
|
||||
1 │ var test = function test(err) {/* if(err){} */};
|
||||
· ───
|
||||
╰────
|
||||
help: Handle the error or rename the parameter if it's not an error.
|
||||
|
||||
⚠ eslint-plugin-node(handle-callback-err): Expected error to be handled.
|
||||
╭─[handle_callback_err.tsx:1:15]
|
||||
1 │ function test(err) {doSomethingHere(function(err){console.log(err);})}
|
||||
· ───
|
||||
╰────
|
||||
help: Handle the error or rename the parameter if it's not an error.
|
||||
|
||||
⚠ eslint-plugin-node(handle-callback-err): Expected error to be handled.
|
||||
╭─[handle_callback_err.tsx:1:15]
|
||||
1 │ function test(error) {}
|
||||
· ─────
|
||||
╰────
|
||||
help: Handle the error or rename the parameter if it's not an error.
|
||||
|
||||
⚠ eslint-plugin-node(handle-callback-err): Expected error to be handled.
|
||||
╭─[handle_callback_err.tsx:1:18]
|
||||
1 │ getData(function(err, data) {getMoreDataWith(data, function(err, moreData) {if (err) {}getEvenMoreDataWith(moreData, function(err, allOfTheThings) {if (err) {}});}); });
|
||||
· ───
|
||||
╰────
|
||||
help: Handle the error or rename the parameter if it's not an error.
|
||||
|
||||
⚠ eslint-plugin-node(handle-callback-err): Expected error to be handled.
|
||||
╭─[handle_callback_err.tsx:1:18]
|
||||
1 │ getData(function(err, data) {getMoreDataWith(data, function(err, moreData) {getEvenMoreDataWith(moreData, function(err, allOfTheThings) {if (err) {}});}); });
|
||||
· ───
|
||||
╰────
|
||||
help: Handle the error or rename the parameter if it's not an error.
|
||||
|
||||
⚠ eslint-plugin-node(handle-callback-err): Expected error to be handled.
|
||||
╭─[handle_callback_err.tsx:1:61]
|
||||
1 │ getData(function(err, data) {getMoreDataWith(data, function(err, moreData) {getEvenMoreDataWith(moreData, function(err, allOfTheThings) {if (err) {}});}); });
|
||||
· ───
|
||||
╰────
|
||||
help: Handle the error or rename the parameter if it's not an error.
|
||||
|
||||
⚠ eslint-plugin-node(handle-callback-err): Expected error to be handled.
|
||||
╭─[handle_callback_err.tsx:1:22]
|
||||
1 │ function userHandler(err) {logThisAction(function(err) {if (err) { console.log(err); } })}
|
||||
· ───
|
||||
╰────
|
||||
help: Handle the error or rename the parameter if it's not an error.
|
||||
|
||||
⚠ eslint-plugin-node(handle-callback-err): Expected error to be handled.
|
||||
╭─[handle_callback_err.tsx:1:40]
|
||||
1 │ function help() { function userHandler(err) {function tester(err) { err; process.nextTick(function() { err; }); } } }
|
||||
· ───
|
||||
╰────
|
||||
help: Handle the error or rename the parameter if it's not an error.
|
||||
|
||||
⚠ eslint-plugin-node(handle-callback-err): Expected error to be handled.
|
||||
╭─[handle_callback_err.tsx:1:21]
|
||||
1 │ var test = function(anyError) { console.log(otherError); };
|
||||
· ────────
|
||||
╰────
|
||||
help: Handle the error or rename the parameter if it's not an error.
|
||||
|
||||
⚠ eslint-plugin-node(handle-callback-err): Expected error to be handled.
|
||||
╭─[handle_callback_err.tsx:1:21]
|
||||
1 │ var test = function(anyError) { };
|
||||
· ────────
|
||||
╰────
|
||||
help: Handle the error or rename the parameter if it's not an error.
|
||||
|
||||
⚠ eslint-plugin-node(handle-callback-err): Expected error to be handled.
|
||||
╭─[handle_callback_err.tsx:1:21]
|
||||
1 │ var test = function(err) { console.log(error); };
|
||||
· ───
|
||||
╰────
|
||||
help: Handle the error or rename the parameter if it's not an error.
|
||||
Reference in new issue
Block a user