Get Started
- CodeAnt AI
- Control Center
- Pull Request Review
- IDE
- Compliance
- Anti-Patterns
- Code Governance
- Infrastructure Security Database
- Application Security Database
Sonar
Cognitive Complexity of functions should not be too high
function analyzeData(data) {
if (data) {
if(data.type === 'student') {
if(data.grade > 50) {
if(data.classes.completed > 20) {
console.log('Student passes.');
if(data.attendance > 90) {
console.log('Student has excellent attendance.');
} else {
console.log('Student attendance is satisfactory.');
}
} else {
console.log('Student must complete more classes.');
}
} else {
console.log('Student must improve grades.');
}
} else if(data.type === 'teacher') {
if(data.yearsOfExperience > 5) {
console.log('Experienced teacher.');
} else {
console.log('New teacher.');
}
}
} else {
console.log('No data provided.');
}
}
-
The rule explicitly addresses cognitive complexity, ensuring that functions within the code are simple enough to understand and maintain. By setting a “cognitive complexity” threshold, it encourages developers to write code that is easier to read and less prone to errors, directly affecting the maintainability and quality of the codebase.
-
By analyzing and reporting on the complexity at both the function and file level, the rule provides valuable insights into specific areas where the code could be refactored to improve readability and reduce potential technical debt, making it a useful tool for ongoing code quality improvement and review processes.
-
The rule’s consideration of logical expressions and their impact on cognitive complexity helps in identifying potentially confusing constructs that might not be immediately apparent. For instance, by distinguishing between direct complexity (e.g.,
if
statements) and structural complexity (e.g., nested loops or conditions), it aids in pinpointing exact code segments that contribute disproportionately to overall complexity. -
The inclusion of options to configure the complexity threshold and the specificity in handling various control structures (like loops, conditional expressions, and logical operations) tailors the rule’s enforcement to the project’s or team’s standards. This customization ensures that the rule is not just a generic guideline but can be adapted to fit the cognitive load the team is comfortable managing, thereby enhancing its effectiveness in promoting best practices tailored to the project’s needs.
“if … else if” constructs should end with “else” clauses
function checkGrade(score) {
if (score >= 90) {
console.log("Grade A");
} else if (score >= 80) {
console.log("Grade B");
} // Notice there is no else clause here
}
checkGrade(85);
- Ensures that every
if ... else if
chain ends with anelse
block, enforcing a default action. This makes sure that all possible branches of execution are accounted for, improving the reliability of the code. - Helps in preventing logical errors that might occur when a condition in the
if ... else if
chain is not met and no default action is specified. This is particularly useful in scenarios like input validation or branching based on variable values, where overlooking a condition can lead to unintended consequences. - Enhances code readability and maintainability by explicitly requiring a final
else
clause. It acts as a self-documenting feature indicating that the developer has considered all possible outcomes. This clarity is beneficial for future code reviews and maintenance, ensuring that every decision branch is concluded with a purposeful action. - Aids in debugging by providing a specific point where a developer can insert logging or error handling as a catch-all for any unhandled cases within the
if ... else if
sequence. Without anelse
clause, diagnosing why none of the specified conditions were met can be more challenging and time-consuming.
“switch” statements should not have too many “case” clauses
// Example of a switch statement violating the sonarjs/max-switch-cases rule
// Let's assume the rule is configured to limit to 5 cases, and this example has 6.
function getColorName(colorCode) {
switch (colorCode) {
case 1:
return 'Red';
case 2:
return 'Blue';
case 3:
return 'Green';
case 4:
return 'Yellow';
case 5:
return 'Pink';
case 6:
return 'Orange';
default:
return 'Unknown';
}
}
-
This rule enforces a manageable number of case clauses within a switch statement, which directly contributes to improving the readability of the code. By limiting the number of cases, the code is easier to understand and maintain, especially for complex logic that might otherwise be buried in a long list of cases.
-
It encourages developers to look for more efficient or appropriate data structures or patterns (like using an object map instead of a switch statement for simple key-value associations) to accomplish the same goals. This leads to cleaner and more idiomatic JavaScript code, as exemplified in the provided ‘fix’ block.
-
By imposing a limit on the number of switch cases, it indirectly promotes the principle of breaking down large, monolithic functions into smaller, more focused functions. This can lead to a more modular codebase, where each function has a single responsibility and is easier to test and debug.
-
This specific rule helps in identifying potential refactoring opportunities. Exceeding the maximum number of cases could be an indicator that the logic needs to be re-evaluated and possibly simplified. Enforcing such rules makes it easier to spot areas of code that might benefit from a design pattern, thus enhancing the overall architecture of the application.
All branches in a conditional structure should not have exactly the same implementation
if (condition) {
console.log("Do something");
} else {
console.log("Do something");
}
-
This ESLint rule helps in identifying redundant code within if-else statements, switch statements, and ternary operators where all branches perform the same action. Such redundancy can lead to bloated and less readable code which can be simplified by consolidating the conditional branches.
-
By detecting duplicate implementations across all branches, this rule encourages developers to refactor their code for higher efficiency. Removing duplicated branches not only shrinks the codebase but also makes future modifications easier since there’s only one piece of logic to update.
-
Applying this rule can potentially uncover logical errors in the code. In scenarios where all branches of a conditional structure are doing the same thing, it could indicate that the developer made a mistake while implementing the conditional logic, such as misunderstanding the requirements or incorrectly copying and pasting code.
-
It enforces better coding practices by prompting the developer to think critically about their use of conditional structures. Encouraging programmers to avoid unnecessary conditionals aligns with clean code principles, making the code more straightforward and maintaining efficiency.
Collapsible “if” statements should be merged
if (userHasPermissions) {
if (userIsAdmin) {
// Code to execute if both conditions are true
console.log('User is an admin with permissions');
}
}
- The rule specifically helps in identifying and suggesting the merging of nested “if” statements that can logically be combined into a single “if” statement. This directly improves code readability by reducing the levels of indentation and making the logical conditions more straightforward to understand at a glance.
- By targeting and merging collapsible “if” statements, this rule aids in reducing the cognitive load on developers. It simplifies the process of reasoning about the code as developers do not have to track multiple nested conditions separately.
- The presence of this rule encourages the practice of writing more efficient and concise conditional logic. By prompting developers to combine conditions, it indirectly fosters the habit of looking for and applying logical simplifications elsewhere in their code.
- Applying this rule can also have subtle performance implications. In scenarios where evaluating the conditions is computationally expensive, reducing the number of “if” statements means the condition is evaluated less frequently. This could contribute to minor performance improvements in certain cases, although the primary benefit remains in code maintainability and readability.
Collection sizes and array length comparisons should make sense
const myArray = [];
// Incorrect comparison that does not make sense.
// This checks if `myArray.length` is less than zero, which is impossible since lengths are non-negative.
if (myArray.length < 0) {
console.log('Array is empty');
}
- Detects logically incorrect comparisons related to collection sizes or array lengths, such as checking if an array’s length is less than zero, which is an impossibility given that lengths are non-negative. This ensures that developers do not write code based on incorrect assumptions about collection states.
- Highlights specific misuse of collection size properties (like
.length
for arrays,.size
for Sets, etc.), thereby teaching or reinforcing correct usage patterns to developers, especially those who may be less familiar with the nuances of JavaScript or the specific collection types being used. - Offers suggestions to correct the identified misuse by providing actionable feedback directly within the code editor. This helps in quickly resolving potential bugs or logical errors related to collection size checks without needing to refer to external documentation or resources.
- Enhances code readability and maintainability by encouraging the use of accurate and logically sound condition checks. This reduces the likelihood of future errors and makes the intention behind the conditionals clearer to anyone reading the code, facilitating easier debugging and code reviews.
String literals should not be duplicated
function setUserRole(user) {
if (user.role === "admin") {
console.log("User role is admin.");
}
if (user.previousRole === "admin") {
console.log("User previous role was admin.");
}
}
- The rule helps maintain consistency in the codebase by enforcing the use of a single, definitive declaration for reused string literals, making it easier to update or localize strings without searching through multiple files or code segments.
- By reducing duplication of string literals, this rule indirectly promotes the practice of declaring constants for frequently used strings, thereby making code more readable and maintainable by providing meaningful names instead of direct values.
- It contributes to optimizing the application’s memory usage as multiple instances of the same string literal can lead to unnecessary consumption of memory resources. Using constants can help in referencing the same memory location for a string value.
- The rule aids in identifying potential typos or inconsistencies in string literals across the codebase. Since duplicated strings need to be consolidated into a single declaration, it reduces the chances of errors that may arise from manually updating multiple instances of the same string.
Two branches in a conditional structure should not have exactly the same implementation
let userStatus = 'active';
let message;
if (userStatus === 'active') {
message = 'User is active.';
} else if (userStatus === 'inactive') {
message = 'User is active.'; // This implementation is duplicated from the if branch
} else {
message = 'User status is unknown.';
}
- It prevents code duplication within if-else and switch-case statements by identifying branches with identical implementation, encouraging more concise and maintainable code.
- By discouraging duplicate branches, it indirectly promotes the use of more efficient patterns, such as combining conditions, which can improve readability and reduce the cognitive load on developers reviewing the code.
- It identifies potential bugs or logic errors where code duplication might indicate a misunderstanding of the requirements or an incorrect implementation of the logic, improving code reliability.
- Enforcing this rule can lead to identifying refactoring opportunities, guiding developers towards adopting best practices like function extraction for repetitive code blocks, thus enhancing the modularity and reusability of code.
Collection elements should not be replaced unconditionally
function fillArray() {
const arr = [1, 2, 3, 4, 5];
for (let i = 0; i < arr.length; i++) {
// Unconditionally overwrite elements
arr[i] = 10;
}
return arr;
}
- Ensures efficient data handling by preventing unnecessary overwriting of collection elements, which can lead to performance degradation, especially in large collections or within loops.
- Encourages developers to implement logic checks before modifying collection elements, fostering more thoughtful and error-resistant coding practices that consider conditions under which data should be altered.
- Helps in maintaining data integrity by safeguarding against unintentional overwrites that could erase valuable data, thus reducing potential bugs and logical errors in the program that are difficult to trace.
- Aids in code readability and maintainability by pushing for condition-based modifications rather than blanket updates, making the code more understandable for future developers and oneself, clarifying the intent behind data manipulation.
Empty collections should not be accessed or iterated
const myEmptyArray = [];
myEmptyArray.forEach(element => {
console.log(element);
});
- Enforces a performance-oriented coding practice by avoiding unnecessary iterations over collections that are empty, which can lead to improved efficiency in code execution since empty collections will not trigger the logic inside iterations that are not needed.
- Helps in the prevention of potential runtime errors or unexpected behavior in JavaScript applications by ensuring that code attempting to access or iterate over empty collections first checks if the collection has elements, thereby avoiding actions on undefined or null values that could lead to errors.
- Encourages more robust and defensive programming by making developers explicitly handle the case of empty collections, thereby making the code more predictable and easier to understand for readers by clearly showing the intention and handling of all possible states of collections.
- Improves code maintainability by preventing the execution of pointless operations, which can simplify debugging and refactoring efforts as there’s a clear check for collection content before performing operations, reducing the chance of issues related to empty collections being overlooked during development.
Function calls should not pass extra arguments
function addNumbers(a, b) {
return a + b;
}
const result = addNumbers(1, 2, 3); // This call includes an extra argument, which is incorrect.
console.log(result);
- Ensures that functions are called with the correct number of arguments, which helps in preventing runtime errors due to undefined behavior from unexpected arguments. This aligns with the intent and design of the function, making code more predictable and robust.
- Improves code readability and maintainability by ensuring that function calls are aligned with the function’s parameter signature. This prevents confusion about a function’s purpose and the role of each argument, especially in large codebases where functions might be used in multiple places.
- Helps in the early detection of potential bugs during development. By flagging cases where extra arguments are passed, developers can rectify mistakes before they become harder to diagnose issues, thus streamlining the debugging process.
- Assists in optimizing performance. Although JavaScript engines can handle extra arguments by making them accessible via the
arguments
object, avoiding unnecessary arguments can prevent undue processing and memory usage, especially in critical performance paths or in functions called frequently.
Boolean expressions should not be gratuitous
if (true === true) {
console.log('This condition is always true.');
}
- Helps in identifying and removing redundant Boolean expressions in conditions that always evaluate to true or false, improving code readability and maintainability.
- Prevents logic errors that may arise from unnecessary complexity in conditional statements by flagging overly explicit or redundant conditions.
- Enhances code quality by encouraging the use of more straightforward and understandable conditional expressions, making it easier for developers to follow the program’s logic.
- Aids in optimizing the codebase by identifying expressions that can be simplified, potentially resulting in minor performance improvements due to reduced evaluation time in conditions.
Related “if-else-if” and “switch-case” statements should not have the same condition
const value = 10;
if (value === 10) {
console.log('Value is 10');
} else if (value === 10) {
console.log('Value is still 10');
}
-
This ESLint rule identifies duplicate conditions in “if-else-if” structures and “switch-case” statements, ensuring that different branches handle unique conditions. By preventing identical conditions, it avoids redundant code checks that could lead to developer confusion or imply a misunderstanding of the code’s logic.
-
It improves code readability and maintainability. When conditions are distinct and intentional, it’s easier for developers to follow the logic flow. This rule highlights areas where the logic may not be as straightforward as intended, prompting a review to clarify or correct the code’s intent.
-
Helps to detect potential bugs early. Identical conditions in control flow statements could indicate a copy-paste error or an oversight where a developer intended to check for a different condition. Catching these early in the development process prevents logical errors that might be difficult to debug later.
-
The rule promotes best coding practices by enforcing a proactive check for logical discrepancies in conditional statements. It aligns with the principle of having each branch in control structures serve a distinct purpose, which is a hallmark of clean, efficient code.
Identical expressions should not be used on both sides of a binary operator
function checkPassword(password, confirmPassword) {
if (password === password) { // Bad: Identical expressions on both sides
console.log('Passwords match');
} else {
console.log('Passwords do not match');
}
}
-
This rule helps in identifying logical and binary expressions in the code where both sides of an operator are identical, which most likely indicates a coding error or oversight. For example, an expression like
password === password
in a password check is clearly a mistake and should bepassword === confirmPassword
. -
The rule aids in preventing bugs related to comparison logic in the code, by catching cases where a developer may have mistakenly used the same variable, expression or literal on both sides of a binary or logical operator, thereby preventing the application from behaving unexpectedly.
-
It promotes code readability and maintainability by ensuring that expressions within conditional statements are meaningful and intentional. Identical expressions may confuse other developers or even the original author upon reviewing the code later, as they might spend time understanding if the repetition was intentional or an error.
-
By automatically detecting and pointing out identical expressions on both sides of a binary operator, it saves time during code reviews and helps in early bug detection. Thus, enabling the development team to focus on more significant issues and logic enhancements rather than trivial bugs that can be caught by such linting rules.
Functions should not have identical implementations
function calculateArea(length, width) {
return length * width;
}
function computeArea(length, width) {
return length * width;
}
- The rule helps in maintaining code uniqueness by identifying and reporting functions that have identical implementations, which ensures that developers avoid unnecessary code duplication. This leads to a cleaner, more maintainable codebase by encouraging the reuse of existing functions instead of introducing new ones that do the same task.
- It enhances code readability and understanding for other developers, as it reduces the number of functions they need to go through. When functions perform identical tasks under different names, it can lead to confusion about which function to use or modify for a particular piece of functionality.
- By reducing code duplication, this rule indirectly aids in reducing the chances of bugs that arise from having to make the same fix in multiple places. When a bug is found in a section of code that’s duplicated elsewhere, there’s a risk that developers might fix it in one location and overlook the others. Enforcing this rule minimizes such risks.
- It promotes best practices in programming, specifically the DRY principle (Don’t Repeat Yourself). This principle states that duplication in logic can lead to increases in complexity, potential for errors, and difficulties in future changes or refactorings. By ensuring that functions are not identically implemented, the rule encourages developers to abstract common functionality into single, well-defined functions.
Return values from functions without side effects should not be ignored
// A function returning a boolean flag based on some condition
function checkInventory(product) {
return product.quantity > 0;
}
// Ignoring the returned value from checkInventory
function processOrder(product) {
checkInventory(product); // Bad: Return value is ignored
// Further code assuming inventory was checked but not actually considering the result of the check
}
-
The rule ensures that return values from functions, which are designed to inform the caller about the outcome or state after execution, are actually utilized. This is especially crucial in scenarios where a function’s output dictates the flow of logic, as demonstrated in the
checkInventory
function, where ignoring the return value could lead to making decisions without considering critical information. -
It prevents potential bugs that could arise from ignoring function outputs. For instance, in the provided example, neglecting the return value of
checkInventory
could result in attempting to process an order for a product that is out of stock, leading to inconsistencies in application state or user experience. -
This rule encourages better coding practices by prompting developers to consciously think about and handle the outputs of functions. By forcing the consideration of function return values, it promotes the development of more robust and fault-tolerant code, where each function’s role and output in the application logic are fully leveraged.
-
It aids in the maintainability and readability of code by highlighting areas where the results of operations are unaccounted for. This can be particularly beneficial during code reviews or when new developers are familiarizing themselves with an existing codebase, as it makes the flow of data and decision-making within the application clearer and more explicit.
Boolean checks should not be inverted
function shouldProceed(isReady) {
if (!isReady) {
return false;
}
// More logic here
return true;
}
-
Enhances code readability by avoiding double negatives, which can be confusing to interpret, especially for those who might not be native English speakers or for developers unfamiliar with the codebase.
-
Simplifies logical conditions making it easier to understand the flow of the program at a glance, reducing the cognitive load on the developer and thereby decreasing the likelihood of errors being introduced during development or maintenance.
-
Improves maintainability by enforcing a more straightforward approach to conditional statements. When boolean checks are not inverted, it aligns better with natural language, making the codebase more approachable for future modifications by different team members.
-
Facilitates easier code reviews and debugging processes since the conditionals follow a more intuitive pattern. Reviewers can quickly ascertain the logic behind condition checks without needing to mentally invert the conditions, leading to faster and more effective code reviews.
“switch” statements should not be nested
function handleActions(action, subAction) {
switch (action) {
case 'ACTION_TYPE_1':
// Some logic here
switch (subAction) { // This nested switch triggers the ESLint rule
case 'SUB_ACTION_1':
// Some specific logic here
break;
// other cases...
}
break;
// other cases...
}
}
-
Improves Code Readability: Nested
switch
statements considerably reduce the readability of the code. This rule helps in maintaining a cleaner, more understandable codebase by preventing deep nesting which can make logic flow hard to follow, especially for new developers or when revisiting code after some time. -
Facilitates Code Maintenance and Debugging: By discouraging nested
switch
statements, this rule encourages the use of separate functions or strategies to handle complex conditional logic. This separation simplifies debugging and testing individual components of the logic, as well as making the codebase more maintainable by isolating changes to specific functions. -
Promotes Good Coding Practices: Enforcing this rule aligns with the principle of keeping functions focused on a single task. Decomposing nested switches into separate functions encourages developers to write modular, reusable code, thus adhering to good coding standards and practices like the Single Responsibility Principle (SRP).
-
Prevents Deeply Nested Structures: Nested structures, specifically
switch
cases, increase the complexity and cognitive load required to understand the code. By avoiding nested switches, this rule helps in maintaining a flatter code structure, which is generally easier to work with and less prone to errors during modifications or additions to the codebase.
Template literals should not be nested
const user = 'Alice';
const greeting = `Hello, ${`user: ${user}`}`;
-
It enhances code readability by avoiding the complexity that comes with nested template literals, ensuring that developers can understand the intent behind a piece of code more swiftly. The rule specifically targets reducing the cognitive load when parsing template literals within other template literals.
-
The rule helps maintain consistent coding practices within a team or project by disallowing nested template literals, which can vary widely in style and readability between different developers. This specific enforcement fosters a unified codebase that is easier to read and maintain.
-
By encouraging the separation of nested template literals into separate variables (as shown in the ‘fix’ example), this rule promotes better reusability and modifiability of code parts. Developers can easily reuse or modify the separated variable without impacting the broader template literal, leading to more modular code.
-
The rule potentially prevents runtime errors or unexpected behaviors that might arise from complicated nesting of template literals, where template parsing and variable interpolation could lead to subtle bugs. By flattening these structures, the code becomes more straightforward and predictable.
Loops with at most one iteration should be refactored
// Example of a for-loop that will only iterate once
for (let i = 0; i < 1; i++) {
console.log("This loop will only ever iterate once.");
}
// Example of a while-loop that will only iterate once
let condition = true;
while (condition) {
console.log("This loop will also only ever iterate once.");
condition = false; // The loop is controlled to run only once
}
- It improves code efficiency by identifying and eliminating loops that iterate only once, which are unnecessary and add unnecessary complexity to the code. By refactoring such loops out, the execution becomes slightly faster as the overhead of loop initialization and iteration checking is removed.
- It enhances code readability by removing redundant control flow structures, making the code simpler and clearer to understand for developers. Instead of puzzling over why a loop exists that only runs a single time, the developer sees a straightforward code block that executes once.
- It helps in code maintenance by flagging patterns that could suggest a misunderstanding of how loops work or a potential logical error in the control flow. For example, a loop that was intended to iterate multiple times but due to a mistake only iterates once will be highlighted for review.
- Prevents potential bugs related to misunderstanding the code’s behavior, especially when other developers or future maintainers assume that the loop could iterate multiple times. By refactoring such loops, the developer is forced to explicitly define the intended behavior, reducing the room for error or misinterpretation.
Boolean literals should not be redundant
const isUserActive = true;
// Using redundant boolean literals in conditionals
if (isUserActive === true) {
console.log('The user is active');
} else {
console.log('The user is inactive');
}
// Using redundant boolean literals in a ternary operator
const status = isUserActive === false ? 'inactive' : 'active';
- Improves code readability and maintainability by eliminating unnecessary verbosity in boolean expressions, making the logic clearer and more concise. For instance, changing
if (isUserActive === true)
toif (isUserActive)
makes the condition easier to read and understand at a glance. - Reduces the risk of introducing errors during code modifications or refactoring. Simpler expressions like
if (isUserActive)
are less prone to mistakes than more complex ones likeif (isUserActive === true)
, especially for inexperienced developers or in complex codebases. - Helps in enforcing a consistent coding style across the project, where boolean expressions are written in a simplified and standard way. This consistency aids in code review processes and new team member onboarding, as they encounter familiar coding patterns.
- Optimizes code performance slightly by removing unnecessary comparisons. Although modern JavaScript engines are highly optimized, simplifying expressions by removing redundant boolean literals can contribute to marginal performance improvements, especially in critical code paths.
Jump statements should not be redundant
function exampleFunction() {
// Some code
if (true) {
console.log("True branch");
return;
}
console.log("After conditional");
return; // Redundant return
}
-
This rule helps identify unnecessary code, specifically redundant jump statements like
return;
at the end of a function or a redundantcontinue;
in the last loop iteration, which can improve code readability by removing superfluous lines. This makes it easier for developers to understand the flow of the program without getting distracted by unnecessary statements. -
By automating the detection of redundant jump statements, this rule assists in maintaining cleaner codebases and can help in reducing the cognitive load on developers. When developers don’t have to manually check for these issues, they can focus on more complex logical or architectural problems, enhancing productivity.
-
The rule includes suggestions for automatic fixes (e.g., removing the redundant jump statement), which can speed up the refactoring process and help maintain consistent code quality. This aspect of the rule is particularly beneficial for large projects or teams, where manually identifying and fixing such issues could be time-consuming and prone to oversight.
-
It enforces best coding practices and standards, particularly in ensuring that control flow statements are used effectively and as intended. By discouraging the use of redundant
return;
andcontinue;
statements, it aligns with the principle of writing clear and purposeful code. This adherence to best practices can be especially important in collaborative environments, where consistent coding standards facilitate easier code reviews and integration.
Conditionals should start on new lines
if (a > b) doSomething(); if (c < d) doSomethingElse();
- Enforces clarity in code structure by ensuring conditional statements are not cramped on the same line, which helps in enhancing the readability and maintainability of the code. This makes it easier for developers to distinguish between different control flow paths.
- Reduces the likelihood of logical errors that could occur when multiple conditions are placed on the same line, as it forces a clear separation and visualization of each conditional execution path.
- Aids in code review and debugging processes by making it straightforward to identify conditional branches, as each condition starts on a new line. This structured approach prevents misinterpretation or oversight of conditions that are closely placed.
- Encourages best coding practices by suggesting automatic fixes, such as inserting ‘else’ where appropriate or adding a newline, thereby helping developers adhere to a standard coding style that prioritizes code clarity and cohesion.
“switch” statements should have at least 3 “case” clauses
function getAnimalSound(animal) {
let sound = '';
switch (animal) {
case 'dog':
sound = 'bark';
break;
case 'cat':
sound = 'meow';
break;
default:
sound = 'unknown';
}
return sound;
}
-
Ensures readability by advocating for the use of
switch
statements only when they manage a considerable number of cases. This prevents misuse for scenarios better served byif-else
constructs, maintaining cleaner and more intuitive code. -
Enhances maintainability by guiding developers towards simpler conditional logic (like
if-else
) for scenarios with fewer cases. This minimizes the cognitive load when interpreting the control flow, making future updates or reviews less error-prone. -
Improves the consistency of decision structures within the codebase by setting a clear threshold (at least 3 cases) for when to use
switch
versusif-else
statements. This consistency aids in code understanding and standardization among team members. -
Encourages developers to consider the most efficient and readable structure for conditionals, potentially leading to performance optimizations in scenarios where
if-else
statements might execute faster thanswitch
statements due to fewer cases to evaluate.
Collection and array contents should be used
function demo() {
const unusedNumbers = [1, 2, 3, 4, 5];
console.log("This function does not use the 'unusedNumbers' array");
}
- This rule helps in identifying and eliminating dead code related to unused collections in a codebase, which can improve readability and maintainability. By reporting unused arrays and similar collections, developers can promptly remove or refactor unnecessary parts of their code.
- It aids in optimizing memory usage and performance. Collections like arrays that are declared but never used can lead to unnecessary memory consumption in an application. By highlighting these collections, the rule encourages developers to clean up their code, potentially reducing the application’s memory footprint.
- The rule promotes best coding practices by enforcing the usage of declared variables. This can be particularly beneficial for less experienced developers learning to write efficient and effective code. By adhering to this rule, developers are discouraged from declaring data structures that they don’t end up utilizing.
- It can help in the early detection of logical errors or unfinished sections of code. Sometimes, a developer might declare a collection with the intent to use it, but then forget or make a mistake. This rule can act as a reminder or a prompt to revisit the code, ensuring that all declared collections have a purpose and are indeed used as intended.
The output of functions that don’t return anything should not be used
function logMessage(message) {
console.log(message);
}
const messageStatus = logMessage('Hello, World!');
// Here, logMessage doesn't return anything, so messageStatus will be undefined, leading to a wrongful usage based on the rule 'sonarjs/no-use-of-empty-return-value'
- This rule helps to avoid bugs related to the misunderstanding of a function’s return value by ensuring that developers do not mistakenly use the output of functions that are intended not to return anything. For example, in situations where a developer might expect a function like
console.log
to return a value, which it does not, leading to potentially incorrect conditional checks or assignments. - The rule enforces better code clarity and intent. When functions that don’t return anything are used as if they do, it can confuse future readers of the code about the developer’s intentions. By making sure that only functions that explicitly return values are used in assignments or conditionals, the intended behavior of the code is much clearer.
- It promotes best practices in JavaScript development by encouraging the explicit return of values when needed. This can lead to more maintainable code, as it becomes clear which functions are pure and return values based on their input, and which functions perform side effects without returning a value.
- Finally, this rule assists in optimizing code performance slightly. By preventing the assignment of undefined values (from functions not returning anything), it avoids unnecessary memory allocations for storing these undefined values and the potential overhead of dealing with them in later computations or logical conditions.
“catch” clauses should do more than rethrow
try {
// Some operation that might fail
performRiskyOperation();
} catch (error) {
// This catch block does nothing but rethrow the error
throw error;
}
- Encourages cleaner code by eliminating unnecessary
catch
clauses that merely rethrow errors without handling them, making the code more readable and concise. - Helps in identifying and refactoring redundant error handling paths which may lead to better error management strategies, rather than just forwarding the errors up the call stack.
- Improves performance slightly by reducing the overhead of catch clauses that do nothing but rethrow the errors, which can be especially noticeable in deeply nested try-catch structures.
- Facilitates the debugging process by ensuring that errors are either properly handled or propagated without unnecessary interruptions, making it easier to trace error origins without stepping through redundant catch blocks.
Non-existent operators ”=+”, ”=-” and ”=!” should not be used
let a = 5;
let b = 10;
// Incorrect usage of non-existent operators
a =+ b; // Intended to add and assign but mistakenly uses =+
a =- b; // Intended to subtract and assign but mistakenly uses =-
let flag = true;
flag =! flag; // Intended to negate and assign but mistakenly uses =!
-
Ensures accuracy in operator usage by catching typos involving compound assignment operators like
+=
,-=
, and logical NOT assignment (=!
to=!
), which are common sources of logic errors due to their similarity in appearance. -
Improves code readability and maintainability by enforcing the correct usage of JavaScript operators, making it easier for developers to understand the intent of the code at first glance, especially for those who might not be deeply familiar with JavaScript’s syntactical nuances.
-
Prevents potential runtime errors or unexpected behavior by ensuring that developers use the intended operators for addition, subtraction, and logical NOT operations. This helps in reducing debugging time and increases the overall reliability of the code.
-
Enhances code consistency across a project by standardizing the use of compound assignment operators and logical NOT operations, which is beneficial for teams to maintain a uniform coding style, thereby improving collaboration and reducing the risk of misinterpretation of code segments among team members.
Local variables should not be declared and then immediately returned or thrown
function calculateArea(width, height) {
const area = width * height;
return area;
}
-
The rule promotes cleaner and more concise code by eliminating unnecessary local variable declarations that are immediately returned or thrown. This leads to a reduction in the overall lines of code, making it easier to read and understand the purpose of a function or code block at a glance.
-
It helps in identifying instances where a variable is declared only to be used for a return or throw statement right after. This can assist in optimizing code performance slightly by reducing the overhead of variable declaration and assignment operations that are not needed.
-
Encourages developers to adopt a more functional programming style where possible, by directly returning expressions. This can lead to code that is more straightforward and less prone to bugs related to variable scope or unintended mutations, as variables that are only used to hold a return value are eliminated.
-
This rule can also aid in the refactoring process. By enforcing immediate returns or throws, developers are nudged to break down complex functions into simpler, more reusable units. If a function is simply performing a calculation or evaluation and immediately returning the result, it might be a candidate for extraction into a separate, reusable function, leading to better modularization of the codebase.
Object literal syntax should be used
const car = new Object();
car.make = 'Toyota';
car.model = 'Corolla';
car.year = 2020;
-
Encourages the use of more concise and readable syntax for object creation, which makes the code easier to understand and maintain. Using literal notation (
{}
) instead ofnew Object()
followed by individual property assignments simplifies object initialization. -
Reduces the risk of unintentional function calls or prototype chain issues. The
new Object()
syntax can lead to confusion withObject.create(null)
, which creates an object with no prototype. This distinction is clearer when using object literal syntax. -
Facilitates easier debugging and code inspection. Object literals are more straightforward for many JavaScript engines to optimize. They also make the structure of the object immediately visible in the source code, whereas objects created with
new Object()
and then populated with properties cannot be inspected as a whole until runtime. -
Supports better coding practices by enforcing consistency. When developers consistently use object literals throughout a codebase, the uniformity can lead to fewer errors (such as typo-related bugs) and a lower learning curve for new developers or contributors reviewing the code for the first time.
Return of boolean expressions should not be wrapped into an “if-then-else” statement
function isNumberEven(number) {
if (number % 2 === 0) {
return true;
} else {
return false;
}
}
- The rule encourages the direct return of the boolean expression, enhancing code simplicity and readability. By removing unnecessary
if-then-else
statements, it simplifies the logic flow, making it easier for other developers to understand the intention of the code. - It promotes the use of boolean expressions in their simplest form, potentially optimizing the code’s execution. Directly returning a boolean expression can be more efficient than executing conditional statements, especially in interpreted languages like JavaScript.
- The rule can help in identifying redundant code patterns, such as an
if-then-else
statement that solely returnstrue
orfalse
. This reinforcement of best practices can significantly improve the quality of the codebase over time by gradually eliminating these patterns. - Automating the suggestion to simplify boolean returns can expedite code refactorings and reviews. By providing developers with instant feedback and actionable suggestions, it reduces the time required to make these improvements manually, leading to quicker development cycles and more maintainable code.
A “while” loop should be used instead of a “for” loop
// A "for" loop that can be replaced by a "while" loop because it doesn't use init and update expressions.
for (; condition;) {
// Loop body actions
}
- This ESLint rule specifically discourages the use of a “for” loop when its
init
andupdate
expressions are absent and only atest
condition is present. This is because a “while” loop would be more semantically appropriate in such cases, improving readability by directly conveying the intent of looping based on a condition without initializing or updating loop variables. - By automatically suggesting the refactoring from a “for” loop to a “while” loop when the loop’s
init
andupdate
sections are not utilized, this rule helps maintain consistency across the codebase. Consistent use of loop constructs based on their semantic purpose can make the code easier to understand and maintain. - The rule includes an automated fix function. This not only identifies instances where a “while” loop would be more appropriate but also offers an immediate correction by generating the equivalent “while” loop syntax. This automated refactoring saves developers time and effort in making the manual conversion and reduces the risk of syntax or logical errors during the conversion process.
- The focus on using a “while” loop instead of a “for” loop in scenarios where only the
test
condition is present can lead to slight performance optimizations. Removing unnecessary syntax from a “for” loop (absence ofinit
andupdate
) could potentially reduce the overhead of evaluating expressions that are not needed, making the “while” loop a more efficient choice in such specific cases.