mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
feat(linter/n): implement callback-return rule (#22470)
this PR implements `callback-return` rule, passes all upstream tests. issue #493 there is an issue with config doc generation for array with default values. Ill fix it a little later and then move the PR out of draft. --------- Co-authored-by: Cameron Clark <cameron.clark@hey.com>
This commit is contained in:
1 parent
65a77f1a5f
commit
5fa47746a3
8 files changed
+730
-1
No files matched your search
@@ -836,6 +836,7 @@ export interface DummyRuleMap {
|
||||
"no-void"?: DummyRule;
|
||||
"no-warning-comments"?: DummyRule;
|
||||
"no-with"?: DummyRule;
|
||||
"node/callback-return"?: DummyRule;
|
||||
"node/global-require"?: DummyRule;
|
||||
"node/handle-callback-err"?: DummyRule;
|
||||
"node/no-exports-assign"?: DummyRule;
|
||||
|
||||
@@ -4875,6 +4875,12 @@ impl RuleRunner for crate::rules::vitest::warn_todo::WarnTodo {
|
||||
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::RunOnJestNode;
|
||||
}
|
||||
|
||||
impl RuleRunner for crate::rules::node::callback_return::CallbackReturn {
|
||||
const NODE_TYPES: Option<&AstTypesBitset> =
|
||||
Some(&AstTypesBitset::from_types(&[AstType::CallExpression]));
|
||||
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
|
||||
}
|
||||
|
||||
impl RuleRunner for crate::rules::node::global_require::GlobalRequire {
|
||||
const NODE_TYPES: Option<&AstTypesBitset> =
|
||||
Some(&AstTypesBitset::from_types(&[AstType::CallExpression]));
|
||||
|
||||
+29
-1
@@ -362,6 +362,7 @@ pub use crate::rules::nextjs::no_sync_scripts::NoSyncScripts as NextjsNoSyncScri
|
||||
pub use crate::rules::nextjs::no_title_in_document_head::NoTitleInDocumentHead as NextjsNoTitleInDocumentHead;
|
||||
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::callback_return::CallbackReturn as NodeCallbackReturn;
|
||||
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;
|
||||
@@ -1599,6 +1600,7 @@ pub enum RuleEnum {
|
||||
VitestValidExpectInPromise(VitestValidExpectInPromise),
|
||||
VitestValidTitle(VitestValidTitle),
|
||||
VitestWarnTodo(VitestWarnTodo),
|
||||
NodeCallbackReturn(NodeCallbackReturn),
|
||||
NodeGlobalRequire(NodeGlobalRequire),
|
||||
NodeHandleCallbackErr(NodeHandleCallbackErr),
|
||||
NodeNoExportsAssign(NodeNoExportsAssign),
|
||||
@@ -2499,7 +2501,8 @@ const VITEST_VALID_EXPECT_ID: usize = VITEST_VALID_DESCRIBE_CALLBACK_ID + 1usize
|
||||
const VITEST_VALID_EXPECT_IN_PROMISE_ID: usize = VITEST_VALID_EXPECT_ID + 1usize;
|
||||
const VITEST_VALID_TITLE_ID: usize = VITEST_VALID_EXPECT_IN_PROMISE_ID + 1usize;
|
||||
const VITEST_WARN_TODO_ID: usize = VITEST_VALID_TITLE_ID + 1usize;
|
||||
const NODE_GLOBAL_REQUIRE_ID: usize = VITEST_WARN_TODO_ID + 1usize;
|
||||
const NODE_CALLBACK_RETURN_ID: usize = VITEST_WARN_TODO_ID + 1usize;
|
||||
const NODE_GLOBAL_REQUIRE_ID: usize = NODE_CALLBACK_RETURN_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;
|
||||
@@ -3430,6 +3433,7 @@ impl RuleEnum {
|
||||
Self::VitestValidExpectInPromise(_) => VITEST_VALID_EXPECT_IN_PROMISE_ID,
|
||||
Self::VitestValidTitle(_) => VITEST_VALID_TITLE_ID,
|
||||
Self::VitestWarnTodo(_) => VITEST_WARN_TODO_ID,
|
||||
Self::NodeCallbackReturn(_) => NODE_CALLBACK_RETURN_ID,
|
||||
Self::NodeGlobalRequire(_) => NODE_GLOBAL_REQUIRE_ID,
|
||||
Self::NodeHandleCallbackErr(_) => NODE_HANDLE_CALLBACK_ERR_ID,
|
||||
Self::NodeNoExportsAssign(_) => NODE_NO_EXPORTS_ASSIGN_ID,
|
||||
@@ -4345,6 +4349,7 @@ impl RuleEnum {
|
||||
Self::VitestValidExpectInPromise(_) => VitestValidExpectInPromise::NAME,
|
||||
Self::VitestValidTitle(_) => VitestValidTitle::NAME,
|
||||
Self::VitestWarnTodo(_) => VitestWarnTodo::NAME,
|
||||
Self::NodeCallbackReturn(_) => NodeCallbackReturn::NAME,
|
||||
Self::NodeGlobalRequire(_) => NodeGlobalRequire::NAME,
|
||||
Self::NodeHandleCallbackErr(_) => NodeHandleCallbackErr::NAME,
|
||||
Self::NodeNoExportsAssign(_) => NodeNoExportsAssign::NAME,
|
||||
@@ -5316,6 +5321,7 @@ impl RuleEnum {
|
||||
Self::VitestValidExpectInPromise(_) => VitestValidExpectInPromise::CATEGORY,
|
||||
Self::VitestValidTitle(_) => VitestValidTitle::CATEGORY,
|
||||
Self::VitestWarnTodo(_) => VitestWarnTodo::CATEGORY,
|
||||
Self::NodeCallbackReturn(_) => NodeCallbackReturn::CATEGORY,
|
||||
Self::NodeGlobalRequire(_) => NodeGlobalRequire::CATEGORY,
|
||||
Self::NodeHandleCallbackErr(_) => NodeHandleCallbackErr::CATEGORY,
|
||||
Self::NodeNoExportsAssign(_) => NodeNoExportsAssign::CATEGORY,
|
||||
@@ -6234,6 +6240,7 @@ impl RuleEnum {
|
||||
Self::VitestValidExpectInPromise(_) => VitestValidExpectInPromise::FIX,
|
||||
Self::VitestValidTitle(_) => VitestValidTitle::FIX,
|
||||
Self::VitestWarnTodo(_) => VitestWarnTodo::FIX,
|
||||
Self::NodeCallbackReturn(_) => NodeCallbackReturn::FIX,
|
||||
Self::NodeGlobalRequire(_) => NodeGlobalRequire::FIX,
|
||||
Self::NodeHandleCallbackErr(_) => NodeHandleCallbackErr::FIX,
|
||||
Self::NodeNoExportsAssign(_) => NodeNoExportsAssign::FIX,
|
||||
@@ -7392,6 +7399,7 @@ impl RuleEnum {
|
||||
Self::VitestValidExpectInPromise(_) => VitestValidExpectInPromise::documentation(),
|
||||
Self::VitestValidTitle(_) => VitestValidTitle::documentation(),
|
||||
Self::VitestWarnTodo(_) => VitestWarnTodo::documentation(),
|
||||
Self::NodeCallbackReturn(_) => NodeCallbackReturn::documentation(),
|
||||
Self::NodeGlobalRequire(_) => NodeGlobalRequire::documentation(),
|
||||
Self::NodeHandleCallbackErr(_) => NodeHandleCallbackErr::documentation(),
|
||||
Self::NodeNoExportsAssign(_) => NodeNoExportsAssign::documentation(),
|
||||
@@ -9655,6 +9663,8 @@ impl RuleEnum {
|
||||
.or_else(|| VitestValidTitle::schema(generator)),
|
||||
Self::VitestWarnTodo(_) => VitestWarnTodo::config_schema(generator)
|
||||
.or_else(|| VitestWarnTodo::schema(generator)),
|
||||
Self::NodeCallbackReturn(_) => NodeCallbackReturn::config_schema(generator)
|
||||
.or_else(|| NodeCallbackReturn::schema(generator)),
|
||||
Self::NodeGlobalRequire(_) => NodeGlobalRequire::config_schema(generator)
|
||||
.or_else(|| NodeGlobalRequire::schema(generator)),
|
||||
Self::NodeHandleCallbackErr(_) => NodeHandleCallbackErr::config_schema(generator)
|
||||
@@ -10514,6 +10524,7 @@ impl RuleEnum {
|
||||
Self::VitestValidExpectInPromise(_) => "vitest",
|
||||
Self::VitestValidTitle(_) => "vitest",
|
||||
Self::VitestWarnTodo(_) => "vitest",
|
||||
Self::NodeCallbackReturn(_) => "node",
|
||||
Self::NodeGlobalRequire(_) => "node",
|
||||
Self::NodeHandleCallbackErr(_) => "node",
|
||||
Self::NodeNoExportsAssign(_) => "node",
|
||||
@@ -13042,6 +13053,9 @@ impl RuleEnum {
|
||||
Self::VitestWarnTodo(_) => {
|
||||
Ok(Self::VitestWarnTodo(VitestWarnTodo::from_configuration(value)?))
|
||||
}
|
||||
Self::NodeCallbackReturn(_) => {
|
||||
Ok(Self::NodeCallbackReturn(NodeCallbackReturn::from_configuration(value)?))
|
||||
}
|
||||
Self::NodeGlobalRequire(_) => {
|
||||
Ok(Self::NodeGlobalRequire(NodeGlobalRequire::from_configuration(value)?))
|
||||
}
|
||||
@@ -13913,6 +13927,7 @@ impl RuleEnum {
|
||||
Self::VitestValidExpectInPromise(rule) => rule.to_configuration(),
|
||||
Self::VitestValidTitle(rule) => rule.to_configuration(),
|
||||
Self::VitestWarnTodo(rule) => rule.to_configuration(),
|
||||
Self::NodeCallbackReturn(rule) => rule.to_configuration(),
|
||||
Self::NodeGlobalRequire(rule) => rule.to_configuration(),
|
||||
Self::NodeHandleCallbackErr(rule) => rule.to_configuration(),
|
||||
Self::NodeNoExportsAssign(rule) => rule.to_configuration(),
|
||||
@@ -14728,6 +14743,7 @@ impl RuleEnum {
|
||||
Self::VitestValidExpectInPromise(rule) => rule.run(node, ctx),
|
||||
Self::VitestValidTitle(rule) => rule.run(node, ctx),
|
||||
Self::VitestWarnTodo(rule) => rule.run(node, ctx),
|
||||
Self::NodeCallbackReturn(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),
|
||||
@@ -15536,6 +15552,7 @@ impl RuleEnum {
|
||||
Self::VitestValidExpectInPromise(rule) => rule.run(node, ctx),
|
||||
Self::VitestValidTitle(rule) => rule.run(node, ctx),
|
||||
Self::VitestWarnTodo(rule) => rule.run(node, ctx),
|
||||
Self::NodeCallbackReturn(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),
|
||||
@@ -16351,6 +16368,7 @@ impl RuleEnum {
|
||||
Self::VitestValidExpectInPromise(rule) => rule.run_once(ctx),
|
||||
Self::VitestValidTitle(rule) => rule.run_once(ctx),
|
||||
Self::VitestWarnTodo(rule) => rule.run_once(ctx),
|
||||
Self::NodeCallbackReturn(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),
|
||||
@@ -17159,6 +17177,7 @@ impl RuleEnum {
|
||||
Self::VitestValidExpectInPromise(rule) => rule.run_once(ctx),
|
||||
Self::VitestValidTitle(rule) => rule.run_once(ctx),
|
||||
Self::VitestWarnTodo(rule) => rule.run_once(ctx),
|
||||
Self::NodeCallbackReturn(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),
|
||||
@@ -18221,6 +18240,7 @@ impl RuleEnum {
|
||||
Self::VitestValidExpectInPromise(rule) => rule.run_on_jest_node(jest_node, ctx),
|
||||
Self::VitestValidTitle(rule) => rule.run_on_jest_node(jest_node, ctx),
|
||||
Self::VitestWarnTodo(rule) => rule.run_on_jest_node(jest_node, ctx),
|
||||
Self::NodeCallbackReturn(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),
|
||||
@@ -19281,6 +19301,7 @@ impl RuleEnum {
|
||||
Self::VitestValidExpectInPromise(rule) => rule.run_on_jest_node(jest_node, ctx),
|
||||
Self::VitestValidTitle(rule) => rule.run_on_jest_node(jest_node, ctx),
|
||||
Self::VitestWarnTodo(rule) => rule.run_on_jest_node(jest_node, ctx),
|
||||
Self::NodeCallbackReturn(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),
|
||||
@@ -20093,6 +20114,7 @@ impl RuleEnum {
|
||||
Self::VitestValidExpectInPromise(rule) => rule.should_run(ctx),
|
||||
Self::VitestValidTitle(rule) => rule.should_run(ctx),
|
||||
Self::VitestWarnTodo(rule) => rule.should_run(ctx),
|
||||
Self::NodeCallbackReturn(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),
|
||||
@@ -21248,6 +21270,7 @@ impl RuleEnum {
|
||||
Self::VitestValidExpectInPromise(_) => VitestValidExpectInPromise::IS_TSGOLINT_RULE,
|
||||
Self::VitestValidTitle(_) => VitestValidTitle::IS_TSGOLINT_RULE,
|
||||
Self::VitestWarnTodo(_) => VitestWarnTodo::IS_TSGOLINT_RULE,
|
||||
Self::NodeCallbackReturn(_) => NodeCallbackReturn::IS_TSGOLINT_RULE,
|
||||
Self::NodeGlobalRequire(_) => NodeGlobalRequire::IS_TSGOLINT_RULE,
|
||||
Self::NodeHandleCallbackErr(_) => NodeHandleCallbackErr::IS_TSGOLINT_RULE,
|
||||
Self::NodeNoExportsAssign(_) => NodeNoExportsAssign::IS_TSGOLINT_RULE,
|
||||
@@ -22227,6 +22250,7 @@ impl RuleEnum {
|
||||
Self::VitestValidExpectInPromise(_) => VitestValidExpectInPromise::VERSION,
|
||||
Self::VitestValidTitle(_) => VitestValidTitle::VERSION,
|
||||
Self::VitestWarnTodo(_) => VitestWarnTodo::VERSION,
|
||||
Self::NodeCallbackReturn(_) => NodeCallbackReturn::VERSION,
|
||||
Self::NodeGlobalRequire(_) => NodeGlobalRequire::VERSION,
|
||||
Self::NodeHandleCallbackErr(_) => NodeHandleCallbackErr::VERSION,
|
||||
Self::NodeNoExportsAssign(_) => NodeNoExportsAssign::VERSION,
|
||||
@@ -23235,6 +23259,7 @@ impl RuleEnum {
|
||||
Self::VitestValidExpectInPromise(_) => VitestValidExpectInPromise::HAS_CONFIG,
|
||||
Self::VitestValidTitle(_) => VitestValidTitle::HAS_CONFIG,
|
||||
Self::VitestWarnTodo(_) => VitestWarnTodo::HAS_CONFIG,
|
||||
Self::NodeCallbackReturn(_) => NodeCallbackReturn::HAS_CONFIG,
|
||||
Self::NodeGlobalRequire(_) => NodeGlobalRequire::HAS_CONFIG,
|
||||
Self::NodeHandleCallbackErr(_) => NodeHandleCallbackErr::HAS_CONFIG,
|
||||
Self::NodeNoExportsAssign(_) => NodeNoExportsAssign::HAS_CONFIG,
|
||||
@@ -24046,6 +24071,7 @@ impl RuleEnum {
|
||||
Self::VitestValidExpectInPromise(rule) => rule.types_info(),
|
||||
Self::VitestValidTitle(rule) => rule.types_info(),
|
||||
Self::VitestWarnTodo(rule) => rule.types_info(),
|
||||
Self::NodeCallbackReturn(rule) => rule.types_info(),
|
||||
Self::NodeGlobalRequire(rule) => rule.types_info(),
|
||||
Self::NodeHandleCallbackErr(rule) => rule.types_info(),
|
||||
Self::NodeNoExportsAssign(rule) => rule.types_info(),
|
||||
@@ -24851,6 +24877,7 @@ impl RuleEnum {
|
||||
Self::VitestValidExpectInPromise(rule) => rule.run_info(),
|
||||
Self::VitestValidTitle(rule) => rule.run_info(),
|
||||
Self::VitestWarnTodo(rule) => rule.run_info(),
|
||||
Self::NodeCallbackReturn(rule) => rule.run_info(),
|
||||
Self::NodeGlobalRequire(rule) => rule.run_info(),
|
||||
Self::NodeHandleCallbackErr(rule) => rule.run_info(),
|
||||
Self::NodeNoExportsAssign(rule) => rule.run_info(),
|
||||
@@ -25786,6 +25813,7 @@ pub static RULES: std::sync::LazyLock<Vec<RuleEnum>> = std::sync::LazyLock::new(
|
||||
RuleEnum::VitestValidExpectInPromise(VitestValidExpectInPromise::default()),
|
||||
RuleEnum::VitestValidTitle(VitestValidTitle::default()),
|
||||
RuleEnum::VitestWarnTodo(VitestWarnTodo::default()),
|
||||
RuleEnum::NodeCallbackReturn(NodeCallbackReturn::default()),
|
||||
RuleEnum::NodeGlobalRequire(NodeGlobalRequire::default()),
|
||||
RuleEnum::NodeHandleCallbackErr(NodeHandleCallbackErr::default()),
|
||||
RuleEnum::NodeNoExportsAssign(NodeNoExportsAssign::default()),
|
||||
|
||||
@@ -817,6 +817,7 @@ pub(crate) mod vitest {
|
||||
}
|
||||
|
||||
pub(crate) mod node {
|
||||
pub mod callback_return;
|
||||
pub mod global_require;
|
||||
pub mod handle_callback_err;
|
||||
pub mod no_exports_assign;
|
||||
|
||||
@@ -0,0 +1,461 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use oxc_ast::{
|
||||
AstKind,
|
||||
ast::{CallExpression, Expression, Statement},
|
||||
};
|
||||
use oxc_diagnostics::OxcDiagnostic;
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::{GetSpan, Span};
|
||||
use oxc_str::CompactStr;
|
||||
|
||||
use crate::{
|
||||
AstNode,
|
||||
context::LintContext,
|
||||
rule::{DefaultRuleConfig, Rule},
|
||||
};
|
||||
|
||||
fn callback_return_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Expected return with your callback function.")
|
||||
.with_help("Return the callback call or add an explicit return immediately after it.")
|
||||
.with_label(span)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, JsonSchema, Deserialize)]
|
||||
/// The rule takes a single option - an array of possible callback names - which may include object methods. The default callback names are `callback`, `cb`, `next`.
|
||||
pub struct CallbackReturn(Box<CallbackNames>);
|
||||
|
||||
#[derive(Debug, Clone, JsonSchema, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
struct CallbackNames(Vec<CompactStr>);
|
||||
|
||||
impl Default for CallbackReturn {
|
||||
fn default() -> Self {
|
||||
Self(Box::new(CallbackNames(vec!["callback".into(), "cb".into(), "next".into()])))
|
||||
}
|
||||
}
|
||||
|
||||
declare_oxc_lint!(
|
||||
/// ### What it does
|
||||
///
|
||||
/// Require `return` statements after callbacks.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
///
|
||||
/// This rule is aimed at ensuring that callbacks used outside of the main function block are always part-of or immediately preceding a `return` statement.
|
||||
/// This rule decides what is a callback based on the name of the function being called.
|
||||
///
|
||||
/// ### Examples
|
||||
///
|
||||
/// Examples of **incorrect** code for this rule:
|
||||
/// ```js
|
||||
/// function done(err) {
|
||||
/// if (err) {
|
||||
/// callback(err);
|
||||
/// }
|
||||
/// callback();
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Examples of **correct** code for this rule:
|
||||
/// ```js
|
||||
/// function done(err) {
|
||||
/// if (err) {
|
||||
/// return callback(err);
|
||||
/// }
|
||||
/// callback();
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ### Known Limitations
|
||||
///
|
||||
/// Because it is difficult to understand the meaning of a program through static analysis, this rule has limitations:
|
||||
///
|
||||
/// - *false negatives* when this rule reports correct code, but the program calls the callback more than one time (which is incorrect behavior)
|
||||
/// - *false positives* when this rule reports incorrect code, but the program calls the callback only one time (which is correct behavior)
|
||||
///
|
||||
/// #### Passing the callback by reference
|
||||
///
|
||||
/// The static analysis of this rule does not detect that the program calls the callback if it is an argument of a function (for example, `setTimeout`).
|
||||
///
|
||||
/// Example of a *false negative* when this rule reports correct code:
|
||||
///
|
||||
/// ```js
|
||||
/// function foo(err, callback) {
|
||||
/// if (err) {
|
||||
/// setTimeout(callback, 0); // this is bad, but WILL NOT warn
|
||||
/// }
|
||||
/// callback();
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// #### Triggering the callback within a nested function
|
||||
///
|
||||
/// The static analysis of this rule does not detect that the program calls the callback from within a nested function or an immediately-invoked function expression (IIFE).
|
||||
///
|
||||
/// Example of a *false negative* when this rule reports correct code:
|
||||
///
|
||||
/// ```js
|
||||
/// function foo(err, callback) {
|
||||
/// if (err) {
|
||||
/// process.nextTick(function() {
|
||||
/// return callback(); // this is bad, but WILL NOT warn
|
||||
/// });
|
||||
/// }
|
||||
/// callback();
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// #### If/else statements
|
||||
///
|
||||
/// The static analysis of this rule does not detect that the program calls the callback only one time in each branch of an `if` statement.
|
||||
///
|
||||
/// Example of a *false positive* when this rule reports incorrect code:
|
||||
///
|
||||
/// ```js
|
||||
/// function foo(err, callback) {
|
||||
/// if (err) {
|
||||
/// callback(err); // this is fine, but WILL warn
|
||||
/// } else {
|
||||
/// callback(); // this is fine, but WILL warn
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
CallbackReturn,
|
||||
node,
|
||||
style,
|
||||
version = "next",
|
||||
config = CallbackReturn,
|
||||
);
|
||||
|
||||
impl Rule for CallbackReturn {
|
||||
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>) {
|
||||
let AstKind::CallExpression(call_expr) = node.kind() else {
|
||||
return;
|
||||
};
|
||||
|
||||
if !self.is_callback(call_expr, ctx.source_text()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(closest_block) = find_closest_block_parent(node, ctx) else {
|
||||
return;
|
||||
};
|
||||
|
||||
if matches!(
|
||||
closest_block.kind(),
|
||||
AstKind::ReturnStatement(_) | AstKind::ArrowFunctionExpression(_)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
let block_body = match closest_block.kind() {
|
||||
AstKind::BlockStatement(block_stmt) => block_stmt.body.as_slice(),
|
||||
AstKind::FunctionBody(function_body) => function_body.statements.as_slice(),
|
||||
_ => &[],
|
||||
};
|
||||
|
||||
if let Some(last_item) = block_body.last() {
|
||||
if is_callback_expression(call_expr, last_item)
|
||||
&& is_function_like(&ctx.nodes().parent_node(closest_block.id()).kind())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if matches!(last_item, Statement::ReturnStatement(_))
|
||||
&& block_body
|
||||
.get(block_body.len().saturating_sub(2))
|
||||
.is_some_and(|previous_item| is_callback_expression(call_expr, previous_item))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if find_closest_function_parent(node, ctx).is_some() {
|
||||
ctx.diagnostic(callback_return_diagnostic(call_expr.span));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CallbackReturn {
|
||||
fn is_callback(&self, call_expr: &CallExpression, source_text: &str) -> bool {
|
||||
contains_only_identifiers(&call_expr.callee)
|
||||
&& self.0.0.iter().any(|callback| {
|
||||
// compare by source text instead of `callee_name()` to handle cases like `obj.method(err)` with config `["obj.method"]`
|
||||
callback.as_str() == call_expr.callee.span().source_text(source_text)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn contains_only_identifiers(expr: &Expression) -> bool {
|
||||
if let Expression::Identifier(_) = expr {
|
||||
return true;
|
||||
}
|
||||
|
||||
if let Some(member_expr) = &expr.as_member_expression() {
|
||||
if matches!(member_expr.object(), Expression::Identifier(_)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if let Some(obj_member_expr) = member_expr.object().as_member_expression() {
|
||||
return contains_only_identifiers(obj_member_expr.object());
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn find_closest_block_parent<'a, 'b>(
|
||||
ast_node: &AstNode<'a>,
|
||||
ctx: &'b LintContext<'a>,
|
||||
) -> Option<&'b AstNode<'a>> {
|
||||
ctx.nodes().ancestors(ast_node.id()).find(|parent| {
|
||||
matches!(
|
||||
parent.kind(),
|
||||
AstKind::BlockStatement(_)
|
||||
| AstKind::FunctionBody(_)
|
||||
| AstKind::ReturnStatement(_)
|
||||
| AstKind::ArrowFunctionExpression(_)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn find_closest_function_parent<'a, 'b>(
|
||||
ast_node: &AstNode<'a>,
|
||||
ctx: &'b LintContext<'a>,
|
||||
) -> Option<&'b AstNode<'a>> {
|
||||
ctx.nodes().ancestors(ast_node.id()).find(|parent| is_function_like(&parent.kind()))
|
||||
}
|
||||
|
||||
fn is_function_like(kind: &AstKind) -> bool {
|
||||
matches!(kind, AstKind::Function(_) | AstKind::ArrowFunctionExpression(_))
|
||||
}
|
||||
|
||||
fn is_callback_expression(call_expr: &CallExpression, parent_node: &Statement) -> bool {
|
||||
let Statement::ExpressionStatement(expr_stmt) = parent_node else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if expr_stmt.expression.without_parentheses().span() == call_expr.span {
|
||||
return true;
|
||||
}
|
||||
|
||||
match expr_stmt.expression.without_parentheses() {
|
||||
Expression::BinaryExpression(binary_expr) => {
|
||||
binary_expr.right.without_parentheses().span() == call_expr.span
|
||||
}
|
||||
Expression::LogicalExpression(logical_expr) => {
|
||||
logical_expr.right.without_parentheses().span() == call_expr.span
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
use crate::tester::Tester;
|
||||
|
||||
let pass = vec![
|
||||
("function a(err) { if (err) return callback (err); }", None),
|
||||
("function a(err) { if (err) return callback (err); callback(); }", None),
|
||||
("function a(err) { if (err) { return callback (err); } callback(); }", None),
|
||||
(
|
||||
"function a(err) { if (err) { return /* confusing comment */ callback (err); } callback(); }",
|
||||
None,
|
||||
),
|
||||
("function x(err) { if (err) { callback(); return; } }", None),
|
||||
(
|
||||
"function x(err) { if (err) {
|
||||
log();
|
||||
callback(); return; } }",
|
||||
None,
|
||||
),
|
||||
("function x(err) { if (err) { callback(); return; } return callback(); }", None),
|
||||
("function x(err) { if (err) { return callback(); } else { return callback(); } }", None),
|
||||
(
|
||||
"function x(err) { if (err) { return callback(); } else if (x) { return callback(); } }",
|
||||
None,
|
||||
),
|
||||
("function x(err) { if (err) return callback(); else return callback(); }", None),
|
||||
("function x(cb) { cb && cb(); }", None),
|
||||
("function x(next) { typeof next !== 'undefined' && next(); }", None),
|
||||
("function x(next) { if (typeof next === 'function') { return next() } }", None),
|
||||
("function x() { switch(x) { case 'a': return next(); } }", None),
|
||||
("function x() { for(x = 0; x < 10; x++) { return next(); } }", None),
|
||||
("function x() { while(x) { return next(); } }", None),
|
||||
("function a(err) { if (err) { obj.method (err); } }", None),
|
||||
("callback()", None),
|
||||
("callback(); callback();", None),
|
||||
("while(x) { move(); }", None),
|
||||
("for (var i = 0; i < 10; i++) { move(); }", None),
|
||||
("for (var i = 0; i < 10; i++) move();", None),
|
||||
("if (x) callback();", None),
|
||||
("if (x) { callback(); }", None),
|
||||
("var x = err => { if (err) { callback(); return; } }", None),
|
||||
("var x = err => callback(err)", None),
|
||||
("var x = err => { setTimeout( () => { callback(); }); }", None),
|
||||
("class x { horse() { callback(); } } ", None),
|
||||
("class x { horse() { if (err) { return callback(); } callback(); } } ", None),
|
||||
("function a(err) { if (err) { callback(err) } }", Some(serde_json::json!([["cb"]]))),
|
||||
(
|
||||
"function a(err) { if (err) { callback(err) } next(); }",
|
||||
Some(serde_json::json!([["cb", "next"]])),
|
||||
),
|
||||
(
|
||||
"function a(err) { if (err) { return next(err) } else { callback(); } }",
|
||||
Some(serde_json::json!([["cb", "next"]])),
|
||||
),
|
||||
(
|
||||
"function a(err) { if (err) { return obj.method(err); } }",
|
||||
Some(serde_json::json!([["obj.method"]])),
|
||||
),
|
||||
(
|
||||
"function a(err) { if (err) { return obj.prop.method(err); } }",
|
||||
Some(serde_json::json!([["obj.prop.method"]])),
|
||||
),
|
||||
(
|
||||
"function a(err) { if (err) { return obj.prop.method(err); } otherObj.prop.method() }",
|
||||
Some(serde_json::json!([["obj.prop.method", "otherObj.prop.method"]])),
|
||||
),
|
||||
(
|
||||
"function a(err) { if (err) { callback(err); } }",
|
||||
Some(serde_json::json!([["obj.method"]])),
|
||||
),
|
||||
(
|
||||
"function a(err) { if (err) { otherObj.method(err); } }",
|
||||
Some(serde_json::json!([["obj.method"]])),
|
||||
),
|
||||
(
|
||||
"function a(err) { if (err) { //comment
|
||||
return obj.method(err); } }",
|
||||
Some(serde_json::json!([["obj.method"]])),
|
||||
),
|
||||
(
|
||||
"function a(err) { if (err) { /*comment*/return obj.method(err); } }",
|
||||
Some(serde_json::json!([["obj.method"]])),
|
||||
),
|
||||
(
|
||||
"function a(err) { if (err) { return obj.method(err); //comment
|
||||
} }",
|
||||
Some(serde_json::json!([["obj.method"]])),
|
||||
),
|
||||
(
|
||||
"function a(err) { if (err) { return obj.method(err); /*comment*/ } }",
|
||||
Some(serde_json::json!([["obj.method"]])),
|
||||
),
|
||||
(
|
||||
"function a(err) { if (err) { obj().method(err); } }",
|
||||
Some(serde_json::json!([["obj().method"]])),
|
||||
),
|
||||
(
|
||||
"function a(err) { if (err) { obj.prop().method(err); } }",
|
||||
Some(serde_json::json!([["obj.prop().method"]])),
|
||||
),
|
||||
(
|
||||
"function a(err) { if (err) { obj().prop.method(err); } }",
|
||||
Some(serde_json::json!([["obj().prop.method"]])),
|
||||
),
|
||||
(
|
||||
"function a(err) { if (err) { obj().method(err); } }",
|
||||
Some(serde_json::json!([["obj.method"]])),
|
||||
),
|
||||
(
|
||||
"function a(err) { if (err) { obj().method(err); } obj.method(); }",
|
||||
Some(serde_json::json!([["obj.method"]])),
|
||||
),
|
||||
("function x(err) { if (err) { setTimeout(callback, 0); } callback(); }", None),
|
||||
(
|
||||
"function x(err) { if (err) { process.nextTick(function(err) { callback(); }); } callback(); }",
|
||||
None,
|
||||
),
|
||||
("function a(err) { (callback(err)); }", None),
|
||||
("function x(err) { if (err) { (callback()); return; } }", None),
|
||||
];
|
||||
|
||||
let fail = vec![
|
||||
("function a(err) { if (err) { callback (err); } }", None),
|
||||
("function a(callback) { if (typeof callback !== 'undefined') { callback(); } }", None),
|
||||
("function a(callback) { if (typeof callback !== 'undefined') callback(); }", None),
|
||||
("function a(callback) { if (err) { callback(); horse && horse(); } }", None),
|
||||
("var x = (err) => { if (err) { callback (err); } }", None),
|
||||
("var x = { x(err) { if (err) { callback (err); } } }", None),
|
||||
(
|
||||
"function x(err) { if (err) {
|
||||
log();
|
||||
callback(err); } }",
|
||||
None,
|
||||
),
|
||||
("var x = { x(err) { if (err) { callback && callback (err); } } }", None),
|
||||
("function a(err) { callback (err); callback(); }", None),
|
||||
("function a(err) { callback (err); horse(); }", None),
|
||||
("function a(err) { if (err) { callback (err); horse(); return; } }", None),
|
||||
("var a = (err) => { callback (err); callback(); }", None),
|
||||
(
|
||||
"function a(err) { if (err) { callback (err); } else if (x) { callback(err); return; } }",
|
||||
None,
|
||||
),
|
||||
(
|
||||
"function x(err) { if (err) { return callback(); }
|
||||
else if (abc) {
|
||||
callback(); }
|
||||
else {
|
||||
return callback(); } }",
|
||||
None,
|
||||
),
|
||||
("class x { horse() { if (err) { callback(); } callback(); } } ", None),
|
||||
("function x(err) { if (err) { callback() } else { callback() } }", None),
|
||||
("function x(err) { if (err) return callback(); else callback(); }", None),
|
||||
("() => { if (x) { callback(); } }", None),
|
||||
("function b() { switch(x) { case 'horse': callback(); } }", None),
|
||||
(
|
||||
"function a() { switch(x) { case 'horse': move(); } }",
|
||||
Some(serde_json::json!([["move"]])),
|
||||
),
|
||||
("var x = function() { while(x) { move(); } }", Some(serde_json::json!([["move"]]))),
|
||||
(
|
||||
"function x() { for (var i = 0; i < 10; i++) { move(); } }",
|
||||
Some(serde_json::json!([["move"]])),
|
||||
),
|
||||
(
|
||||
"var x = function() { for (var i = 0; i < 10; i++) move(); }",
|
||||
Some(serde_json::json!([["move"]])),
|
||||
),
|
||||
(
|
||||
"function a(err) { if (err) { obj.method(err); } }",
|
||||
Some(serde_json::json!([["obj.method"]])),
|
||||
),
|
||||
(
|
||||
"function a(err) { if (err) { obj.prop.method(err); } }",
|
||||
Some(serde_json::json!([["obj.prop.method"]])),
|
||||
),
|
||||
(
|
||||
"function a(err) { if (err) { obj.prop.method(err); } otherObj.prop.method() }",
|
||||
Some(serde_json::json!([["obj.prop.method", "otherObj.prop.method"]])),
|
||||
),
|
||||
(
|
||||
"function a(err) { if (err) { /*comment*/obj.method(err); } }",
|
||||
Some(serde_json::json!([["obj.method"]])),
|
||||
),
|
||||
(
|
||||
"function a(err) { if (err) { //comment
|
||||
obj.method(err); } }",
|
||||
Some(serde_json::json!([["obj.method"]])),
|
||||
),
|
||||
(
|
||||
"function a(err) { if (err) { obj.method(err); /*comment*/ } }",
|
||||
Some(serde_json::json!([["obj.method"]])),
|
||||
),
|
||||
(
|
||||
"function a(err) { if (err) { obj.method(err); //comment
|
||||
} }",
|
||||
Some(serde_json::json!([["obj.method"]])),
|
||||
),
|
||||
];
|
||||
|
||||
Tester::new(CallbackReturn::NAME, CallbackReturn::PLUGIN, pass, fail).test_and_snapshot();
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
---
|
||||
source: crates/oxc_linter/src/tester.rs
|
||||
assertion_line: 490
|
||||
---
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:30]
|
||||
1 │ function a(err) { if (err) { callback (err); } }
|
||||
· ──────────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:63]
|
||||
1 │ function a(callback) { if (typeof callback !== 'undefined') { callback(); } }
|
||||
· ──────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:61]
|
||||
1 │ function a(callback) { if (typeof callback !== 'undefined') callback(); }
|
||||
· ──────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:35]
|
||||
1 │ function a(callback) { if (err) { callback(); horse && horse(); } }
|
||||
· ──────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:31]
|
||||
1 │ var x = (err) => { if (err) { callback (err); } }
|
||||
· ──────────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:31]
|
||||
1 │ var x = { x(err) { if (err) { callback (err); } } }
|
||||
· ──────────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:3:14]
|
||||
2 │ log();
|
||||
3 │ callback(err); } }
|
||||
· ─────────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:43]
|
||||
1 │ var x = { x(err) { if (err) { callback && callback (err); } } }
|
||||
· ──────────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:19]
|
||||
1 │ function a(err) { callback (err); callback(); }
|
||||
· ──────────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:19]
|
||||
1 │ function a(err) { callback (err); horse(); }
|
||||
· ──────────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:30]
|
||||
1 │ function a(err) { if (err) { callback (err); horse(); return; } }
|
||||
· ──────────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:20]
|
||||
1 │ var a = (err) => { callback (err); callback(); }
|
||||
· ──────────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:30]
|
||||
1 │ function a(err) { if (err) { callback (err); } else if (x) { callback(err); return; } }
|
||||
· ──────────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:3:13]
|
||||
2 │ else if (abc) {
|
||||
3 │ callback(); }
|
||||
· ──────────
|
||||
4 │ else {
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:32]
|
||||
1 │ class x { horse() { if (err) { callback(); } callback(); } }
|
||||
· ──────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:30]
|
||||
1 │ function x(err) { if (err) { callback() } else { callback() } }
|
||||
· ──────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:50]
|
||||
1 │ function x(err) { if (err) { callback() } else { callback() } }
|
||||
· ──────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:52]
|
||||
1 │ function x(err) { if (err) return callback(); else callback(); }
|
||||
· ──────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:18]
|
||||
1 │ () => { if (x) { callback(); } }
|
||||
· ──────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:42]
|
||||
1 │ function b() { switch(x) { case 'horse': callback(); } }
|
||||
· ──────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:42]
|
||||
1 │ function a() { switch(x) { case 'horse': move(); } }
|
||||
· ──────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:33]
|
||||
1 │ var x = function() { while(x) { move(); } }
|
||||
· ──────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:47]
|
||||
1 │ function x() { for (var i = 0; i < 10; i++) { move(); } }
|
||||
· ──────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:51]
|
||||
1 │ var x = function() { for (var i = 0; i < 10; i++) move(); }
|
||||
· ──────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:30]
|
||||
1 │ function a(err) { if (err) { obj.method(err); } }
|
||||
· ───────────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:30]
|
||||
1 │ function a(err) { if (err) { obj.prop.method(err); } }
|
||||
· ────────────────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:30]
|
||||
1 │ function a(err) { if (err) { obj.prop.method(err); } otherObj.prop.method() }
|
||||
· ────────────────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:41]
|
||||
1 │ function a(err) { if (err) { /*comment*/obj.method(err); } }
|
||||
· ───────────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:2:13]
|
||||
1 │ function a(err) { if (err) { //comment
|
||||
2 │ obj.method(err); } }
|
||||
· ───────────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:30]
|
||||
1 │ function a(err) { if (err) { obj.method(err); /*comment*/ } }
|
||||
· ───────────────
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
|
||||
⚠ node(callback-return): Expected return with your callback function.
|
||||
╭─[callback_return.tsx:1:30]
|
||||
1 │ function a(err) { if (err) { obj.method(err); //comment
|
||||
· ───────────────
|
||||
2 │ } }
|
||||
╰────
|
||||
help: Return the callback call or add an explicit return immediately after it.
|
||||
@@ -1219,6 +1219,9 @@
|
||||
"no-with": {
|
||||
"$ref": "#/definitions/DummyRule"
|
||||
},
|
||||
"node/callback-return": {
|
||||
"$ref": "#/definitions/DummyRule"
|
||||
},
|
||||
"node/global-require": {
|
||||
"$ref": "#/definitions/DummyRule"
|
||||
},
|
||||
|
||||
@@ -1223,6 +1223,9 @@ expression: json
|
||||
"no-with": {
|
||||
"$ref": "#/definitions/DummyRule"
|
||||
},
|
||||
"node/callback-return": {
|
||||
"$ref": "#/definitions/DummyRule"
|
||||
},
|
||||
"node/global-require": {
|
||||
"$ref": "#/definitions/DummyRule"
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user