From 4a54646759987f671c777b7b7d8ac3a9e0692b50 Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Sat, 19 Nov 2022 16:52:58 +0530 Subject: [PATCH] feat: add new `allowParensAfterComment` option (`no-extra-parens`) --- lib/rules/no-extra-parens.js | 8 ++- tests/lib/rules/no-extra-parens.js | 94 ++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/lib/rules/no-extra-parens.js b/lib/rules/no-extra-parens.js index 246a5a0d5e1e..a57b3ed78f40 100644 --- a/lib/rules/no-extra-parens.js +++ b/lib/rules/no-extra-parens.js @@ -52,7 +52,8 @@ module.exports = { enforceForArrowConditionals: { type: "boolean" }, enforceForSequenceExpressions: { type: "boolean" }, enforceForNewInMemberExpressions: { type: "boolean" }, - enforceForFunctionPrototypeMethods: { type: "boolean" } + enforceForFunctionPrototypeMethods: { type: "boolean" }, + allowParensAfterComment: { type: "boolean" } }, additionalProperties: false } @@ -86,6 +87,7 @@ module.exports = { context.options[1].enforceForNewInMemberExpressions === false; const IGNORE_FUNCTION_PROTOTYPE_METHODS = ALL_NODES && context.options[1] && context.options[1].enforceForFunctionPrototypeMethods === false; + const ALLOW_PARENS_AFTER_COMMENT = ALL_NODES && context.options[1] && context.options[1].allowParensAfterComment === true; const PRECEDENCE_OF_ASSIGNMENT_EXPR = precedence({ type: "AssignmentExpression" }); const PRECEDENCE_OF_UPDATE_EXPR = precedence({ type: "UpdateExpression" }); @@ -402,6 +404,10 @@ module.exports = { if (isIIFE(node) && !isParenthesised(node.callee)) { return; } + + if (ALLOW_PARENS_AFTER_COMMENT && isParenthesised(node) && sourceCode.getCommentsBefore(leftParenToken).length > 0) { + return; + } } /** diff --git a/tests/lib/rules/no-extra-parens.js b/tests/lib/rules/no-extra-parens.js index 557b641cf50b..d72a6af86628 100644 --- a/tests/lib/rules/no-extra-parens.js +++ b/tests/lib/rules/no-extra-parens.js @@ -735,6 +735,43 @@ ruleTester.run("no-extra-parens", rule, { code: "var foo = (function(){}?.call())", options: ["all", { enforceForFunctionPrototypeMethods: false }], parserOptions: { ecmaVersion: 2020 } + }, + + // "allowParensAfterComment" option + { + code: "const span = /**@type {HTMLSpanElement}*/(event.currentTarget);", + options: ["all", { allowParensAfterComment: true }], + parserOptions: { ecmaVersion: 2020 } + }, + { + code: "if (/** @type {Compiler | MultiCompiler} */(options).hooks) console.log('good');", + options: ["all", { allowParensAfterComment: true }], + parserOptions: { ecmaVersion: 2020 } + }, + { + code: ` + validate(/** @type {Schema} */ (schema), options, { + name: "Dev Server", + baseDataPath: "options", + }); + `, + options: ["all", { allowParensAfterComment: true }], + parserOptions: { ecmaVersion: 2020 } + }, + { + code: ` + if (condition) { + /** @type {ServerOptions} */ + (options.server.options).requestCert = false; + } + `, + options: ["all", { allowParensAfterComment: true }], + parserOptions: { ecmaVersion: 2020 } + }, + { + code: "const net = ipaddr.parseCIDR(/** @type {string} */ (cidr));", + options: ["all", { allowParensAfterComment: true }], + parserOptions: { ecmaVersion: 2020 } } ], @@ -3187,6 +3224,63 @@ ruleTester.run("no-extra-parens", rule, { errors: [{ messageId: "unexpected" }] }, + // "allowParensAfterComment" option + { + code: "const span = /**@type {HTMLSpanElement}*/(event.currentTarget);", + output: "const span = /**@type {HTMLSpanElement}*/event.currentTarget;", + options: ["all", { allowParensAfterComment: false }], + parserOptions: { ecmaVersion: 2020 }, + errors: [{ messageId: "unexpected" }] + }, + { + code: "if (/** @type {Compiler | MultiCompiler} */(options).hooks) console.log('good');", + output: "if (/** @type {Compiler | MultiCompiler} */options.hooks) console.log('good');", + options: ["all", { allowParensAfterComment: false }], + parserOptions: { ecmaVersion: 2020 }, + errors: [{ messageId: "unexpected" }] + }, + { + code: ` + validate(/** @type {Schema} */ (schema), options, { + name: "Dev Server", + baseDataPath: "options", + }); + `, + output: ` + validate(/** @type {Schema} */ schema, options, { + name: "Dev Server", + baseDataPath: "options", + }); + `, + options: ["all", { allowParensAfterComment: false }], + parserOptions: { ecmaVersion: 2020 }, + errors: [{ messageId: "unexpected" }] + }, + { + code: ` + if (condition) { + /** @type {ServerOptions} */ + (options.server.options).requestCert = false; + } + `, + output: ` + if (condition) { + /** @type {ServerOptions} */ + options.server.options.requestCert = false; + } + `, + options: ["all", { allowParensAfterComment: false }], + parserOptions: { ecmaVersion: 2020 }, + errors: [{ messageId: "unexpected" }] + }, + { + code: "const net = ipaddr.parseCIDR(/** @type {string} */ (cidr));", + output: "const net = ipaddr.parseCIDR(/** @type {string} */ cidr);", + options: ["all", { allowParensAfterComment: false }], + parserOptions: { ecmaVersion: 2020 }, + errors: [{ messageId: "unexpected" }] + }, + // Optional chaining { code: "var v = (obj?.aaa)?.aaa",