Skip to content

Commit 2061413

Browse files
committedMay 2, 2019
💥 update node/recommended
1 parent 9006518 commit 2061413

14 files changed

+344
-87
lines changed
 

‎README.md

+16-9
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ $ npm install --save-dev eslint eslint-plugin-node
2323

2424
```json
2525
{
26-
"extends": ["eslint:recommended", "plugin:node/recommended"],
26+
"extends": [
27+
"eslint:recommended",
28+
"plugin:node/recommended"
29+
],
2730
"rules": {
2831
"node/exports-style": ["error", "module.exports"],
2932
"node/prefer-global/buffer": ["error", "always"],
@@ -102,15 +105,19 @@ These rules have been deprecated in accordance with the [deprecation policy](htt
102105

103106
## 🔧 Configs
104107

105-
This plugin provides `plugin:node/recommended` preset config.
106-
This preset config:
108+
This plugin provides three configs:
107109

108-
- enables the environment of ES2015 (ES6) and Node.js.
109-
- enables rules which are given :star: in the above table.
110-
- enables [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()`.
111-
- adds `{ecmaVersion: 2019}` into `parserOptions`.
112-
- adds `Atomics` and `SharedArrayBuffer` into `globals`.
113-
- adds this plugin into `plugins`.
110+
- `plugin:node/recommended` condiders 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.
111+
- `plugin:node/recommended-module` considers all files as ES Modules.
112+
- `plugin:node/recommended-script` considers all files as CommonJS.
113+
114+
Those preset config:
115+
116+
- 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()`.
117+
- enable plugin rules which are given :star: in the above table.
118+
- add `{ecmaVersion: 2019}` and etc into `parserOptions`.
119+
- add proper globals into `globals`.
120+
- add this plugin into `plugins`.
114121

115122
## 👫 FAQ
116123

‎lib/configs/_commons.js

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
"use strict"
2+
3+
module.exports = {
4+
commonGlobals: {
5+
// ECMAScript
6+
ArrayBuffer: "readonly",
7+
Atomics: "readonly",
8+
DataView: "readonly",
9+
Float32Array: "readonly",
10+
Float64Array: "readonly",
11+
Int16Array: "readonly",
12+
Int32Array: "readonly",
13+
Int8Array: "readonly",
14+
Map: "readonly",
15+
Promise: "readonly",
16+
Proxy: "readonly",
17+
Reflect: "readonly",
18+
Set: "readonly",
19+
SharedArrayBuffer: "readonly",
20+
Symbol: "readonly",
21+
Uint16Array: "readonly",
22+
Uint32Array: "readonly",
23+
Uint8Array: "readonly",
24+
Uint8ClampedArray: "readonly",
25+
WeakMap: "readonly",
26+
WeakSet: "readonly",
27+
28+
// ECMAScript (experimental)
29+
BigInt: "readonly",
30+
BigInt64Array: "readonly",
31+
BigUint64Array: "readonly",
32+
globalThis: "readonly",
33+
34+
// ECMA-404
35+
Intl: "readonly",
36+
37+
// Web Standard
38+
TextDecoder: "readonly",
39+
TextEncoder: "readonly",
40+
URL: "readonly",
41+
URLSearchParams: "readonly",
42+
WebAssembly: "readonly",
43+
clearInterval: "readonly",
44+
clearTimeout: "readonly",
45+
console: "readonly",
46+
queueMicrotask: "readonly",
47+
setInterval: "readonly",
48+
setTimeout: "readonly",
49+
50+
// Node.js
51+
Buffer: "readonly",
52+
GLOBAL: "readonly",
53+
clearImmediate: "readonly",
54+
global: "readonly",
55+
process: "readonly",
56+
root: "readonly",
57+
setImmediate: "readonly",
58+
},
59+
commonRules: {
60+
"no-process-exit": "error",
61+
"node/no-deprecated-api": "error",
62+
"node/no-extraneous-require": "error",
63+
"node/no-missing-require": "error",
64+
"node/no-unpublished-bin": "error",
65+
"node/no-unpublished-require": "error",
66+
"node/no-unsupported-features/es-builtins": "error",
67+
"node/no-unsupported-features/es-syntax": "error",
68+
"node/no-unsupported-features/node-builtins": "error",
69+
"node/process-exit-as-throw": "error",
70+
"node/shebang": "error",
71+
},
72+
}

‎lib/configs/recommended-module.js

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
"use strict"
2+
3+
const { commonGlobals, commonRules } = require("./_commons")
4+
5+
module.exports = {
6+
globals: {
7+
...commonGlobals,
8+
__dirname: "off",
9+
__filename: "off",
10+
exports: "off",
11+
module: "off",
12+
require: "off",
13+
},
14+
parserOptions: {
15+
ecmaFeatures: { globalReturn: false },
16+
ecmaVersion: 2019,
17+
sourceType: "module",
18+
},
19+
plugins: ["node"],
20+
rules: {
21+
...commonRules,
22+
"node/no-extraneous-import": "error",
23+
"node/no-missing-import": "error",
24+
"node/no-unpublished-import": "error",
25+
"node/no-unsupported-features/es-syntax": [
26+
"error",
27+
{ ignores: ["modules"] },
28+
],
29+
},
30+
}

‎lib/configs/recommended-script.js

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"use strict"
2+
3+
const { commonGlobals, commonRules } = require("./_commons")
4+
5+
module.exports = {
6+
globals: {
7+
...commonGlobals,
8+
__dirname: "readonly",
9+
__filename: "readonly",
10+
exports: "readonly",
11+
module: "readonly",
12+
require: "readonly",
13+
},
14+
parserOptions: {
15+
ecmaFeatures: { globalReturn: true },
16+
ecmaVersion: 2019,
17+
sourceType: "script",
18+
},
19+
plugins: ["node"],
20+
rules: {
21+
...commonRules,
22+
"node/no-extraneous-import": "off",
23+
"node/no-missing-import": "off",
24+
"node/no-unpublished-import": "off",
25+
"node/no-unsupported-features/es-syntax": ["error", { ignores: [] }],
26+
},
27+
}

‎lib/configs/recommended.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"use strict"
2+
3+
const getPackageJson = require("../util/get-package-json")
4+
const moduleConfig = require("./recommended-module")
5+
const scriptConfig = require("./recommended-script")
6+
7+
module.exports = () => {
8+
const packageJson = getPackageJson()
9+
const isModule = (packageJson && packageJson.type) === "module"
10+
11+
return {
12+
...(isModule ? moduleConfig : scriptConfig),
13+
overrides: [
14+
{ files: ["*.cjs", ".*.cjs"], ...scriptConfig },
15+
{ files: ["*.mjs", ".*.mjs"], ...moduleConfig },
16+
],
17+
}
18+
}

‎lib/configs/recommended.json

-40
This file was deleted.

‎lib/index.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33

44
module.exports = {
55
configs: {
6-
recommended: require("./configs/recommended.json"),
6+
"recommended-module": require("./configs/recommended-module"),
7+
"recommended-script": require("./configs/recommended-script"),
8+
get recommended() {
9+
return require("./configs/recommended")()
10+
},
711
},
812
rules: {
913
"exports-style": require("./rules/exports-style"),

‎lib/util/get-package-json.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ function readPackageJson(dir) {
3939
* Gets a `package.json` data.
4040
* The data is cached if found, then it's used after.
4141
*
42-
* @param {string} startPath - A file path to lookup.
42+
* @param {string} [startPath] - A file path to lookup.
4343
* @returns {object|null} A found `package.json` data or `null`.
4444
* This object have additional property `filePath`.
4545
*/
46-
module.exports = function getPackageJson(startPath) {
46+
module.exports = function getPackageJson(startPath = "a.js") {
4747
const startDir = path.dirname(path.resolve(startPath))
4848
let dir = startDir
4949
let prevDir = ""

‎package.json

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"@mysticatea/eslint-plugin": "^10.0.3",
2525
"codecov": "^3.3.0",
2626
"eslint": "^5.16.0",
27+
"eslint-plugin-node": "file:.",
2728
"fast-glob": "^2.2.6",
2829
"mocha": "^6.1.4",
2930
"nyc": "^14.0.0",

‎scripts/update-lib-configs-recommended.js

-34
This file was deleted.

‎scripts/update-lib-index.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ const rawContent = `/* DON'T EDIT THIS FILE. This is generated by 'scripts/updat
1515
1616
module.exports = {
1717
configs: {
18-
recommended: require("./configs/recommended.json"),
18+
"recommended-module": require("./configs/recommended-module"),
19+
"recommended-script": require("./configs/recommended-script"),
20+
get recommended() {
21+
return require("./configs/recommended")()
22+
},
1923
},
2024
rules: {
2125
${rules
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
{
2+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"type": "module"
3+
}

‎tests/lib/configs/recommended.js

+163
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
"use strict"
2+
3+
const assert = require("assert")
4+
const path = require("path")
5+
const { CLIEngine } = require("eslint")
6+
const originalCwd = process.cwd()
7+
8+
describe("node/recommended config", () => {
9+
describe("in CJS directory", () => {
10+
const root = path.resolve(__dirname, "../../fixtures/configs/cjs/")
11+
12+
/** @type {CLIEngine} */
13+
let engine = null
14+
15+
beforeEach(() => {
16+
process.chdir(root)
17+
engine = new CLIEngine({
18+
baseConfig: { extends: "plugin:node/recommended" },
19+
useEslintrc: false,
20+
})
21+
})
22+
23+
afterEach(() => {
24+
process.chdir(originalCwd)
25+
})
26+
27+
it("*.js files should be a script.", () => {
28+
const report = engine.executeOnText(
29+
"import 'foo'",
30+
path.join(root, "test.js")
31+
)
32+
33+
assert.deepStrictEqual(report.results[0].messages, [
34+
{
35+
column: 1,
36+
fatal: true,
37+
line: 1,
38+
message:
39+
"Parsing error: 'import' and 'export' may appear only with 'sourceType: module'",
40+
ruleId: null,
41+
severity: 2,
42+
},
43+
])
44+
})
45+
46+
it("*.cjs files should be a script.", () => {
47+
const report = engine.executeOnText(
48+
"import 'foo'",
49+
path.join(root, "test.cjs")
50+
)
51+
52+
assert.deepStrictEqual(report.results[0].messages, [
53+
{
54+
column: 1,
55+
fatal: true,
56+
line: 1,
57+
message:
58+
"Parsing error: 'import' and 'export' may appear only with 'sourceType: module'",
59+
ruleId: null,
60+
severity: 2,
61+
},
62+
])
63+
})
64+
65+
it("*.mjs files should be a module.", () => {
66+
const report = engine.executeOnText(
67+
"import 'foo'",
68+
path.join(root, "test.mjs")
69+
)
70+
71+
assert.deepStrictEqual(report.results[0].messages, [
72+
{
73+
column: 8,
74+
endColumn: 13,
75+
endLine: 1,
76+
line: 1,
77+
message: '"foo" is not found.',
78+
nodeType: "Literal",
79+
ruleId: "node/no-missing-import",
80+
severity: 2,
81+
},
82+
])
83+
})
84+
})
85+
86+
describe("in ESM directory", () => {
87+
const root = path.resolve(__dirname, "../../fixtures/configs/esm/")
88+
89+
/** @type {CLIEngine} */
90+
let engine = null
91+
92+
beforeEach(() => {
93+
process.chdir(root)
94+
engine = new CLIEngine({
95+
baseConfig: { extends: "plugin:node/recommended" },
96+
useEslintrc: false,
97+
})
98+
})
99+
100+
afterEach(() => {
101+
process.chdir(originalCwd)
102+
})
103+
104+
it("*.js files should be a module.", () => {
105+
const report = engine.executeOnText(
106+
"import 'foo'",
107+
path.join(root, "test.js")
108+
)
109+
110+
assert.deepStrictEqual(report.results[0].messages, [
111+
{
112+
column: 8,
113+
endColumn: 13,
114+
endLine: 1,
115+
line: 1,
116+
message: '"foo" is not found.',
117+
nodeType: "Literal",
118+
ruleId: "node/no-missing-import",
119+
severity: 2,
120+
},
121+
])
122+
})
123+
124+
it("*.cjs files should be a script.", () => {
125+
const report = engine.executeOnText(
126+
"import 'foo'",
127+
path.join(root, "test.cjs")
128+
)
129+
130+
assert.deepStrictEqual(report.results[0].messages, [
131+
{
132+
column: 1,
133+
fatal: true,
134+
line: 1,
135+
message:
136+
"Parsing error: 'import' and 'export' may appear only with 'sourceType: module'",
137+
ruleId: null,
138+
severity: 2,
139+
},
140+
])
141+
})
142+
143+
it("*.mjs files should be a module.", () => {
144+
const report = engine.executeOnText(
145+
"import 'foo'",
146+
path.join(root, "test.mjs")
147+
)
148+
149+
assert.deepStrictEqual(report.results[0].messages, [
150+
{
151+
column: 8,
152+
endColumn: 13,
153+
endLine: 1,
154+
line: 1,
155+
message: '"foo" is not found.',
156+
nodeType: "Literal",
157+
ruleId: "node/no-missing-import",
158+
severity: 2,
159+
},
160+
])
161+
})
162+
})
163+
})

0 commit comments

Comments
 (0)
Please sign in to comment.