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
  • Loading branch information
giltayar committed Feb 4, 2022
1 parent b072e22 commit 2dd5161
Show file tree
Hide file tree
Showing 30 changed files with 193 additions and 231 deletions.
3 changes: 2 additions & 1 deletion .nycrc
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
81 changes: 37 additions & 44 deletions README.md
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,8 +55,8 @@ $ 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
Expand Down Expand Up @@ -133,48 +126,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 +177,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.
23 changes: 0 additions & 23 deletions docs/rules/file-extension-in-import.md
Expand Up @@ -27,7 +27,6 @@ This rule has a string option and an object option.
"error",
"always" or "never",
{
"tryExtensions": [".js", ".json", ".node"],
".xxx": "always" or "never",
}
]
Expand All @@ -36,7 +35,6 @@ This rule has a string option and an object option.

- `"always"` (default) requires file extensions in `import`/`export` declarations.
- `"never"` disallows file extensions in `import`/`export` declarations.
- `tryExtensions` is the file extensions to resolve import paths. Default is `[".js", ".json", ".node"]`.
- `.xxx` is the overriding setting for specific file extensions. You can use arbitrary property names which start with `.`.

#### always
Expand Down Expand Up @@ -90,27 +88,6 @@ import styles from "./styles.css"
import logo from "./logo.png"
```

### Shared Settings

The following options can be set by [shared settings](http://eslint.org/docs/user-guide/configuring.html#adding-shared-settings).
Several rules have the same option, but we can set this option at once.

- `tryExtensions`

```js
// .eslintrc.js
module.exports = {
"settings": {
"node": {
"tryExtensions": [".js", ".json", ".node"]
}
},
"rules": {
"n/file-extension-in-import": "error"
}
}
```

## 🔎 Implementation

- [Rule source](../../lib/rules/file-extension-in-import.js)
Expand Down
12 changes: 1 addition & 11 deletions docs/rules/no-extraneous-import.md
Expand Up @@ -16,8 +16,7 @@ This rule warns `import` declarations of extraneous modules.
"rules": {
"n/no-extraneous-import": ["error", {
"allowModules": [],
"resolvePaths": [],
"tryExtensions": []
"resolvePaths": []
}]
}
}
Expand Down Expand Up @@ -48,21 +47,13 @@ If a path is relative, it will be resolved from CWD.

Default is `[]`

#### tryExtensions

When an import path does not exist, this rule checks whether or not any of `path.js`, `path.json`, and `path.node` exists.
`tryExtensions` option is the extension list this rule uses at the time.

Default is `[".js", ".json", ".node"]`.

### Shared Settings

The following options can be set by [shared settings](http://eslint.org/docs/user-guide/configuring.html#adding-shared-settings).
Several rules have the same option, but we can set this option at once.

- `allowModules`
- `resolvePaths`
- `tryExtensions`

```js
// .eslintrc.js
Expand All @@ -71,7 +62,6 @@ module.exports = {
"node": {
"allowModules": ["electron"],
"resolvePaths": [__dirname],
"tryExtensions": [".js", ".json", ".node"]
}
},
"rules": {
Expand Down
12 changes: 1 addition & 11 deletions docs/rules/no-missing-import.md
Expand Up @@ -36,8 +36,7 @@ import existingModule from "existing-module";
"rules": {
"n/no-missing-import": ["error", {
"allowModules": [],
"resolvePaths": ["/path/to/a/modules/directory"],
"tryExtensions": [".js", ".json", ".node"]
"resolvePaths": ["/path/to/a/modules/directory"]
}]
}
}
Expand Down Expand Up @@ -68,21 +67,13 @@ If a path is relative, it will be resolved from CWD.

Default is `[]`

#### tryExtensions

When an import path does not exist, this rule checks whether or not any of `path.js`, `path.json`, and `path.node` exists.
`tryExtensions` option is the extension list this rule uses at the time.

Default is `[".js", ".json", ".node"]`.

### Shared Settings

The following options can be set by [shared settings](http://eslint.org/docs/user-guide/configuring.html#adding-shared-settings).
Several rules have the same option, but we can set this option at once.

- `allowModules`
- `resolvePaths`
- `tryExtensions`

```js
// .eslintrc.js
Expand All @@ -91,7 +82,6 @@ module.exports = {
"node": {
"allowModules": ["electron"],
"resolvePaths": [__dirname],
"tryExtensions": [".js", ".json", ".node"]
}
},
"rules": {
Expand Down
17 changes: 3 additions & 14 deletions docs/rules/no-unpublished-import.md
Expand Up @@ -25,8 +25,7 @@ Then this rule warns `import` declarations in \*published\* files if the `import
"rules": {
"n/no-unpublished-import": ["error", {
"allowModules": [],
"convertPath": null,
"tryExtensions": [".js", ".json", ".node"]
"convertPath": null
}]
}
}
Expand Down Expand Up @@ -63,8 +62,7 @@ For example:
"n/no-unpublished-import": ["error", {
"convertPath": {
"src/**/*.jsx": ["^src/(.+?)\\.jsx$", "lib/$1.js"]
},
"tryExtensions": [".js", ".jsx", ".json"]
}
}]
}
}
Expand Down Expand Up @@ -104,21 +102,13 @@ For example:
In this style, this option has the following shape as the same expression as above: `{include: [<targetFiles>], replace: [<fromRegExp>, <toString>]}`.
In addition, we can specify glob patterns to exclude files.

