Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 16 additions & 31 deletions crates/oxc_linter/src/rules/unicorn/throw_new_error.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
use lazy_regex::{Lazy, Regex, lazy_regex};
use oxc_ast::{
AstKind,
ast::{Expression, match_member_expression},
};
use oxc_ast::{AstKind, ast::Expression};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
Expand All @@ -16,7 +12,7 @@ use crate::{

fn throw_new_error_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Require `new` when throwing an error.")
.with_help("While it's possible to create a new error without using the `new` keyword, it's better to be explicit.")
.with_help("Using `new` ensures the error is correctly initialized.")
.with_label(span)
}

Expand All @@ -26,11 +22,14 @@ pub struct ThrowNewError;
declare_oxc_lint!(
/// ### What it does
///
/// Require `new` when throwing an error.`
/// This rule makes sure you always use `new` when throwing an error.
///
/// ### Why is this bad?
///
/// While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
/// In JavaScript, omitting `new` (e.g., `throw Error('message')`) is allowed,
/// but it does not properly initialize the error object. This can lead to missing
/// stack traces or incorrect prototype chains. Using `new` makes the intent clear,
/// ensures consistent behavior, and helps avoid subtle bugs.
///
/// ### Examples
///
Expand All @@ -53,8 +52,6 @@ declare_oxc_lint!(
fix
);

static CUSTOM_ERROR_REGEX_PATTERN: Lazy<Regex> = lazy_regex!(r"^(?:[A-Z][\da-z]*)*Error$");

impl Rule for ThrowNewError {
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
let AstKind::CallExpression(call_expr) = node.kind() else {
Expand All @@ -69,29 +66,17 @@ impl Rule for ThrowNewError {
return;
};

match call_expr.callee.without_parentheses() {
Expression::Identifier(v) => {
if !CUSTOM_ERROR_REGEX_PATTERN.is_match(&v.name) {
return;
}
}
callee @ match_member_expression!(Expression) => {
let member_expr = callee.to_member_expression();
if member_expr.is_computed() {
return;
}
if let Some(v) = member_expr.static_property_name() {
if !CUSTOM_ERROR_REGEX_PATTERN.is_match(v) {
return;
}
}
}
let name = match call_expr.callee.without_parentheses() {
Expression::Identifier(v) => v.name,
Expression::StaticMemberExpression(v) => v.property.name,
_ => return,
}
};

ctx.diagnostic_with_fix(throw_new_error_diagnostic(call_expr.span), |fixer| {
fixer.insert_text_before_range(call_expr.span, "new ")
});
if name.len() >= 5 && name.as_bytes()[0].is_ascii_uppercase() && name.ends_with("Error") {
ctx.diagnostic_with_fix(throw_new_error_diagnostic(call_expr.span), |fixer| {
fixer.insert_text_before_range(call_expr.span, "new ")
});
}
}
}

Expand Down
44 changes: 22 additions & 22 deletions crates/oxc_linter/src/snapshots/unicorn_throw_new_error.snap
Original file line number Diff line number Diff line change
Expand Up @@ -6,151 +6,151 @@ source: crates/oxc_linter/src/tester.rs
1 │ throw Error()
· ───────
╰────
help: While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
help: Using `new` ensures the error is correctly initialized.

⚠ eslint-plugin-unicorn(throw-new-error): Require `new` when throwing an error.
╭─[throw_new_error.tsx:1:7]
1 │ throw (Error)()
· ─────────
╰────
help: While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
help: Using `new` ensures the error is correctly initialized.

⚠ eslint-plugin-unicorn(throw-new-error): Require `new` when throwing an error.
╭─[throw_new_error.tsx:1:7]
1 │ throw lib.Error()
· ───────────
╰────
help: While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
help: Using `new` ensures the error is correctly initialized.

⚠ eslint-plugin-unicorn(throw-new-error): Require `new` when throwing an error.
╭─[throw_new_error.tsx:1:7]
1 │ throw lib.mod.Error()
· ───────────────
╰────
help: While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
help: Using `new` ensures the error is correctly initialized.

⚠ eslint-plugin-unicorn(throw-new-error): Require `new` when throwing an error.
╭─[throw_new_error.tsx:1:7]
1 │ throw lib[mod].Error()
· ────────────────
╰────
help: While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
help: Using `new` ensures the error is correctly initialized.

⚠ eslint-plugin-unicorn(throw-new-error): Require `new` when throwing an error.
╭─[throw_new_error.tsx:1:7]
1 │ throw (lib.mod).Error()
· ─────────────────
╰────
help: While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
help: Using `new` ensures the error is correctly initialized.

⚠ eslint-plugin-unicorn(throw-new-error): Require `new` when throwing an error.
╭─[throw_new_error.tsx:1:7]
1 │ throw Error('foo')
· ────────────
╰────
help: While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
help: Using `new` ensures the error is correctly initialized.

⚠ eslint-plugin-unicorn(throw-new-error): Require `new` when throwing an error.
╭─[throw_new_error.tsx:1:7]
1 │ throw CustomError('foo')
· ──────────────────
╰────
help: While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
help: Using `new` ensures the error is correctly initialized.

⚠ eslint-plugin-unicorn(throw-new-error): Require `new` when throwing an error.
╭─[throw_new_error.tsx:1:7]
1 │ throw FooBarBazError('foo')
· ─────────────────────
╰────
help: While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
help: Using `new` ensures the error is correctly initialized.

⚠ eslint-plugin-unicorn(throw-new-error): Require `new` when throwing an error.
╭─[throw_new_error.tsx:1:7]
1 │ throw ABCError('foo')
· ───────────────
╰────
help: While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
help: Using `new` ensures the error is correctly initialized.

⚠ eslint-plugin-unicorn(throw-new-error): Require `new` when throwing an error.
╭─[throw_new_error.tsx:1:7]
1 │ throw Abc3Error('foo')
· ────────────────
╰────
help: While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
help: Using `new` ensures the error is correctly initialized.

⚠ eslint-plugin-unicorn(throw-new-error): Require `new` when throwing an error.
╭─[throw_new_error.tsx:1:7]
1 │ throw TypeError()
· ───────────
╰────
help: While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
help: Using `new` ensures the error is correctly initialized.

⚠ eslint-plugin-unicorn(throw-new-error): Require `new` when throwing an error.
╭─[throw_new_error.tsx:1:7]
1 │ throw EvalError()
· ───────────
╰────
help: While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
help: Using `new` ensures the error is correctly initialized.

⚠ eslint-plugin-unicorn(throw-new-error): Require `new` when throwing an error.
╭─[throw_new_error.tsx:1:7]
1 │ throw RangeError()
· ────────────
╰────
help: While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
help: Using `new` ensures the error is correctly initialized.

⚠ eslint-plugin-unicorn(throw-new-error): Require `new` when throwing an error.
╭─[throw_new_error.tsx:1:7]
1 │ throw ReferenceError()
· ────────────────
╰────
help: While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
help: Using `new` ensures the error is correctly initialized.

⚠ eslint-plugin-unicorn(throw-new-error): Require `new` when throwing an error.
╭─[throw_new_error.tsx:1:7]
1 │ throw SyntaxError()
· ─────────────
╰────
help: While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
help: Using `new` ensures the error is correctly initialized.

⚠ eslint-plugin-unicorn(throw-new-error): Require `new` when throwing an error.
╭─[throw_new_error.tsx:1:7]
1 │ throw URIError()
· ──────────
╰────
help: While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
help: Using `new` ensures the error is correctly initialized.

⚠ eslint-plugin-unicorn(throw-new-error): Require `new` when throwing an error.
╭─[throw_new_error.tsx:1:10]
1 │ throw (( URIError() ))
· ──────────
╰────
help: While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
help: Using `new` ensures the error is correctly initialized.

⚠ eslint-plugin-unicorn(throw-new-error): Require `new` when throwing an error.
╭─[throw_new_error.tsx:1:7]
1 │ throw (( URIError ))()
· ────────────────
╰────
help: While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
help: Using `new` ensures the error is correctly initialized.

⚠ eslint-plugin-unicorn(throw-new-error): Require `new` when throwing an error.
╭─[throw_new_error.tsx:1:7]
1 │ throw getGlobalThis().Error()
· ───────────────────────
╰────
help: While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
help: Using `new` ensures the error is correctly initialized.

⚠ eslint-plugin-unicorn(throw-new-error): Require `new` when throwing an error.
╭─[throw_new_error.tsx:1:7]
1 │ throw utils.getGlobalThis().Error()
· ─────────────────────────────
╰────
help: While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
help: Using `new` ensures the error is correctly initialized.

⚠ eslint-plugin-unicorn(throw-new-error): Require `new` when throwing an error.
╭─[throw_new_error.tsx:1:7]
1 │ throw (( getGlobalThis().Error ))()
· ─────────────────────────────
╰────
help: While it's possible to create a new error without using the `new` keyword, it's better to be explicit.
help: Using `new` ensures the error is correctly initialized.
Loading