npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

eslint-plugin-bad-smells

v1.0.3

Published

This plugin looks for bad smells in JavaScript

Downloads

3

Readme

eslint-plugin-bad-smells

NPM Downloads

This plugin looks for bad smells in JavaScript

Installation

You'll first need to install ESLint:

npm i eslint --save-dev

Next, install eslint-plugin-bad-smells:

npm install eslint-plugin-bad-smells --save-dev

Usage

Add bad-smells to the plugins section of your .eslintrc configuration file. You can omit the eslint-plugin- prefix:

{
  "plugins": ["bad-smells"]
}

Then configure the rules you want to use under the rules section.

{
  "rules": {
    "bad-smells/empty-catch": "error",
    "bad-smells/long-method": "error",
    "bad-smells/nested-callbacks": "error",
    "bad-smells/long-message-chain": "error",
    "bad-smells/long-parameter-list": "error"
  }
}

Supported Rules

  • Long method: A method contains too many lines of code
  • Long parameter list: A method contains too many parameters
  • Long message chain: Long chaining of functions with the dot operator
  • Empty catch: Catch blocks with zero lines of code
  • Nested callbacks: A method contains many callbacks

Refactoring

Long method

  • Extract method: Move code to a separate new method (or function) and replace the old code with a call to the method.

    Steps:

    1. First, create a new method and make sure to name it that the purpose of this method obvious

    2. Than you are able move the code from the main method to the function created

    3. The last step is to update the main method with the new methods created

    //Before
    function printOwing() {
      printBanner();
    
      // Print details.
      console.log("name: ", name);
      console.log("amount: ", getAmount());
    }
    //After
    function printDetails(amount) {
      console.log("name: " + name);
      console.log("amount: " + amount);
    }
    
    function printOwing() {
      printBanner();
      printDetails(getOutstanding());
    }
  • Replace Temp with Query: Move a part of the code to a new separate method and return the result from it.

    Steps:

    1. First, use Extract Method to calculate the value you need in the main method. Make sure that the method only returns a value and does not change the state of the object.

    2. Replace the variable in the main method.

//Before
function calculateTotal() {
  let basePrice = quantity * itemPrice;

  if (basePrice > 1000) return basePrice * 0.95;
  else return basePrice * 0.98;
}
//After
function basePrice() {
  return quantity * itemPrice;
}

function calculateTotal() {
  if (basePrice() > 1000) return basePrice() * 0.95;
  else return basePrice() * 0.98;
}

Long Parameter List

  • Extract method: Move code to a separate new method (or function) and replace the old code with a call to the method.

    Steps:

    1. First, you need to identify the parameters that can be grouped

    2. Than you are able to create methods with those parameters

    3. The last step is to update the main method with the new methods created

//Before
function printUserData(name, email, number, salary, zipCode, address) {
  console.log("name: ", name);
  console.log("email: ", email);
  console.log("number: ", number);
  console.log("salary: ", salary);
  console.log("zipCode: ", zipCode);
  console.log("address: ", address);
}
//After
function printAddress(zipCode, address) {
  console.log("zipCode: ", zipCode);
  console.log("address: ", address);
}

function printPersonalData(name, email, number, salary) {
  console.log("name: ", name);
  console.log("email: ", email);
  console.log("number: ", number);
  console.log("salary: ", salary);
}

function printUserData() {
  printAddress(zipCode, address);
  printPersonalData(name, email, number, salary);
}
  • Preserve Whole Object: Instead of passing the values of the object as parameters, you could pass the whole object as a parameter.

    Steps:

    1. Instead of destructuring the object, you can preserve the whole object so you know the reference to the properties used in the method.

    2. Now you are able to remove the old parameters from the method and use the object reference.

//Before
const { name, email, number, salary, zipCode, address } = userData;

function printUserData({ name, email, number, salary, zipCode, address }) {
  console.log("name: ", name);
  console.log("email: ", email);
  console.log("number: ", number);
  console.log("salary: ", salary);
  console.log("zipCode: ", zipCode);
  console.log("address: ", address);
}
//After
function printUserData(userData) {
  console.log("name: ", userData.name);
  console.log("email: ", userData.email);
  console.log("number: ", userData.number);
  console.log("salary: ", userData.salary);
  console.log("zipCode: ", userData.zipCode);
  console.log("address: ", userData.address);
}
  • Replace Parameter with Method Call: Instead of passing the values of the object as parameters, you could pass the whole object as a parameter.

    Steps:

    1. Make sure that you don't need the values that are passed to the current method. This is important because it guarantees the code can be moved.

    2. If the code is more complex than a single function, you can use Extract Method to isolate the code and make a simple call.

    3. The next step is to update the main method with all the new functions created to get the values.

    4. After adding the news calls to the method to replace the parameters, you are able to eliminate the parameters from the main method.

//Before
const discount = getDiscount();
const fees = getFees();
const shipping = getShipping();
const hasCupom = getCupom();

function printFinalPrice(
  quantity,
  itemPrice,
  discount,
  fees,
  shipping,
  hasCupom
) {
  // Caculate the final price

  console.log("finalPrice", finalPrice);
}
//After
function printFinalPrice(quantity, itemPrice) {
  // Get the values
  const discount = getDiscount();
  const fees = getFees();
  const shipping = getShipping();
  const hasCupom = getCupom();

  // Caculate the final price

  console.log("finalPrice", finalPrice);
}

Long Message Chain

Introduce variable to replace the calls or break the chain into general methods/properties for the object

//Before
const arr1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const arr2 = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20];

const newArr = arr1
  .map((e) => e + 3)
  .filter((e) => e % 2 === 0)
  .concat(arr2)
  .find((e) => e === 10);
//After
const arr1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const arr2 = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20];

const arrPlusThree = arr1.map((e) => e + 3);
const evenArr = arrPlusThree.filter((e) => e % 2 === 0);
const concatArr = evenArr.concat(arr2);
const hasNumberTen = evenArr.find((e) => e === 10);

Nested Callback

Extract Method or introduce method variable to replace the call

//Before
setTimeout(function () {
  xhr("/greeting/", function (greeting) {
    xhr("/who/?greeting=" + greeting, function (who) ←֓
      {
        document.write(greeting + " " + who)
      })
  })
}, 1000)
//After
setTimeout(foo, 1000);

function foo() {
  xhr("/greeting/", bar);
}

function bar(greeting) {
  xhr("/who/?greeting=" + greeting, baz);
}

function baz(who) {
  document.write(greeting + " " + who);
}

Empty catch

Include message errors

//Before
try {
  await asyncCall();
} catch (error) {}
//After

try {
  await asyncCall();
} catch (error) {
  console.error(error);
}

References