From 380d7672fdde726161cd784a77b5633c169519cc Mon Sep 17 00:00:00 2001 From: Chiawen Chen Date: Fri, 30 Aug 2019 22:09:58 +0800 Subject: [PATCH 1/7] New: add rule default-param-last (fixes #11361) --- docs/rules/default-param-last.md | 25 +++++++++ lib/rules/default-param-last.js | 61 +++++++++++++++++++++ lib/rules/index.js | 1 + tests/lib/rules/default-param-last.js | 76 +++++++++++++++++++++++++++ tools/rule-types.json | 1 + 5 files changed, 164 insertions(+) create mode 100644 docs/rules/default-param-last.md create mode 100644 lib/rules/default-param-last.js create mode 100644 tests/lib/rules/default-param-last.js diff --git a/docs/rules/default-param-last.md b/docs/rules/default-param-last.md new file mode 100644 index 00000000000..c9f361d13cd --- /dev/null +++ b/docs/rules/default-param-last.md @@ -0,0 +1,25 @@ +# enforce default parameters to be last (default-param-last) + +Putting default parameter at last allowes function calls to omit optional tail arguments. + +## Rule Details + +This rule enforces default parameters to be the last of paramters. + +Examples of **incorrect** code for this rule: + +```js +/* eslint default-param-last: ["error"] */ + +function f(a = 0, b) {} + +function f(a, b = 0, c) {} +``` + +Examples of **correct** code for this rule: + +```js +/* eslint default-param-last: ["error"] */ + +function f(a, b = 0) {} +``` diff --git a/lib/rules/default-param-last.js b/lib/rules/default-param-last.js new file mode 100644 index 00000000000..cdafc3bfcfb --- /dev/null +++ b/lib/rules/default-param-last.js @@ -0,0 +1,61 @@ +/** + * @fileoverview enforce default parameters to be last + * @author Chiawen Chen + */ + +"use strict"; + +module.exports = { + meta: { + type: "suggestion", + + docs: { + description: "enforce default parameters to be last", + category: "Best Practices", + recommended: false, + url: "https://eslint.org/docs/rules/default-param-last" + }, + + schema: [], + + messages: { + shouldBeLast: "Default parameters should be the last of parameters." + } + }, + + create(context) { + + /** + * @param {ASTNode} node function node + * @returns {void} + */ + function handleFunction(node) { + let hasSeenPlainParam = false; + + for (let i = node.params.length - 1; i >= 0; i -= 1) { + const param = node.params[i]; + + if ( + param.type !== "AssignmentPattern" && + param.type !== "RestElement" + ) { + hasSeenPlainParam = true; + continue; + } + + if (hasSeenPlainParam && param.type === "AssignmentPattern") { + context.report({ + node: param, + messageId: "shouldBeLast" + }); + } + } + } + + return { + FunctionDeclaration: handleFunction, + FunctionExpression: handleFunction, + ArrowFunctionExpression: handleFunction + }; + } +}; diff --git a/lib/rules/index.js b/lib/rules/index.js index c42ae41d6cb..51d224d219f 100644 --- a/lib/rules/index.js +++ b/lib/rules/index.js @@ -37,6 +37,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({ "constructor-super": () => require("./constructor-super"), curly: () => require("./curly"), "default-case": () => require("./default-case"), + "default-param-last": () => require("./default-param-last"), "dot-location": () => require("./dot-location"), "dot-notation": () => require("./dot-notation"), "eol-last": () => require("./eol-last"), diff --git a/tests/lib/rules/default-param-last.js b/tests/lib/rules/default-param-last.js new file mode 100644 index 00000000000..c161e08e2c1 --- /dev/null +++ b/tests/lib/rules/default-param-last.js @@ -0,0 +1,76 @@ +/** + * @fileoverview Test file for default-param-last + * @author Chiawen Chen + */ +"use strict"; + +const rule = require("../../../lib/rules/default-param-last"); +const { RuleTester } = require("../../../lib/rule-tester"); + +const SHOULD_BE_LAST = "shouldBeLast"; + +const ruleTester = new RuleTester({ + parserOptions: { ecmaVersion: 8 } +}); + +const cannedError = { + messageId: SHOULD_BE_LAST, + type: "AssignmentPattern" +}; + +ruleTester.run("default-param-last", rule, { + valid: [ + "function f(a) {}", + "function f(a = 5) {}", + "function f(a, b = 5) {}", + "function f(a, b = 5, c = 5) {}", + "function f(a, b = 5, ...c) {}" + ], + invalid: [ + { + code: "function f(a = 5, b) {}", + errors: [ + { + messageId: SHOULD_BE_LAST, + column: 12, + columnEnd: 15 + } + ] + }, + { + code: "function f(a = 5, b = 6, c) {}", + errors: [ + { + messageId: SHOULD_BE_LAST, + column: 12, + endColumn: 17 + }, + { + messageId: SHOULD_BE_LAST, + column: 19, + endColumn: 24 + } + ] + }, + { + code: "function f (a = 5, b, c = 6, d) {}", + errors: [cannedError, cannedError] + }, + { + code: "function f(a = 5, b, c = 5) {}", + errors: [cannedError] + }, + { + code: "const f = (a = 5, b, ...c) => {}", + errors: [cannedError] + }, + { + code: "const f = function f (a, b = 5, c) {}", + errors: [cannedError] + }, + { + code: "const f = (a = 5, { b }) => {}", + errors: [cannedError] + } + ] +}); diff --git a/tools/rule-types.json b/tools/rule-types.json index eef001a20d5..74cae9391cb 100644 --- a/tools/rule-types.json +++ b/tools/rule-types.json @@ -24,6 +24,7 @@ "constructor-super": "problem", "curly": "suggestion", "default-case": "suggestion", + "default-param-last": "suggestion", "dot-location": "layout", "dot-notation": "suggestion", "eol-last": "layout", From c884101bc1c35846fb8aaffa0b59fa9f72ad854f Mon Sep 17 00:00:00 2001 From: Chiawen Chen Date: Sun, 1 Sep 2019 12:45:21 +0800 Subject: [PATCH 2/7] Chore: fix typos --- docs/rules/default-param-last.md | 4 ++-- tests/lib/rules/default-param-last.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/rules/default-param-last.md b/docs/rules/default-param-last.md index c9f361d13cd..383114126ab 100644 --- a/docs/rules/default-param-last.md +++ b/docs/rules/default-param-last.md @@ -1,10 +1,10 @@ # enforce default parameters to be last (default-param-last) -Putting default parameter at last allowes function calls to omit optional tail arguments. +Putting default parameter at last allows function calls to omit optional tail arguments. ## Rule Details -This rule enforces default parameters to be the last of paramters. +This rule enforces default parameters to be the last of parameters. Examples of **incorrect** code for this rule: diff --git a/tests/lib/rules/default-param-last.js b/tests/lib/rules/default-param-last.js index c161e08e2c1..026c5a3bc9f 100644 --- a/tests/lib/rules/default-param-last.js +++ b/tests/lib/rules/default-param-last.js @@ -33,7 +33,7 @@ ruleTester.run("default-param-last", rule, { { messageId: SHOULD_BE_LAST, column: 12, - columnEnd: 15 + endColumn: 17 } ] }, From 8fb5f470dad0cc49496017a36a1b2560b1332815 Mon Sep 17 00:00:00 2001 From: Chiawen Chen Date: Sun, 1 Sep 2019 13:02:15 +0800 Subject: [PATCH 3/7] Chore: add test cases --- tests/lib/rules/default-param-last.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/lib/rules/default-param-last.js b/tests/lib/rules/default-param-last.js index 026c5a3bc9f..f094ecb9346 100644 --- a/tests/lib/rules/default-param-last.js +++ b/tests/lib/rules/default-param-last.js @@ -20,11 +20,19 @@ const cannedError = { ruleTester.run("default-param-last", rule, { valid: [ + "function f() {}", "function f(a) {}", "function f(a = 5) {}", + "function f(a, b) {}", "function f(a, b = 5) {}", "function f(a, b = 5, c = 5) {}", - "function f(a, b = 5, ...c) {}" + "function f(a, b = 5, ...c) {}", + "const f = () => {}", + "const f = (a) => {}", + "const f = (a = 5) => {}", + "const f = function f() {}", + "const f = function f(a) {}", + "const f = function f(a = 5) {}" ], invalid: [ { From a4fe4354ab83031c6823b7f6a4d6d390950bf6ad Mon Sep 17 00:00:00 2001 From: Chiawen Chen Date: Sun, 1 Sep 2019 18:22:50 +0800 Subject: [PATCH 4/7] Apply suggestion: add column for a test case --- tests/lib/rules/default-param-last.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/lib/rules/default-param-last.js b/tests/lib/rules/default-param-last.js index f094ecb9346..e259591b4e6 100644 --- a/tests/lib/rules/default-param-last.js +++ b/tests/lib/rules/default-param-last.js @@ -66,7 +66,13 @@ ruleTester.run("default-param-last", rule, { }, { code: "function f(a = 5, b, c = 5) {}", - errors: [cannedError] + errors: [ + { + messageId: SHOULD_BE_LAST, + column: 12, + endColumn: 17 + } + ] }, { code: "const f = (a = 5, b, ...c) => {}", From e5766615e4b131da6542930e51207d804e5774f7 Mon Sep 17 00:00:00 2001 From: Chiawen Chen Date: Mon, 2 Sep 2019 00:04:23 +0800 Subject: [PATCH 5/7] Update: change error message --- lib/rules/default-param-last.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rules/default-param-last.js b/lib/rules/default-param-last.js index cdafc3bfcfb..ee73aaf3215 100644 --- a/lib/rules/default-param-last.js +++ b/lib/rules/default-param-last.js @@ -19,7 +19,7 @@ module.exports = { schema: [], messages: { - shouldBeLast: "Default parameters should be the last of parameters." + shouldBeLast: "Default parameters should be last." } }, From 1296635fe83887ce89be075cece8bd44d2453144 Mon Sep 17 00:00:00 2001 From: Chiawen Chen Date: Mon, 2 Sep 2019 00:02:10 +0800 Subject: [PATCH 6/7] Docs: add example in opening section --- docs/rules/default-param-last.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/rules/default-param-last.md b/docs/rules/default-param-last.md index 383114126ab..97bba70fa8c 100644 --- a/docs/rules/default-param-last.md +++ b/docs/rules/default-param-last.md @@ -2,6 +2,16 @@ Putting default parameter at last allows function calls to omit optional tail arguments. +```js +// Correct: optional argument can be omitted +function createUser(id, isAdmin = false) {} +createUser("tabby") + +// Incorrect: optional argument can **not** be omitted +function createUser(isAdmin = false, id) {} +createUser(undefined, "tabby") +``` + ## Rule Details This rule enforces default parameters to be the last of parameters. From 10a74879307839462f23bcfc29720217b5253ad5 Mon Sep 17 00:00:00 2001 From: Chiawen Chen Date: Wed, 4 Sep 2019 00:08:40 +0800 Subject: [PATCH 7/7] Add test cases about parameter destructuring --- tests/lib/rules/default-param-last.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/lib/rules/default-param-last.js b/tests/lib/rules/default-param-last.js index e259591b4e6..05321f5e265 100644 --- a/tests/lib/rules/default-param-last.js +++ b/tests/lib/rules/default-param-last.js @@ -85,6 +85,22 @@ ruleTester.run("default-param-last", rule, { { code: "const f = (a = 5, { b }) => {}", errors: [cannedError] + }, + { + code: "const f = ({ a } = {}, b) => {}", + errors: [cannedError] + }, + { + code: "const f = ({ a, b } = { a: 1, b: 2 }, c) => {}", + errors: [cannedError] + }, + { + code: "const f = ([a] = [], b) => {}", + errors: [cannedError] + }, + { + code: "const f = ([a, b] = [1, 2], c) => {}", + errors: [cannedError] } ] });