#### tryExtensions

When an import path does not exist, this rule checks whether or not any of `path.js`, `path.json`, and `path.node` exists.
`tryExtensions` option is the extension list this rule uses at the time.

Default is `[".js", ".json", ".node"]`.

### Shared Settings

The following options can be set by [shared settings](http://eslint.org/docs/user-guide/configuring.html#adding-shared-settings).
Several rules have the same option, but we can set this option at once.

- `allowModules`
- `convertPath`
- `tryExtensions`

For Example:

Expand All @@ -129,8 +119,7 @@ For Example:
"allowModules": ["electron"],
"convertPath": {
"src/**/*.jsx": ["^src/(.+?)\\.jsx$", "lib/$1.js"]
},
"tryExtensions": [".js", ".jsx", ".json"]
}
}
},
"rules": {
Expand Down
11 changes: 2 additions & 9 deletions lib/rules/file-extension-in-import.js
Expand Up @@ -6,7 +6,6 @@

const path = require("path")
const fs = require("fs")
const getTryExtensions = require("../util/get-try-extensions")
const visitImport = require("../util/visit-import")
const packageNamePattern = /^(?:@[^/\\]+[/\\])?[^/\\]+$/u
const corePackageOverridePattern =
Expand Down Expand Up @@ -52,9 +51,7 @@ module.exports = {
},
{
type: "object",
properties: {
tryExtensions: getTryExtensions.schema,
},
properties: {},
additionalProperties: {
enum: ["always", "never"],
},
Expand Down Expand Up @@ -83,11 +80,7 @@ module.exports = {
const originalExt = path.extname(name)
const resolvedExt = path.extname(filePath)
const existingExts = getExistingExtensions(filePath)
if (!resolvedExt && existingExts.length !== 1) {
// Ignore if the file extension could not be determined one.
return
}
const ext = resolvedExt || existingExts[0]
const ext = resolvedExt || existingExts.join(" or ")
const style = overrideStyle[ext] || defaultStyle

// Verify.
Expand Down
2 changes: 0 additions & 2 deletions lib/rules/no-extraneous-import.js
Expand Up @@ -8,7 +8,6 @@ const checkExtraneous = require("../util/check-extraneous")
const getAllowModules = require("../util/get-allow-modules")
const getConvertPath = require("../util/get-convert-path")
const getResolvePaths = require("../util/get-resolve-paths")
const getTryExtensions = require("../util/get-try-extensions")
const visitImport = require("../util/visit-import")

module.exports = {
Expand All @@ -29,7 +28,6 @@ module.exports = {
allowModules: getAllowModules.schema,
convertPath: getConvertPath.schema,
resolvePaths: getResolvePaths.schema,
tryExtensions: getTryExtensions.schema,
},
additionalProperties: false,
},
Expand Down
11 changes: 7 additions & 4 deletions lib/rules/no-hide-core-modules.js
Expand Up @@ -10,8 +10,10 @@

const path = require("path")
const resolve = require("resolve")
const {pathToFileURL, fileURLToPath} = require('url')
const {defaultResolve: importResolve} = require("../converted-esm/import-meta-resolve")
const { pathToFileURL, fileURLToPath } = require("url")
const {
defaultResolve: importResolve,
} = require("../converted-esm/import-meta-resolve")
const getPackageJson = require("../util/get-package-json")
const mergeVisitorsInPlace = require("../util/merge-visitors-in-place")
const visitImport = require("../util/visit-import")
Expand Down Expand Up @@ -129,13 +131,14 @@ module.exports = {
let resolved = ""
const moduleId = `${name}/`
try {

resolved = resolve.sync(moduleId, {
basedir: dirPath,
})
} catch (_error) {
try {
const {url} = importResolve(moduleId, {parentURL: pathToFileURL(dirPath).href})
const { url } = importResolve(moduleId, {
parentURL: pathToFileURL(dirPath).href,
})

resolved = fileURLToPath(url)
} catch (_error) {
Expand Down

0 comments on commit 2dd5161

Please sign in to comment.