Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/helpers/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
6 changes: 5 additions & 1 deletion src/helpers/createReport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeof analyzeRegExpForLookaheadAndLookbehind>,
targets: ReturnType<typeof collectUnsupportedTargets>,
Expand Down
50 changes: 50 additions & 0 deletions src/rules/noLookAheadLookBehindRegExp.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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`,
},
],
};
}),
],
});

Expand Down
21 changes: 19 additions & 2 deletions src/rules/noLookaheadLookbehindRegex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"] = {
Expand Down Expand Up @@ -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) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would end up reporting the problem on any string template literal (regardless if it is used inside a regexp or not). We should first check if the template literal is inside a regexp constructor before we iterate over all the nodes

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.
Expand Down