From d5113f6312f51b7e9cfe390fbe58d678f8a427f6 Mon Sep 17 00:00:00 2001 From: Rodrigo Vieira Date: Wed, 12 Jul 2023 11:38:51 +1000 Subject: [PATCH] Extend rule to look into Template Literal and BinaryExpressions --- src/helpers/ast.ts | 4 ++ src/helpers/createReport.ts | 6 ++- src/rules/noLookAheadLookBehindRegExp.test.ts | 50 +++++++++++++++++++ src/rules/noLookaheadLookbehindRegex.ts | 21 +++++++- 4 files changed, 78 insertions(+), 3 deletions(-) diff --git a/src/helpers/ast.ts b/src/helpers/ast.ts index ae70e0e..cc180e6 100644 --- a/src/helpers/ast.ts +++ b/src/helpers/ast.ts @@ -15,3 +15,7 @@ export function isStringLiteralRegExp(literal: Literal & Rule.NodeParentExtensio literal.parent.callee.name === "RegExp" ); } + +export function isBinaryExpression(literal: Literal & Rule.NodeParentExtension) { + return literal.parent !== null && literal.parent.type === "BinaryExpression"; +} diff --git a/src/helpers/createReport.ts b/src/helpers/createReport.ts index a5685e9..48abace 100644 --- a/src/helpers/createReport.ts +++ b/src/helpers/createReport.ts @@ -7,8 +7,12 @@ import { } from "../helpers/analyzeRegExpForLookaheadAndLookbehind"; import { collectUnsupportedTargets, formatLinterMessage } from "../helpers/caniuse"; +type NodeToReport = + | (ESTree.Literal & Rule.NodeParentExtension) + | (ESTree.TemplateLiteral & Rule.NodeParentExtension); + export function createContextReport( - node: ESTree.Literal & Rule.NodeParentExtension, + node: NodeToReport, context: Rule.RuleContext, violators: ReturnType, targets: ReturnType, diff --git a/src/rules/noLookAheadLookBehindRegExp.test.ts b/src/rules/noLookAheadLookBehindRegExp.test.ts index 6b8a3ca..5588b19 100644 --- a/src/rules/noLookAheadLookBehindRegExp.test.ts +++ b/src/rules/noLookAheadLookBehindRegExp.test.ts @@ -70,6 +70,56 @@ tester.run("noLookaheadLookbehindRegexp", noLookaheadLookbehindRegexp, { ], }; }), + ...groups.map((g) => { + return { + code: `new RegExp("(${g.expression})" + "")`, + errors: [ + { + message: `Disallowed ${g.type} match group at position 1`, + }, + ], + }; + }), + ...groups.map((g) => { + return { + code: `new RegExp("" + "(${g.expression})")`, + errors: [ + { + message: `Disallowed ${g.type} match group at position 1`, + }, + ], + }; + }), + ...groups.map((g) => { + return { + code: `new RegExp("" + "(${g.expression})" + "")`, + errors: [ + { + message: `Disallowed ${g.type} match group at position 1`, + }, + ], + }; + }), + ...groups.map((g) => { + return { + code: `new RegExp(\`(${g.expression})\`)`, + errors: [ + { + message: `Disallowed ${g.type} match group at position 0`, + }, + ], + }; + }), + ...groups.map((g) => { + return { + code: `new RegExp(\`some expression (${g.expression})\`)`, + errors: [ + { + message: `Disallowed ${g.type} match group at position 16`, + }, + ], + }; + }), ], }); diff --git a/src/rules/noLookaheadLookbehindRegex.ts b/src/rules/noLookaheadLookbehindRegex.ts index 1113a7d..b270bb8 100644 --- a/src/rules/noLookaheadLookbehindRegex.ts +++ b/src/rules/noLookaheadLookbehindRegex.ts @@ -7,7 +7,7 @@ import { CheckableExpression, } from "../helpers/analyzeRegExpForLookaheadAndLookbehind"; import { collectBrowserTargets, collectUnsupportedTargets } from "../helpers/caniuse"; -import { isStringLiteralRegExp, isRegExpLiteral } from "../helpers/ast"; +import { isStringLiteralRegExp, isRegExpLiteral, isBinaryExpression } from "../helpers/ast"; import { createContextReport } from "../helpers/createReport"; export const DEFAULT_OPTIONS: AnalyzeOptions["rules"] = { @@ -85,8 +85,25 @@ const noLookaheadLookbehindRegexp: Rule.RuleModule = { if (!unsupportedTargets.length && hasConfig) return {}; return { + TemplateLiteral(node: ESTree.TemplateLiteral & Rule.NodeParentExtension): void { + for (let quasi of node.quasis) { + if (typeof quasi.value.raw === "string") { + const unsupportedGroups = analyzeRegExpForLookaheadAndLookbehind( + quasi.value.raw, + rules // For string literals, we need to pass the raw value which includes escape characters. + ); + + if (unsupportedGroups.length > 0) { + createContextReport(node, context, unsupportedGroups, unsupportedTargets, config); + } + } + } + }, Literal(node: ESTree.Literal & Rule.NodeParentExtension): void { - if (isStringLiteralRegExp(node) && typeof node.raw === "string") { + if ( + (isStringLiteralRegExp(node) || isBinaryExpression(node)) && + typeof node.raw === "string" + ) { const unsupportedGroups = analyzeRegExpForLookaheadAndLookbehind( node.raw, rules // For string literals, we need to pass the raw value which includes escape characters.