Security News
tea.xyz Spam Plagues npm and RubyGems Package Registries
Tea.xyz, a crypto project aimed at rewarding open source contributions, is once again facing backlash due to an influx of spam packages flooding public package registries.
eslint-config-lostfictions
Advanced tools
Readme
eslint-config-lostfictions
is a shareable, opinionated, batteries-included
configuration for ESLint.
Features
tsconfig.json
configured.)eslint-plugin-react
and
eslint-plugin-react-hooks
to catch errors and uphold best practices in React code.eslint-plugin-unicorn
.eslint-config-lostfictions
doesn't declare any peerDependencies
besides
ESLint and TypeScript, so there's no extra ESLint plugins and parsers
cluttering your package.json
that need to be audited for compatibility on
version bumps. (See below for why this is now possible.)Read on for the rationale, or jump to the Usage section below to get started.
TypeScript and ESLint might seem like they're used for the exact same thing — catching errors in JavaScript — but they have different, complementary uses. TypeScript generally limits itself to typechecking, while ESLint can catch a broad variety of other errors, from simple oversights like expressions that do nothing or comparing a value to itself, to technically legal but dangerous syntax, to analysis of possible race conditions. The typescript-eslint project not only enables ESLint to parse and validate TypeScript code directly, it adds support for a wide range of TypeScript-specific lints and error-checking not covered by the TypeScript compiler. In fact, the TypeScript developers use ESLint and typescript-eslint on their own codebase! (Another tool called TSLint formerly fulfilled a similar role for TypeScript, but it's been deprecated for a while now in favour of ESLint.)
eslint-config-lostfictions
is based on a few key principles:
After untold numbers of code reviews nitpicking whitespace or semicolons, programmers are finally coming around to the idea that it's usually easier to let the computer fix those things for you. A consistent team-wide code style helps to improve readability and avoid bikeshedding that arises from minor differences in opinion, but time and experience have shown that the ideal way to enforce style is via editor tooling and runnning checks in continuous integration. (Who cares about "tabs versus spaces" if you can treat leading whitespace as tabstops on your machine but save them to disk as spaces?)
Languages like Go and Rust make things easy here by integrating opinionated formatters in their toolchain. In JavaScript-land, there are two main options for formatting: ESLint and Prettier. Both are viable, but I've found that Prettier is much easier to configure, more consistent, and allows for a better separation of concerns.
(For example, when saving a file in your editor you may want to automatically reformat your code, but you may not want to simultaneously "auto-fix" other linter warnings, since these "fixes" occasionally change the semantics of your code or erase some intermediate work you've done. This is a lot harder when using ESLint as both a formatter and linter. ESLint also tends to give you angry messages if a line of text is too long or it detects some other whitespace or formatting issue, which can mask other more important lints.)
eslint-config-lostfictions
assumes that you're using Prettier. All ESLint
whitespace and formatting rules are turned off via
eslint-config-prettier
.
Some popular ESLint configs like to scream at you at maximum volume for every possible variety of included lint. Again, in my experience, this can result in a lot of noise that masks other more important problems, such as typechecker failures, semantic issues, and parsing errors.
By contrast, eslint-config-lostfictions
tries to reserve the "error" lint
level for genuine suspected errors and prefers warnings for lesser code smells
and minor issues.
For example, no-lonely-if
is a
warning. A lonely if
may be somewhat unidiomatic JavaScript, but by itself
it does not represent a semantic issue. On the other hand,
no-self-compare
is an
error. There is almost no imaginable circumstance where you would want to
compare a value to itself, so it very likely represents an oversight that will
lead to unintended behaviour in your code.
All that said, for the same reason you should use a formatter, it's a good
idea to treat warnings as errors in your CI to ensure warnings get fixed
before a pull request can be merged. You can use the ESLint CLI option
--max-warnings=0
to enforce this.
npm i -D eslint eslint-config-lostfictions
# or
yarn add -D eslint eslint-config-lostfictions
eslint-config-lostfictions
bundles all its required plugins and parsers as
dependencies. Since ESLint doesn't yet directly support bundling plugins in a
config in this way (the feature request for
it is by far the most upvoted
open issue in the ESLint repo), eslint-config-lostfictions
also re-exports
@rushstack/eslint-patch
.
You'll need to require
it in your ESLint config like this:
.eslintrc.js
require("eslint-config-lostfictions/patch");
/** @type {import("eslint-config-lostfictions").Config} */
module.exports = {
extends: ["lostfictions"],
parserOptions: { tsconfigRootDir: __dirname },
};
For React projects, use the lostfictions/react
config, which adds additional
React-specific plugins and rules:
require("eslint-config-lostfictions/patch");
/** @type {import("eslint-config-lostfictions").Config} */
module.exports = {
--- extends: ["lostfictions"],
+++ extends: ["lostfictions/react"],
parserOptions: { tsconfigRootDir: __dirname }
};
Since we're require
ing a module in the config, this obviously means you need
to use the .eslintrc.js
config format rather than JSON, YAML, etc.
eslint-config-lostfictions
also includes
eslint-plugin-jest
for
linting your tests (including helpful rules like
expect-expect
,
which ensures you haven't forgotten to make assertions in your test cases). By
default the extra Jest rules are enabled for files with a
.test.{js,jsx,ts,tsx}
suffix, as well as files under a test
folder — which
should match Jest's default rules for finding tests.
If you're using an editor integration like
vscode-eslint, typescript-eslint
may complain about any files not listed in your tsconfig.json
being unlintable
(including .config.js
files, etc). This is not the fault of
eslint-config-lostfictions
; it's a quirk of typescript-eslint
's type-aware
linting. There are a few solutions to this:
You can safely ignore these warnings and (at least in VS Code) they'll go away when you close the file. Often you don't care too much about linting a config file in your project root.
If you don't want to lint the files in question but are annoyed by the
warning, add them to a .eslintignore
file, to an ignorePatterns
field in
.eslintrc.js
, or via any other method ESLint offers for ignoring
code.
(eslint-config-lostfictions
already excludes .eslintrc.js
itself from
linting.)
If you do want to lint these files, add them to your tsconfig.json
via the
include
or files
field. If you do this, note that TypeScript may include
these files for transpilation if you're using TypeScript as a transpiler
rather than purely as a typechecker (typecheck-only mode is typical for
Babel/SWC/esbuild-based setups, including create-react-app and Next.js).
If transpiling them isn't what you want, you may need to introduce an
additional ESLint-specific tsconfig.json
to your project. It can be named
something like tsconfig.eslint.json
and can
inherit from your existing
tsconfig.json
. You should only need to additionally specify
noEmit: true
and the extra
files to lint. You can then point the typescript-eslint
parser at the new
tsconfig file via the project
field
under parserOptions
in your .eslintrc.js
.
See typescript-eslint's documentation for further explanation about this warning and example configurations that fix it.
Array#at()
and String#at()
unicorn/prefer-at
and
are both enabled in this config.prefer-object-has-own
(EDIT: Object.hasOwn
doesn't have support
yet in TypeScript's lib.d.ts
, so we're waiting for that. See the tracking
issue.)
The respective functions they recommend are cleaner and less error-prone than
their older alternatives, but they're both pretty fresh at the moment.
Object.hasOwn()
shipped in Node
16.9.0
(2021-09-07).
String#at()
and
Array#at()
shipped in Node
16.6.0
(2021-07-29). If you're stuck on an older version of Node, you may prefer to
disable these rules. These functions have shipped in all evergreen browsers and
should be polyfilled by frontend tools that incorporate core-js polyfills
(Next.js, CRA) if your browserslist config indicates that support is required.
in
operatorThe in
operator
has a number of pitfalls that can make it tricky to use. Using an object with
arbitrary string keys can be a code smell if there's any possibility the keys
are user-provided — this can be a source of prototype
poisoning,
and even solutions like Object.create(null)
aren't foolproof (and create new
pitfalls of their own). For this reason, it's recommended to use a Map
or
Set
when working with arbitrary keys.
However, the in
operator is often more ergonomic than the more "correct"
alternatives and works as a type guard in TypeScript where other forms of
membership checking do not. For example, given this type declaration:
type XorY = { x: string } | { y: number };
let thing: XorY;
This code will typecheck correctly:
if ("x" in thing) {
// narrowed to { x: string } in this block
console.log(thing.x);
} else {
// narrowed to { y: number } in this block
console.log(thing.y + 3);
}
But this will not:
if (Object.prototype.hasOwnProperty.call(thing, "x")) {
// ERROR: Property 'x' does not exist on type 'XorY'.
// Property 'x' does not exist on type '{ y: number; }'.
console.log(thing.x);
}
For these reasons, eslint-config-lostfictions
warns when using the in
operator, unless the left-hand operand is a string literal. This should catch
a majority of code-smell cases while still permitting the relatively safer case
of using in
to narrow a union of TypeScript types.
Keep in mind that the preferred way to narrow non-literal union types is the use
of a discriminant property. (For example, the kind
property in
type Shape = { kind: 'circle'; radius: number } | { kind: 'square'; size: number }
is a discriminant.) Discriminants sidestep the need to reach for something like
in
in the first place.
process.env
As noted in eslint-plugin-node's no-process-env
rule,
Node's
process.env
is effectively a kind of global mutable variable. But even if you don't mutate
it, spreading it around your codebase can make it difficult to reason about your
application's configuration. Instead, it's recommended to declare and validate
all your configuration up-front in a single file, and then export those
validated bindings for use across your application. (Something like
znv could help you with this.)
no-process-env
is thus enabled by default, with the expectation that you'll
disable it in the file that handles your app configuration. This might be a bit
noisy for brownfield projects that don't already follow the
single-point-of-declaration convention, but in my experience it's worth it to
clean up those stray uses of process.env
.
for-of
vs. forEach()
forEach()
methods — mainly Array#forEach()
, though equivalents also exist
for Maps, Sets, TypedArrays, and some "array-like" DOM entities — are a holdover
from an earlier age of JavaScript. Before the block-scoped declarations let
and const
became widely supported, iteration blocks were either clunky or
risky to use. Even a simple for(var i = 0; i < x; i++)
often needed its body
wrapped in an IIFE. In
these dire circumstances, forEach()
emerged as a more elegant and humane
alternative for iteration.
Fortunately, things are better for JavaScript these days, and for-of
loops are
generally a simpler and more readable construct. Every built-in with a
forEach()
method also supports iteration via for-of
.
Digging a bit deeper, forEach()
has some issues in that it's imperative but
looks functional; it can sometimes be tempting to add it at the end of a chain
of array .map()
and .filter()
calls. Unfortunately, the resulting code is
generally the worst of both worlds, with none of the benefits of truly
functional code but all of the drawbacks.
In this config, the rule forbidding forEach()
comes by way of
eslint-plugin-unicorn,
but Github's ESLint docs about
forEach()
go into more detail and outline some further compelling reasons to avoid it.
FAQs
Unknown package
The npm package eslint-config-lostfictions receives a total of 4 weekly downloads. As such, eslint-config-lostfictions popularity was classified as not popular.
We found that eslint-config-lostfictions demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Tea.xyz, a crypto project aimed at rewarding open source contributions, is once again facing backlash due to an influx of spam packages flooding public package registries.
Security News
As cyber threats become more autonomous, AI-powered defenses are crucial for businesses to stay ahead of attackers who can exploit software vulnerabilities at scale.
Security News
UnitedHealth Group disclosed that the ransomware attack on Change Healthcare compromised protected health information for millions in the U.S., with estimated costs to the company expected to reach $1 billion.