Skip to content

Commit

Permalink
invalidate ESM imports that were valid in Node 10
Browse files Browse the repository at this point in the history
oopsi
  • Loading branch information
giltayar committed Jan 28, 2022
1 parent b072e22 commit 09108d7
Show file tree
Hide file tree
Showing 66 changed files with 5,413 additions and 4,573 deletions.
3 changes: 2 additions & 1 deletion .nycrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
],
"exclude": [
"lib/rules/no-hide-core-modules.js",
"lib/rules/no-unsupported-features.js"
"lib/rules/no-unsupported-features.js",
"lib/converted-esm/*.js"
],
"reporter": [
"lcov",
Expand Down
96 changes: 45 additions & 51 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@

> forked from [eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node) v11.1.0. as the original repository seems [no longer maintained](https://github.com/mysticatea/eslint-plugin-node/issues/300).
[![npm version](https://img.shields.io/npm/v/eslint-plugin-n.svg)](https://www.npmjs.com/package/eslint-plugin-n)
[![Downloads/month](https://img.shields.io/npm/dm/eslint-plugin-n.svg)](http://www.npmtrends.com/eslint-plugin-n)
[![Build Status](https://github.com/weiran-zsd/eslint-plugin-node/workflows/CI/badge.svg)](https://github.com/weiran-zsd/eslint-plugin-node/actions)
[![Coverage Status](https://codecov.io/gh/weiran-zsd/eslint-plugin-node/branch/master/graph/badge.svg)](https://codecov.io/gh/weiran-zsd/eslint-plugin-node)
[![Dependency Status](https://david-dm.org/weiran-zsd/eslint-plugin-node.svg)](https://david-dm.org/weiran-zsd/eslint-plugin-node)
[![npm version](https://img.shields.io/npm/v/eslint-plugin-n.svg)](https://www.npmjs.com/package/eslint-plugin-n) [![Downloads/month](https://img.shields.io/npm/dm/eslint-plugin-n.svg)](http://www.npmtrends.com/eslint-plugin-n) [![Build Status](https://github.com/weiran-zsd/eslint-plugin-node/workflows/CI/badge.svg)](https://github.com/weiran-zsd/eslint-plugin-node/actions) [![Coverage Status](https://codecov.io/gh/weiran-zsd/eslint-plugin-node/branch/master/graph/badge.svg)](https://codecov.io/gh/weiran-zsd/eslint-plugin-node) [![Dependency Status](https://david-dm.org/weiran-zsd/eslint-plugin-node.svg)](https://david-dm.org/weiran-zsd/eslint-plugin-node)

Additional ESLint's rules for Node.js

Expand All @@ -16,19 +12,16 @@ Additional ESLint's rules for Node.js
$ npm install --save-dev eslint eslint-plugin-n
```

- Requires Node.js `>=12.22.0`
- Requires ESLint `>=7.0.0`
- Requires Node.js `>=12.22.0`
- Requires ESLint `>=7.0.0`

**Note:** It recommends a use of [the "engines" field of package.json](https://docs.npmjs.com/files/package.json#engines). The "engines" field is used by `n/no-unsupported-features/*` rules.

**.eslintrc.json** (An example)

```jsonc
{
"extends": [
"eslint:recommended",
"plugin:n/recommended"
],
"extends": ["eslint:recommended", "plugin:n/recommended"],
"parserOptions": {
// Only ESLint 6.2.0 and later support ES2020.
"ecmaVersion": 2020
Expand Down Expand Up @@ -62,14 +55,15 @@ $ npm install --save-dev eslint eslint-plugin-n

## 📖 Rules

- ⭐️ - the mark of recommended rules.
- ✒️ - the mark of fixable rules.
- ⭐️ - the mark of recommended rules.
- ✒️ - the mark of fixable rules.

<!--RULES_TABLE_START-->

### Possible Errors

| Rule ID | Description | |
|:--------|:------------|:--:|
| Rule ID | Description | |
| :-- | :-- | :-: |
| [n/handle-callback-err](./docs/rules/handle-callback-err.md) | require error handling in callbacks | |
| [n/no-callback-literal](./docs/rules/no-callback-literal.md) | ensure Node.js-style error-first callback pattern is followed | |
| [n/no-exports-assign](./docs/rules/no-exports-assign.md) | disallow the assignment to `exports` | ⭐️ |
Expand All @@ -91,14 +85,14 @@ $ npm install --save-dev eslint eslint-plugin-n

### Best Practices

| Rule ID | Description | |
|:--------|:------------|:--:|
| Rule ID | Description | |
| :-- | :-- | :-: |
| [n/no-deprecated-api](./docs/rules/no-deprecated-api.md) | disallow deprecated APIs | ⭐️ |

### Stylistic Issues

| Rule ID | Description | |
|:--------|:------------|:--:|
| Rule ID | Description | |
| :-- | :-- | :-: |
| [n/callback-return](./docs/rules/callback-return.md) | require `return` statements after callbacks | |
| [n/exports-style](./docs/rules/exports-style.md) | enforce either `module.exports` or `exports` | |
| [n/file-extension-in-import](./docs/rules/file-extension-in-import.md) | enforce the style of file extensions in `import` declarations | ✒️ |
Expand All @@ -123,7 +117,7 @@ $ npm install --save-dev eslint eslint-plugin-n
These rules have been deprecated in accordance with the [deprecation policy](https://eslint.org/docs/user-guide/rule-deprecation), and replaced by newer rules:

| Rule ID | Replaced by |
|:--------|:------------|
| :-- | :-- |
| [n/no-hide-core-modules](./docs/rules/no-hide-core-modules.md) | (nothing) |
| [n/no-unsupported-features](./docs/rules/no-unsupported-features.md) | [n/no-unsupported-features/es-syntax](./docs/rules/no-unsupported-features/es-syntax.md) and [n/no-unsupported-features/es-builtins](./docs/rules/no-unsupported-features/es-builtins.md) |

Expand All @@ -133,48 +127,48 @@ These rules have been deprecated in accordance with the [deprecation policy](htt

This plugin provides three configs:

- `plugin:n/recommended` considers both CommonJS and ES Modules. If [`"type":"module"` field](https://medium.com/@nodejs/announcing-a-new-experimental-modules-1be8d2d6c2ff#b023) existed in package.json then it considers files as ES Modules. Otherwise it considers files as CommonJS. In addition, it considers `*.mjs` files as ES Modules and `*.cjs` files as CommonJS.
- `plugin:n/recommended-module` considers all files as ES Modules.
- `plugin:n/recommended-script` considers all files as CommonJS.
- `plugin:n/recommended` considers both CommonJS and ES Modules. If [`"type":"module"` field](https://medium.com/@nodejs/announcing-a-new-experimental-modules-1be8d2d6c2ff#b023) existed in package.json then it considers files as ES Modules. Otherwise it considers files as CommonJS. In addition, it considers `*.mjs` files as ES Modules and `*.cjs` files as CommonJS.
- `plugin:n/recommended-module` considers all files as ES Modules.
- `plugin:n/recommended-script` considers all files as CommonJS.

Those preset config:

- enable [no-process-exit](http://eslint.org/docs/rules/no-process-exit) rule because [the official document](https://nodejs.org/api/process.html#process_process_exit_code) does not recommend a use of `process.exit()`.
- enable plugin rules which are given :star: in the above table.
- add `{ecmaVersion: 2019}` and etc into `parserOptions`.
- add proper globals into `globals`.
- add this plugin into `plugins`.
- enable [no-process-exit](http://eslint.org/docs/rules/no-process-exit) rule because [the official document](https://nodejs.org/api/process.html#process_process_exit_code) does not recommend a use of `process.exit()`.
- enable plugin rules which are given :star: in the above table.
- add `{ecmaVersion: 2019}` and etc into `parserOptions`.
- add proper globals into `globals`.
- add this plugin into `plugins`.

## 👫 FAQ

- Q: The `no-missing-import` / `no-missing-require` rules don't work with nested folders in SublimeLinter-eslint
- A: See [context.getFilename() in rule returns relative path](https://github.com/roadhump/SublimeLinter-eslint#contextgetfilename-in-rule-returns-relative-path) in the SublimeLinter-eslint FAQ.
- Q: The `no-missing-import` / `no-missing-require` rules don't work with nested folders in SublimeLinter-eslint
- A: See [context.getFilename() in rule returns relative path](https://github.com/roadhump/SublimeLinter-eslint#contextgetfilename-in-rule-returns-relative-path) in the SublimeLinter-eslint FAQ.

## 🚥 Semantic Versioning Policy

`eslint-plugin-n` follows [semantic versioning](http://semver.org/) and [ESLint's Semantic Versioning Policy](https://github.com/eslint/eslint#semantic-versioning-policy).

- Patch release (intended to not break your lint build)
- A bug fix in a rule that results in it reporting fewer errors.
- Improvements to documentation.
- Non-user-facing changes such as refactoring code, adding, deleting, or modifying tests, and increasing test coverage.
- Re-releasing after a failed release (i.e., publishing a release that doesn't work for anyone).
- Minor release (might break your lint build)
- A bug fix in a rule that results in it reporting more errors.
- A new rule is created.
- A new option to an existing rule is created.
- An existing rule is deprecated.
- Major release (likely to break your lint build)
- A support for old Node version is dropped.
- A support for old ESLint version is dropped.
- An existing rule is changed in it reporting more errors.
- An existing rule is removed.
- An existing option of a rule is removed.
- An existing config is updated.
- Patch release (intended to not break your lint build)
- A bug fix in a rule that results in it reporting fewer errors.
- Improvements to documentation.
- Non-user-facing changes such as refactoring code, adding, deleting, or modifying tests, and increasing test coverage.
- Re-releasing after a failed release (i.e., publishing a release that doesn't work for anyone).
- Minor release (might break your lint build)
- A bug fix in a rule that results in it reporting more errors.
- A new rule is created.
- A new option to an existing rule is created.
- An existing rule is deprecated.
- Major release (likely to break your lint build)
- A support for old Node version is dropped.
- A support for old ESLint version is dropped.
- An existing rule is changed in it reporting more errors.
- An existing rule is removed.
- An existing option of a rule is removed.
- An existing config is updated.

## 📰 Changelog

- [GitHub Releases](https://github.com/weiran-zsd/eslint-plugin-n/releases)
- [GitHub Releases](https://github.com/weiran-zsd/eslint-plugin-n/releases)

## ❤️ Contributing

Expand All @@ -184,6 +178,6 @@ Please use GitHub's Issues/PRs.

### Development Tools

- `npm test` runs tests and measures coverage.
- `npm run coverage` shows the coverage result of `npm test` command.
- `npm run clean` removes the coverage result of `npm test` command.
- `npm test` runs tests and measures coverage.
- `npm run coverage` shows the coverage result of `npm test` command.
- `npm run clean` removes the coverage result of `npm test` command.
72 changes: 34 additions & 38 deletions docs/rules/callback-return.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,23 @@
# n/callback-return

> require `return` statements after callbacks
The callback pattern is at the heart of most I/O and event-driven programming
in JavaScript.
The callback pattern is at the heart of most I/O and event-driven programming in JavaScript.

```js
function doSomething(err, callback) {
if (err) {
return callback(err);
return callback(err)
}
callback();
callback()
}
```

To prevent calling the callback multiple times it is important to `return` anytime the callback is triggered outside
of the main function body. Neglecting this technique often leads to issues where you do something more than once.
For example, in the case of an HTTP request, you may try to send HTTP headers more than once leading Node.js to `throw`
a `Can't render headers after they are sent to the client.` error.
To prevent calling the callback multiple times it is important to `return` anytime the callback is triggered outside of the main function body. Neglecting this technique often leads to issues where you do something more than once. For example, in the case of an HTTP request, you may try to send HTTP headers more than once leading Node.js to `throw` a `Can't render headers after they are sent to the client.` error.

## 📖 Rule Details

This rule is aimed at ensuring that callbacks used outside of the main function block are always part-of or immediately
preceding a `return` statement. This rule decides what is a callback based on the name of the function being called.
This rule is aimed at ensuring that callbacks used outside of the main function block are always part-of or immediately preceding a `return` statement. This rule decides what is a callback based on the name of the function being called.

### Options

Expand All @@ -36,9 +32,9 @@ Examples of **incorrect** code for this rule with the default `["callback", "cb"

function foo(err, callback) {
if (err) {
callback(err);
callback(err)
}
callback();
callback()
}
```

Expand All @@ -49,9 +45,9 @@ Examples of **correct** code for this rule with the default `["callback", "cb",

function foo(err, callback) {
if (err) {
return callback(err);
return callback(err)
}
callback();
callback()
}
```

Expand All @@ -64,16 +60,16 @@ Examples of **incorrect** code for this rule with the option `["done", "send.err

function foo(err, done) {
if (err) {
done(err);
done(err)
}
done();
done()
}

function bar(err, send) {
if (err) {
send.error(err);
send.error(err)
}
send.success();
send.success()
}
```

Expand All @@ -84,81 +80,81 @@ Examples of **correct** code for this rule with the option `["done", "send.error

function foo(err, done) {
if (err) {
return done(err);
return done(err)
}
done();
done()
}

function bar(err, send) {
if (err) {
return send.error(err);
return send.error(err)
}
send.success();
send.success()
}
```

### Known Limitations

Because it is difficult to understand the meaning of a program through static analysis, this rule has limitations:

* *false negatives* when this rule reports correct code, but the program calls the callback more than one time (which is incorrect behavior)
* *false positives* when this rule reports incorrect code, but the program calls the callback only one time (which is correct behavior)
- _false negatives_ when this rule reports correct code, but the program calls the callback more than one time (which is incorrect behavior)
- _false positives_ when this rule reports incorrect code, but the program calls the callback only one time (which is correct behavior)

#### Passing the callback by reference

The static analysis of this rule does not detect that the program calls the callback if it is an argument of a function (for example, `setTimeout`).
The static analysis of this rule does not detect that the program calls the callback if it is an argument of a function (for example, `setTimeout`).

Example of a *false negative* when this rule reports correct code:
Example of a _false negative_ when this rule reports correct code:

```js
/*eslint callback-return: "error"*/

function foo(err, callback) {
if (err) {
setTimeout(callback, 0); // this is bad, but WILL NOT warn
setTimeout(callback, 0) // this is bad, but WILL NOT warn
}
callback();
callback()
}
```

#### Triggering the callback within a nested function

The static analysis of this rule does not detect that the program calls the callback from within a nested function or an immediately-invoked function expression (IIFE).

Example of a *false negative* when this rule reports correct code:
Example of a _false negative_ when this rule reports correct code:

```js
/*eslint callback-return: "error"*/

function foo(err, callback) {
if (err) {
process.nextTick(function() {
return callback(); // this is bad, but WILL NOT warn
});
process.nextTick(function () {
return callback() // this is bad, but WILL NOT warn
})
}
callback();
callback()
}
```

#### If/else statements

The static analysis of this rule does not detect that the program calls the callback only one time in each branch of an `if` statement.

Example of a *false positive* when this rule reports incorrect code:
Example of a _false positive_ when this rule reports incorrect code:

```js
/*eslint callback-return: "error"*/

function foo(err, callback) {
if (err) {
callback(err); // this is fine, but WILL warn
callback(err) // this is fine, but WILL warn
} else {
callback(); // this is fine, but WILL warn
callback() // this is fine, but WILL warn
}
}
```

## 🔎 Implementation

- [Rule source](../../lib/rules/callback-return.js)
- [Test source](../../tests/lib/rules/callback-return.js)
- [Rule source](../../lib/rules/callback-return.js)
- [Test source](../../tests/lib/rules/callback-return.js)

0 comments on commit 09108d7

Please sign in to comment.