Skip to content

Commit

Permalink
feat: add new allowParensAfterCommentPattern option to the `no-extr…
Browse files Browse the repository at this point in the history
…a-parens` rule
  • Loading branch information
snitin315 committed Nov 20, 2022
1 parent 2af9e54 commit 9cf3e20
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 17 deletions.
1 change: 1 addition & 0 deletions docs/src/rules/no-extra-parens.md
Expand Up @@ -38,6 +38,7 @@ This rule has an object option for exceptions to the `"all"` option:
* `"enforceForSequenceExpressions": false` allows extra parentheses around sequence expressions
* `"enforceForNewInMemberExpressions": false` allows extra parentheses around `new` expressions in member expressions
* `"enforceForFunctionPrototypeMethods": false` allows extra parentheses around immediate `.call` and `.apply` method calls on function expressions and around function expressions in the same context.
* `"allowParensAfterComment": true` allows extra parentheses preceded by a comment that matches a regular expression

### all

Expand Down
17 changes: 13 additions & 4 deletions lib/rules/no-extra-parens.js
Expand Up @@ -53,7 +53,7 @@ module.exports = {
enforceForSequenceExpressions: { type: "boolean" },
enforceForNewInMemberExpressions: { type: "boolean" },
enforceForFunctionPrototypeMethods: { type: "boolean" },
allowParensAfterComment: { type: "boolean" }
allowParensAfterCommentPattern: { type: "string" }
},
additionalProperties: false
}
Expand Down Expand Up @@ -87,7 +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 ALLOW_PARENS_AFTER_COMMENT_PATTERN = ALL_NODES && context.options[1] && context.options[1].allowParensAfterCommentPattern;

const PRECEDENCE_OF_ASSIGNMENT_EXPR = precedence({ type: "AssignmentExpression" });
const PRECEDENCE_OF_UPDATE_EXPR = precedence({ type: "UpdateExpression" });
Expand Down Expand Up @@ -405,8 +405,17 @@ module.exports = {
return;
}

if (ALLOW_PARENS_AFTER_COMMENT && isParenthesised(node) && sourceCode.getCommentsBefore(leftParenToken).length > 0) {
return;
if (ALLOW_PARENS_AFTER_COMMENT_PATTERN && isParenthesised(node)) {
const commentsBeforeLeftParenToken = sourceCode.getCommentsBefore(leftParenToken);
const totalCommentsBeforeLeftParenTokenCount = commentsBeforeLeftParenToken.length;
const ignorePattern = new RegExp(ALLOW_PARENS_AFTER_COMMENT_PATTERN, "u");

if (
totalCommentsBeforeLeftParenTokenCount > 0 &&
ignorePattern.test(commentsBeforeLeftParenToken[totalCommentsBeforeLeftParenTokenCount - 1].value)
) {
return;
}
}
}

Expand Down
81 changes: 68 additions & 13 deletions tests/lib/rules/no-extra-parens.js
Expand Up @@ -738,18 +738,18 @@ ruleTester.run("no-extra-parens", rule, {
},
{
code: "(Object.prototype.toString.call())",
options: ["functions"],
options: ["functions"]
},

// "allowParensAfterComment" option
// "allowParensAfterCommentPattern" option
{
code: "const span = /**@type {HTMLSpanElement}*/(event.currentTarget);",
options: ["all", { allowParensAfterComment: true }],
options: ["all", { allowParensAfterCommentPattern: "@type" }],
parserOptions: { ecmaVersion: 2020 }
},
{
code: "if (/** @type {Compiler | MultiCompiler} */(options).hooks) console.log('good');",
options: ["all", { allowParensAfterComment: true }],
options: ["all", { allowParensAfterCommentPattern: "@type" }],
parserOptions: { ecmaVersion: 2020 }
},
{
Expand All @@ -759,7 +759,7 @@ ruleTester.run("no-extra-parens", rule, {
baseDataPath: "options",
});
`,
options: ["all", { allowParensAfterComment: true }],
options: ["all", { allowParensAfterCommentPattern: "@type" }],
parserOptions: { ecmaVersion: 2020 }
},
{
Expand All @@ -769,12 +769,12 @@ ruleTester.run("no-extra-parens", rule, {
(options.server.options).requestCert = false;
}
`,
options: ["all", { allowParensAfterComment: true }],
options: ["all", { allowParensAfterCommentPattern: "@type" }],
parserOptions: { ecmaVersion: 2020 }
},
{
code: "const net = ipaddr.parseCIDR(/** @type {string} */ (cidr));",
options: ["all", { allowParensAfterComment: true }],
options: ["all", { allowParensAfterCommentPattern: "@type" }],
parserOptions: { ecmaVersion: 2020 }
}
],
Expand Down Expand Up @@ -3228,18 +3228,73 @@ ruleTester.run("no-extra-parens", rule, {
errors: [{ messageId: "unexpected" }]
},

// "allowParensAfterComment" option
// "allowParensAfterCommentPattern" option (off by default)
{
code: "const span = /**@type {HTMLSpanElement}*/(event.currentTarget);",
output: "const span = /**@type {HTMLSpanElement}*/event.currentTarget;",
options: ["all"],
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"],
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"],
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"],
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unexpected" }]
},
{
code: "const net = ipaddr.parseCIDR(/** @type {string} */ (cidr));",
output: "const net = ipaddr.parseCIDR(/** @type {string} */ cidr);",
options: ["all"],
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unexpected" }]
},
{
code: "const span = /**@type {HTMLSpanElement}*/(event.currentTarget);",
output: "const span = /**@type {HTMLSpanElement}*/event.currentTarget;",
options: ["all", { allowParensAfterComment: false }],
options: ["all", { allowParensAfterCommentPattern: "invalid" }],
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 }],
options: ["all", { allowParensAfterCommentPattern: "invalid" }],
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unexpected" }]
},
Expand All @@ -3256,7 +3311,7 @@ ruleTester.run("no-extra-parens", rule, {
baseDataPath: "options",
});
`,
options: ["all", { allowParensAfterComment: false }],
options: ["all", { allowParensAfterCommentPattern: "invalid" }],
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unexpected" }]
},
Expand All @@ -3273,14 +3328,14 @@ ruleTester.run("no-extra-parens", rule, {
options.server.options.requestCert = false;
}
`,
options: ["all", { allowParensAfterComment: false }],
options: ["all", { allowParensAfterCommentPattern: "invalid" }],
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 }],
options: ["all", { allowParensAfterCommentPattern: "invalid" }],
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unexpected" }]
},
Expand Down

0 comments on commit 9cf3e20

Please sign in to comment.