diff --git a/.gitignore b/.gitignore index 51ecba1c..f9187bd4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ /.nyc_output /coverage -/index.js /npm-debug.log /node_modules /test.js diff --git a/README.md b/README.md index 9ea10c4c..c8f74acb 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Additional ESLint's rules for Node.js -## :cd: Install & Usage +## 💿 Install & Usage ``` $ npm install --save-dev eslint eslint-plugin-node @@ -43,27 +43,39 @@ $ npm install --save-dev eslint eslint-plugin-node } ``` -## :bulb: Rules +## 📖 Rules -- :star: - the mark of recommended rules. -- :pencil: - the mark of fixable rules. +- ⭐️ - the mark of recommended rules. +- ✒️ - the mark of fixable rules. -| | | Rule ID | Description | -|:------:|:--------:|:-----------------------------------------------------------------|:------------| -| | | [exports-style](docs/rules/exports-style.md) | Enforce either `module.exports` or `exports`. -| :star: | | [no-deprecated-api](docs/rules/no-deprecated-api.md) | Disallow deprecated API. -| | | [no-extraneous-import](docs/rules/no-extraneous-import.md) | Disallow `import` declarations of extraneous packages. :warning: -| :star: | | [no-extraneous-require](docs/rules/no-extraneous-require.md) | Disallow `require()` expressions of extraneous packages. -| | | [no-missing-import](docs/rules/no-missing-import.md) | Disallow `import` declarations of files that don't exist. :warning: -| :star: | | [no-missing-require](docs/rules/no-missing-require.md) | Disallow `require()` expressions of files that don't exist. -| :star: | | [no-unpublished-bin](docs/rules/no-unpublished-bin.md) | Disallow `bin` files that npm ignores. -| | | [no-unpublished-import](docs/rules/no-unpublished-import.md) | Disallow `import` declarations of files that npm ignores. :warning: -| :star: | | [no-unpublished-require](docs/rules/no-unpublished-require.md) | Disallow `require()` expressions of files that npm ignores. -| :star: | | [no-unsupported-features](docs/rules/no-unsupported-features.md) | Disallow unsupported ECMAScript features on the specified version. -| :star: | | [process-exit-as-throw](docs/rules/process-exit-as-throw.md) | Make the same code path as throw at `process.exit()`. -| :star: | :pencil: | [shebang](docs/rules/shebang.md) | Suggest correct usage of shebang. + +### Possible Errors +| | Rule ID | Description | +|:---|:--------|:------------| +| | [no-extraneous-import](./docs/rules/no-extraneous-import.md) | disallow `import` declarations of extraneous packages | +| ⭐️ | [no-extraneous-require](./docs/rules/no-extraneous-require.md) | disallow `require()` expressions of extraneous packages | +| | [no-missing-import](./docs/rules/no-missing-import.md) | disallow `import` declarations of missing files | +| ⭐️ | [no-missing-require](./docs/rules/no-missing-require.md) | disallow `require()` expressions of missing files | +| ⭐️ | [no-unpublished-bin](./docs/rules/no-unpublished-bin.md) | disallow 'bin' files which are ignored by npm | +| | [no-unpublished-import](./docs/rules/no-unpublished-import.md) | disallow `import` declarations of private things | +| ⭐️ | [no-unpublished-require](./docs/rules/no-unpublished-require.md) | disallow `require()` expressions of private things | +| ⭐️ | [no-unsupported-features](./docs/rules/no-unsupported-features.md) | disallow unsupported ECMAScript features on the specified version | +| ⭐️ | [process-exit-as-throw](./docs/rules/process-exit-as-throw.md) | make `process.exit()` expressions the same code path as `throw` | +| ⭐️✒️ | [shebang](./docs/rules/shebang.md) | enforce the correct usage of shebang | -## :wrench: Configs +### Best Practices +| | Rule ID | Description | +|:---|:--------|:------------| +| ⭐️ | [no-deprecated-api](./docs/rules/no-deprecated-api.md) | disallow deprecated APIs | + +### Stylistic Issues +| | Rule ID | Description | +|:---|:--------|:------------| +| | [exports-style](./docs/rules/exports-style.md) | enforce either `module.exports` or `exports` | + + + +## 🔧 Configs This plugin provides `plugin:node/recommended` preset config. This preset config: @@ -73,12 +85,12 @@ This preset config: - 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()`. - adds `{ecmaVersion: 8}` into `parserOptions`. -## :couple: FAQ +## 👫 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. -## :anchor: Semantic Versioning Policy +## 🚥 Semantic Versioning Policy `eslint-plugin-node` follows [semantic versioning](http://semver.org/) and [ESLint's Semantic Versioning Policy](https://github.com/eslint/eslint#semantic-versioning-policy). @@ -100,11 +112,11 @@ This preset config: - An existing option of a rule is removed. - An existing config is updated. -## :newspaper: Changelog +## 📰 Changelog - [GitHub Releases](https://github.com/mysticatea/eslint-plugin-node/releases) -## :muscle: Contributing +## 💎 Contributing Welcome contributing! diff --git a/conf/recommended.json b/conf/recommended.json deleted file mode 100644 index d763bde7..00000000 --- a/conf/recommended.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "parserOptions": { - "ecmaVersion": 8 - }, - "env": { - "es6": true, - "node": true - }, - "rules": { - "no-process-exit": "error", - "node/no-deprecated-api": "error", - "node/no-missing-require": "error", - "node/no-unpublished-bin": "error", - "node/no-unpublished-require": "error", - "node/no-unsupported-features": "error", - "node/process-exit-as-throw": "error", - "node/shebang": "error" - } -} diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 00000000..12ab57b0 --- /dev/null +++ b/lib/index.js @@ -0,0 +1,11 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +"use strict" + +module.exports = { + configs: {recommended: require("./recommended.json")}, + rules: require("./rules.js"), +} diff --git a/lib/recommended.json b/lib/recommended.json new file mode 100644 index 00000000..9bea4a3a --- /dev/null +++ b/lib/recommended.json @@ -0,0 +1,24 @@ +{ + "parserOptions": { + "ecmaVersion": 8 + }, + "env": { + "es6": true, + "node": true + }, + "rules": { + "no-process-exit": "error", + "node/exports-style": "off", + "node/no-deprecated-api": "error", + "node/no-extraneous-import": "off", + "node/no-extraneous-require": "error", + "node/no-missing-import": "off", + "node/no-missing-require": "error", + "node/no-unpublished-bin": "error", + "node/no-unpublished-import": "off", + "node/no-unpublished-require": "error", + "node/no-unsupported-features": "error", + "node/process-exit-as-throw": "error", + "node/shebang": "error" + } +} \ No newline at end of file diff --git a/lib/rules.js b/lib/rules.js new file mode 100644 index 00000000..822080e5 --- /dev/null +++ b/lib/rules.js @@ -0,0 +1,22 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +"use strict" + +module.exports = { + "exports-style": require("./rules/exports-style"), + "no-deprecated-api": require("./rules/no-deprecated-api"), + "no-extraneous-import": require("./rules/no-extraneous-import"), + "no-extraneous-require": require("./rules/no-extraneous-require"), + "no-hide-core-modules": require("./rules/no-hide-core-modules"), + "no-missing-import": require("./rules/no-missing-import"), + "no-missing-require": require("./rules/no-missing-require"), + "no-unpublished-bin": require("./rules/no-unpublished-bin"), + "no-unpublished-import": require("./rules/no-unpublished-import"), + "no-unpublished-require": require("./rules/no-unpublished-require"), + "no-unsupported-features": require("./rules/no-unsupported-features"), + "process-exit-as-throw": require("./rules/process-exit-as-throw"), + "shebang": require("./rules/shebang"), +} diff --git a/lib/rules/no-deprecated-api.js b/lib/rules/no-deprecated-api.js index a8f7b400..572ff338 100644 --- a/lib/rules/no-deprecated-api.js +++ b/lib/rules/no-deprecated-api.js @@ -546,7 +546,7 @@ module.exports = { docs: { description: "disallow deprecated APIs", category: "Best Practices", - recommended: false, + recommended: true, }, fixable: false, schema: [ diff --git a/lib/rules/no-extraneous-require.js b/lib/rules/no-extraneous-require.js index 6c226899..db8d5d73 100644 --- a/lib/rules/no-extraneous-require.js +++ b/lib/rules/no-extraneous-require.js @@ -49,9 +49,9 @@ module.exports = { create, meta: { docs: { - description: "disallow `require()` expressions for extraneous packages", + description: "disallow `require()` expressions of extraneous packages", category: "Possible Errors", - recommended: false, + recommended: true, }, fixable: false, schema: [ diff --git a/lib/rules/no-missing-import.js b/lib/rules/no-missing-import.js index fdd50816..a2ae4389 100644 --- a/lib/rules/no-missing-import.js +++ b/lib/rules/no-missing-import.js @@ -49,7 +49,7 @@ module.exports = { create, meta: { docs: { - description: "disallow import declarations for files that don't exist", + description: "disallow `import` declarations of missing files", category: "Possible Errors", recommended: false, }, diff --git a/lib/rules/no-missing-require.js b/lib/rules/no-missing-require.js index d40999a4..6188ed06 100644 --- a/lib/rules/no-missing-require.js +++ b/lib/rules/no-missing-require.js @@ -49,9 +49,9 @@ module.exports = { create, meta: { docs: { - description: "disallow `require()` expressions for files that don't exist", + description: "disallow `require()` expressions of missing files", category: "Possible Errors", - recommended: false, + recommended: true, }, fixable: false, schema: [ diff --git a/lib/rules/no-unpublished-bin.js b/lib/rules/no-unpublished-bin.js index 4cd1f445..2409142f 100644 --- a/lib/rules/no-unpublished-bin.js +++ b/lib/rules/no-unpublished-bin.js @@ -96,9 +96,9 @@ module.exports = { create, meta: { docs: { - description: "disallow 'bin' files that npm ignores", + description: "disallow 'bin' files which are ignored by npm", category: "Possible Errors", - recommended: false, + recommended: true, }, fixable: false, schema: [ diff --git a/lib/rules/no-unpublished-import.js b/lib/rules/no-unpublished-import.js index ee5c89b1..7feb04b9 100644 --- a/lib/rules/no-unpublished-import.js +++ b/lib/rules/no-unpublished-import.js @@ -50,7 +50,7 @@ module.exports = { create, meta: { docs: { - description: "disallow import declarations for files that npm ignores", + description: "disallow `import` declarations of private things", category: "Possible Errors", recommended: false, }, diff --git a/lib/rules/no-unpublished-require.js b/lib/rules/no-unpublished-require.js index a3bbe7b5..286f8e25 100644 --- a/lib/rules/no-unpublished-require.js +++ b/lib/rules/no-unpublished-require.js @@ -50,9 +50,9 @@ module.exports = { create, meta: { docs: { - description: "disallow `require()` expressions for files that npm ignores", + description: "disallow `require()` expressions of private things", category: "Possible Errors", - recommended: false, + recommended: true, }, fixable: false, schema: [ diff --git a/lib/rules/no-unsupported-features.js b/lib/rules/no-unsupported-features.js index cea0515f..98a14953 100644 --- a/lib/rules/no-unsupported-features.js +++ b/lib/rules/no-unsupported-features.js @@ -725,7 +725,7 @@ module.exports = { docs: { description: "disallow unsupported ECMAScript features on the specified version", category: "Possible Errors", - recommended: false, + recommended: true, }, fixable: false, schema: [ diff --git a/lib/rules/process-exit-as-throw.js b/lib/rules/process-exit-as-throw.js index e6477b36..1e078883 100644 --- a/lib/rules/process-exit-as-throw.js +++ b/lib/rules/process-exit-as-throw.js @@ -144,9 +144,9 @@ const visitor = CodePathAnalyzer == null ? {} : { module.exports = { meta: { docs: { - description: "make the same code path as `throw` at `process.exit()`", + description: "make `process.exit()` expressions the same code path as `throw`", category: "Possible Errors", - recommended: false, + recommended: true, }, fixable: false, schema: [], diff --git a/lib/rules/shebang.js b/lib/rules/shebang.js index 35388e3f..729fb5c5 100644 --- a/lib/rules/shebang.js +++ b/lib/rules/shebang.js @@ -145,7 +145,7 @@ module.exports = { docs: { description: "enforce the correct usage of shebang", category: "Possible Errors", - recommended: false, + recommended: true, }, fixable: "code", schema: [ diff --git a/package.json b/package.json index 6237195d..f0fc07f8 100644 --- a/package.json +++ b/package.json @@ -2,20 +2,19 @@ "name": "eslint-plugin-node", "version": "4.2.2", "description": "Additional ESLint's rules for Node.js", + "main": "lib/index.js", "files": [ - "conf", - "lib", - "index.js" + "lib" ], "scripts": { - "build": "node scripts/generate-index.js", - "clean": "rimraf .nyc_output coverage index.js", + "build": "node scripts/update.js", + "clean": "rimraf .nyc_output coverage", "codecov": "nyc report -r lcovonly && codecov", "coverage": "nyc report -r lcov && opener ./coverage/lcov-report/index.html", "lint": "eslint lib tests/lib index.js", "postversion": "git push && git push --tags", "pretest": "npm run -s lint", - "preversion": "npm t && npm run build", + "preversion": "npm t && npm run -s build", "test": "nyc npm run -s test:_mocha", "test:_mocha": "_mocha tests/lib/**/*.js --reporter progress", "watch": "npm run test:_mocha -- --watch --growl" diff --git a/scripts/generate-index.js b/scripts/generate-index.js deleted file mode 100644 index 80ec5d2c..00000000 --- a/scripts/generate-index.js +++ /dev/null @@ -1,69 +0,0 @@ -/** - * @author Toru Nagashima - * @copyright 2015 Toru Nagashima. All rights reserved. - * See LICENSE file in root directory for full license. - */ -"use strict" - -//------------------------------------------------------------------------------ -// Requirements -//------------------------------------------------------------------------------ - -const path = require("path") - -/* eslint-env shelljs */ -require("shelljs/global") - -//------------------------------------------------------------------------------ -// Helpers -//------------------------------------------------------------------------------ - -/** - * @param {string} name - A file name to convert. - * @returns {string} The base name of the file name. - */ -function toBasename(name) { - return path.basename(name, ".js") -} - -/** - * @param {string} name - A rule name to convert. - * @returns {string} The definition code of the rule creator. - */ -function toRuleDefinition(name) { - return ` "${name}": require("./lib/rules/${name}"),` -} - -/** - * @param {string} name - A rule name to convert. - * @returns {string} The definition code of the default rule level. - */ -function toRuleLevel(name) { - return ` "${name}": "off",` -} - -//------------------------------------------------------------------------------ -// Main -//------------------------------------------------------------------------------ - -const ruleNames = ls("lib/rules").map(toBasename); - -[ - "/**", - " * @author Toru Nagashima", - " * @copyright 2015 Toru Nagashima. All rights reserved.", - " * See LICENSE file in root directory for full license.", - " */", - "\"use strict\"", - "", - "module.exports = {", - " rules: {", - ruleNames.map(toRuleDefinition).join("\n"), - " },", - " rulesConfig: {", - ruleNames.map(toRuleLevel).join("\n"), - " },", - " configs: {recommended: require(\"./conf/recommended.json\")},", - "}", - "", -].join("\n").to("index.js") diff --git a/scripts/update.js b/scripts/update.js new file mode 100644 index 00000000..d3567c7e --- /dev/null +++ b/scripts/update.js @@ -0,0 +1,102 @@ +/** + * @author Toru Nagashima + * @copyright 2015 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +"use strict" + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const fs = require("fs") +const path = require("path") + +//------------------------------------------------------------------------------ +// Main +//------------------------------------------------------------------------------ + +const ROOT = path.resolve(__dirname, "../lib/rules") +const README = path.resolve(__dirname, "../README.md") +const RULES_JS = path.resolve(__dirname, "../lib/rules.js") +const RECOMMENDED_JSON = path.resolve(__dirname, "../lib/recommended.json") +const STAR = "⭐️" +const PEN = "✒️" +const CATEGORIES = ["Possible Errors", "Best Practices", "Stylistic Issues"] +const TABLE_PLACE_HOLDER = /[\s\S]*/ + +const ruleNames = fs.readdirSync(ROOT) + .filter(file => path.extname(file) === ".js") + .map(file => path.basename(file, ".js")) + +const rules = new Map( + ruleNames + .map(name => [ + name, + require(path.join(ROOT, name)), + ]) + .filter(rule => !rule[1].meta.deprecated) +) + +const RULE_TABLE = CATEGORIES.map(category => `### ${category} +| | Rule ID | Description | +|:---|:--------|:------------| +${ + Array.from(rules.entries()) + .filter(entry => entry[1].meta.docs.category === category) + .map(entry => { + const name = entry[0] + const meta = entry[1].meta + const mark = `${meta.docs.recommended ? STAR : ""}${meta.fixable ? PEN : ""}` + const link = `[${name}](./docs/rules/${name}.md)` + const description = meta.docs.description || "(no description)" + return `| ${mark} | ${link} | ${description} |` + }) + .join("\n") +} +`).join("\n") + +const RULES_JS_CONTENT = `/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +"use strict" + +module.exports = { +${ruleNames.map(name => ` "${name}": require("./rules/${name}"),`).join("\n")} +} +` + +const recommendedConf = { + parserOptions: {ecmaVersion: 8}, + env: { + es6: true, + node: true, + }, + rules: Array.from(rules.entries()).reduce( + (obj, entry) => { + const name = entry[0] + const recommended = entry[1].meta.docs.recommended + obj[`node/${name}`] = recommended ? "error" : "off" + return obj + }, + {"no-process-exit": "error"} + ), +} + +fs.writeFileSync( + README, + fs.readFileSync(README, "utf8").replace( + TABLE_PLACE_HOLDER, + `\n${RULE_TABLE}\n` + ) +) +fs.writeFileSync( + RULES_JS, + RULES_JS_CONTENT +) +fs.writeFileSync( + RECOMMENDED_JSON, + JSON.stringify(recommendedConf, null, 4) +)