Skip to content

Helpful JavaScript, React, and React Native rules for ESLint, by Nozbe

License

Notifications You must be signed in to change notification settings

Nozbe/eslint-plugin-nozbe

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

eslint-plugin-nozbe

A collection of helpful ESLint rules we created while building Nozbe app.

Installation

yarn add --dev @nozbe/eslint-plugin-nozbe

In your .eslintrc.{js,yml,json}, add plugin:

  plugins: [
    '@nozbe/nozbe',
  ],

Then add rules you want to include

JSX: no &&

  rules: [
    '@nozbe/nozbe/no-jsx-andand': 'error',
  ]

This raises an error for && used in JSX expressions, like so:

<>
  {shouldShowFoo && <Foo />}
</>

Expressions like this behave differently on React and React Native: instead of not displaying, it can evaluate to 0, NaN, or cause a crash in some cases..

This auto-fixes to:

<>
  {shouldShowFoo ? <Foo /> : null}
</>

No overdue TODOs/FIXMEs

  rules: [
    '@nozbe/nozbe/no-overdue-todos': 'warn',
  ]

This turns TODO: and FIXME: comments into a warning after a specified date, for example:

// date given in yyyy-mm-dd format, but days and months can be omitted

// TODO(2024): Refactor X after Y is done
// FIXME(2023-03): Fix A once B is released
// TODO(2023-04-20): Remove this deprecation once version a.b.c is out

BTW: It can be helpful to set up your editor to highlight these comments. For example, for VS Code, use TODO Highlight v2 with this configuration:

"todohighlight.keywords": [
  {
    "text": "TODO(string):",
    "regex": {
      "pattern": "(?<=^|\"|\\s)TODO(\\([^)]+\\))?:"
    },
    "color": "#fff",
    "backgroundColor": "#ffbd2a",
    "overviewRulerColor": "rgba(255,189,42,0.8)",
    "diagnosticSeverity": "error"
  },
  {
    "text": "FIXME(string):",
    "regex": {
      "pattern": "(?<=^|\"|\\s)FIXME(\\([^)]+\\))?:"
    },
    "color": "#fff",
    "backgroundColor": "#f06292",
    "overviewRulerColor": "rgba(240,98,146,0.8)",
    "diagnosticSeverity": "warning"
  }
]

No argument spread

/* eslint @nozbe/nozbe/no-arg-spread: error */

This raises an error when spread is used on a call expression, like so:

someFunction(...args)

This isn't something you generally need to enable for a whole project. However, you should be aware that spreading very large arrays (tens of thousands of elements) can cause a "RangeError: Maximum call stack size exceeded" error. In such cases, you should pass the array as a single argument instead.

No optional catch binding

  rules: [
    '@nozbe/nozbe/no-catch-without-param': 'error',
  ]

This raises an error for catch clause without binding, like so:

try {
  foo()
} catch {
  fallback()
}

Since this is a relatively new addition to JavaScript, it can cause unexpected failure of JS tooling, sometimes at runtime.

This auto-fixes to:

try {
  foo()
} catch (_error) {
  fallback()
}

Imports: No imports

/* eslint @nozbe/nozbe/no-imports: error */

This raises an error when imports are used instead of require().

This isn't something you generally need to enable for a whole project.

However, in some cases you want to make sure that require() is used to order calls in a specific order. For example, in application bootstrapping code, you might want to ensure that you require() a crash collection library, then initialize it, before requiring other code. Normally, imports would all be reordered to the top, breaking the strict ordering.

Imports: No namespaced imports

/* eslint @nozbe/nozbe/no-namespaced-imports: error */

This raises an error when namespaced imports are used, like so:

import * as Foo from 'bar'

In some cases, you might want to ensure that namespaced imports aren't used in a project or in specific files as to not balloon bundle or chunk size.

Flow: No ambiguous object exactness

  rules: [
    '@nozbe/nozbe/flow-no-ambiguous-object-exactness': [
      'error',
      { exactByDefault: false }
    ],
  ]

This raises an error when ambiguous objects (not explicitly exact or inexact) are used, except for indexed objects:

// bad:
const foo: { a: true }

// good:
const foo: {| a: true |}
const foo: $Exact<{ a: true }>
const foo: { a: true, ... }
const foo: { [string]: boolean }

The problem with ambiguous object exactness is that Flow is in the process of migrating from "inexact objects by default" to "exact objects by default", and until this migration is complete, different users can have objects configured differently. This can be confusing, it makes it hard to migrate from inexact to exact objects, and is particularly a problem if you are shipping a library using Flow (e.g. WatermelonDB), since its users can have different Flow configurations.

This auto-fixes to:

// If configured with { exactByDefault: true }
const foo: {| a: true |}

// If configured with { exactByDefault: false }
// Note that this auto-fix is not perfect, and it sometimes places one comma too many before `...`
// When mass-auto-fixing, run regex find `,[\s\n]+, \.{3} \}` and replace with `, ... }`
const foo: { a: true, ... }

Flow: No shorthand exact objects

  rules: [
    '@nozbe/nozbe/flow-no-shorthand-exact-object': 'warn',
  ]

This raises an error when shorthand exact objects are used:

const foo: {| a: true |}

This syntax breaks VS Code's code coloring unfortunately...

This auto-fixes to:

const foo: $Exact<{ a: true }>

Max lines

  rules: [
    '@nozbe/nozbe/max-lines': [
      'warn',
      { max: 600 }
    ],
  ]

This rule disallows file longer than max lines.

This is very similar to ESLint's builtin max-lines rule. The main difference is that max-lines will highlight all offending lines red/yellow in your IDE, which is very annoying. @nozbe/nozbe/max-lines will only highlight the top line, in addition to producing a message in eslint output.

This is good when you don't want to enforce this rule as an error, merely a warning - something to be dealt with at the nearest convenience, not something you have to drop everything you're doing to fix. IMO, the official rule's behavior encourages the developer to just silence the error for the whole file, which defeats the point.

No invariant() without message

  rules: [
    '@nozbe/nozbe/no-invariant-without-message': 'error',
  ]

This rule disallows invariant() to be called without the second parameter, enforcing that errors thrown must produce a helpful message.

// bad:
invariant(someCondition)

// good:
invariant(someCondition, 'Some condition was not met!')

No in expressions

  rules: [
    '@nozbe/nozbe/no-in-expression': 'error',
  ]

This rule disallows 'foo' in bar expressions. These expressions can easily produce the wrong (potentially unsafe) behavior if you're not careful (e.g. 'toString' in {} is true; also inheritance, etc.)

You probably want to have in your project a convenient shortcut to Object.prototype.hasOwnProperty.call(obj, prop) which has a less error-prone behavior.

About

Helpful JavaScript, React, and React Native rules for ESLint, by Nozbe

Resources

License

Stars

Watchers

Forks

Packages

No packages published