🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
Book a DemoInstallSign in
Socket

eslint-plugin-regexp

Package Overview
Dependencies
Maintainers
2
Versions
79
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

eslint-plugin-regexp - npm Package Compare versions

Comparing version

to
1.1.0

80

dist/rules/no-useless-flag.js

@@ -7,3 +7,3 @@ "use strict";

class RegExpReference {
constructor(regExpContext, defineNode) {
constructor(regExpContext) {
this.readNodes = new Map();

@@ -15,4 +15,6 @@ this.state = {

this.regExpContext = regExpContext;
this.defineNode = defineNode;
}
get defineNode() {
return this.regExpContext.regexpNode;
}
addReadNode(node) {

@@ -84,18 +86,2 @@ this.readNodes.set(node, {});

}
function getFlagLocation(context, node, flag) {
const sourceCode = context.getSourceCode();
if (node.type === "Literal") {
const flagIndex = node.range[1] -
node.regex.flags.length +
node.regex.flags.indexOf(flag);
return {
start: sourceCode.getLocFromIndex(flagIndex),
end: sourceCode.getLocFromIndex(flagIndex + 1),
};
}
if (node.arguments.length >= 2) {
return node.arguments[1].loc;
}
return context.getSourceCode().getTokenAfter(node.arguments[0]).loc;
}
function fixRemoveFlag({ flagsString, fixReplaceFlags }, flag) {

@@ -110,3 +96,3 @@ if (flagsString) {

createVisitor(regExpContext) {
const { flags, regexpNode, toCharSet, ownsFlags } = regExpContext;
const { flags, regexpNode, toCharSet, ownsFlags, getFlagLocation, } = regExpContext;
if (!flags.ignoreCase || !ownsFlags) {

@@ -150,3 +136,3 @@ return {};

node: regexpNode,
loc: getFlagLocation(context, regexpNode, "i"),
loc: getFlagLocation("i"),
messageId: "uselessIgnoreCaseFlag",

@@ -164,3 +150,3 @@ fix: fixRemoveFlag(regExpContext, "i"),

createVisitor(regExpContext) {
const { flags, regexpNode, ownsFlags } = regExpContext;
const { flags, regexpNode, ownsFlags, getFlagLocation, } = regExpContext;
if (!flags.multiline || !ownsFlags) {

@@ -180,3 +166,3 @@ return {};

node: regexpNode,
loc: getFlagLocation(context, regexpNode, "m"),
loc: getFlagLocation("m"),
messageId: "uselessMultilineFlag",

@@ -194,3 +180,3 @@ fix: fixRemoveFlag(regExpContext, "m"),

createVisitor(regExpContext) {
const { flags, regexpNode, ownsFlags } = regExpContext;
const { flags, regexpNode, ownsFlags, getFlagLocation, } = regExpContext;
if (!flags.dotAll || !ownsFlags) {

@@ -210,3 +196,3 @@ return {};

node: regexpNode,
loc: getFlagLocation(context, regexpNode, "s"),
loc: getFlagLocation("s"),
messageId: "uselessDotAllFlag",

@@ -223,6 +209,7 @@ fix: fixRemoveFlag(regExpContext, "s"),

function reportUselessGlobalFlag(regExpReference, data) {
const { getFlagLocation } = regExpReference.regExpContext;
const node = regExpReference.defineNode;
context.report({
node,
loc: getFlagLocation(context, node, "g"),
loc: getFlagLocation("g"),
messageId: data.kind === 0

@@ -314,6 +301,7 @@ ? "uselessGlobalFlagForSplit"

function reportUselessStickyFlag(regExpReference, data) {
const { getFlagLocation } = regExpReference.regExpContext;
const node = regExpReference.defineNode;
context.report({
node,
loc: getFlagLocation(context, node, "y"),
loc: getFlagLocation("y"),
messageId: "uselessStickyFlag",

@@ -409,3 +397,3 @@ fix: data.fixable

if (flags[flag]) {
const regExpReference = new RegExpReference(regExpContext, regexpNode);
const regExpReference = new RegExpReference(regExpContext);
regExpReferenceList.push(regExpReference);

@@ -504,2 +492,38 @@ regExpReferenceMap.set(regexpNode, regExpReference);

}
function createOwnedRegExpFlagsVisitor(context) {
const sourceCode = context.getSourceCode();
function removeFlags(node) {
const newFlags = node.regex.flags.replace(/[^u]+/g, "");
if (newFlags === node.regex.flags) {
return;
}
context.report({
node,
loc: utils_1.getFlagsLocation(sourceCode, node, node),
messageId: "uselessFlagsOwned",
fix(fixer) {
const range = utils_1.getFlagsRange(node);
return fixer.replaceTextRange(range, newFlags);
},
});
}
return utils_1.defineRegexpVisitor(context, {
createSourceVisitor(regExpContext) {
var _a;
const { patternSource, regexpNode } = regExpContext;
if (patternSource.isStringValue()) {
patternSource.getOwnedRegExpLiterals().forEach(removeFlags);
}
else {
if (regexpNode.arguments.length >= 2) {
const ownedNode = (_a = patternSource.regexpValue) === null || _a === void 0 ? void 0 : _a.ownedNode;
if (ownedNode) {
removeFlags(ownedNode);
}
}
}
return {};
},
});
}
function parseOption(userOption) {

@@ -557,2 +581,3 @@ var _a;

uselessStickyFlag: "The 'y' flag is unnecessary because 'String.prototype.split' ignores the 'y' flag.",
uselessFlagsOwned: "The flags of this RegExp literal are useless because only the source of the regex is used.",
},

@@ -579,4 +604,5 @@ type: "suggestion",

}
visitor = utils_1.compositingVisitors(visitor, createOwnedRegExpFlagsVisitor(context));
return visitor;
},
});

@@ -76,2 +76,14 @@ "use strict";

}
getOwnedRegExpLiteral() {
if (utils_1.isRegexpLiteral(this.node)) {
return this.node;
}
if (this.node.type === "MemberExpression" &&
this.node.object.type !== "Super" &&
utils_1.isRegexpLiteral(this.node.object) &&
utils_1.getPropertyName(this.node) === "source") {
return this.node.object;
}
return null;
}
getReplaceRange(range) {

@@ -81,11 +93,9 @@ if (!this.contains(range)) {

}
const regexp = this.getOwnedRegExpLiteral();
if (regexp) {
return PatternReplaceRange.fromLiteral(regexp, this.sourceCode, this, range);
}
if (this.node.type === "Literal") {
return PatternReplaceRange.fromLiteral(this.node, this.sourceCode, this, range);
}
if (this.node.type === "MemberExpression" &&
this.node.object.type !== "Super" &&
utils_1.isRegexpLiteral(this.node.object) &&
utils_1.getPropertyName(this.node) === "source") {
return PatternReplaceRange.fromLiteral(this.node.object, this.sourceCode, this, range);
}
return null;

@@ -191,2 +201,12 @@ }

}
getOwnedRegExpLiterals() {
const literals = [];
for (const segment of this.segments) {
const regexp = segment.getOwnedRegExpLiteral();
if (regexp) {
literals.push(regexp);
}
}
return literals;
}
}

@@ -193,0 +213,0 @@ exports.PatternSource = PatternSource;

@@ -13,3 +13,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.isEscapeSequence = exports.isUseHexEscape = exports.getEscapeSequenceKind = exports.EscapeSequenceKind = exports.isUnicodeCodePointEscape = exports.isUnicodeEscape = exports.isHexadecimalEscape = exports.isControlEscape = exports.isOctalEscape = exports.canUnwrapped = exports.mightCreateNewElement = exports.toCharSetSource = exports.quantToString = exports.getQuantifierOffsets = exports.compositingVisitors = exports.defineRegexpVisitor = exports.createRule = exports.parseFlags = exports.FLAG_UNICODE = exports.FLAG_STICKY = exports.FLAG_MULTILINE = exports.FLAG_IGNORECASE = exports.FLAG_DOTALL = exports.FLAG_GLOBAL = void 0;
exports.isEscapeSequence = exports.isUseHexEscape = exports.getEscapeSequenceKind = exports.EscapeSequenceKind = exports.isUnicodeCodePointEscape = exports.isUnicodeEscape = exports.isHexadecimalEscape = exports.isControlEscape = exports.isOctalEscape = exports.canUnwrapped = exports.mightCreateNewElement = exports.toCharSetSource = exports.quantToString = exports.getQuantifierOffsets = exports.getFlagsLocation = exports.getFlagsRange = exports.compositingVisitors = exports.defineRegexpVisitor = exports.createRule = exports.parseFlags = exports.FLAG_UNICODE = exports.FLAG_STICKY = exports.FLAG_MULTILINE = exports.FLAG_IGNORECASE = exports.FLAG_DOTALL = exports.FLAG_GLOBAL = void 0;
const regexpp_1 = require("regexpp");

@@ -90,3 +90,3 @@ const eslint_utils_1 = require("eslint-utils");

const parser = new regexpp_1.RegExpParser();
function verify(patternNode, regexpNode, patternSource, flagsString, ownsFlags, createVisitor) {
function verify(patternNode, flagsNode, regexpNode, patternSource, flagsString, ownsFlags, createVisitor) {
const flags = parseFlags(flagsString || "");

@@ -101,2 +101,3 @@ if (!patternSource) {

flagsString,
flagsNode,
ownsFlags,

@@ -120,2 +121,3 @@ })));

flagsString,
flagsNode,
ownsFlags,

@@ -129,2 +131,3 @@ })));

regexpNode,
flagsNode,
context,

@@ -136,6 +139,7 @@ flags,

}
const ownedRegExpLiterals = new Set();
return {
"Program:exit": programExit,
Literal(node) {
if (!utils_1.isRegexpLiteral(node)) {
if (!utils_1.isRegexpLiteral(node) || ownedRegExpLiterals.has(node)) {
return;

@@ -145,3 +149,3 @@ }

const patternSource = pattern_source_1.PatternSource.fromRegExpLiteral(context, node);
verify(node, node, patternSource, flagsString, true, (base) => {
verify(node, node, node, patternSource, flagsString, true, (base) => {
return createLiteralVisitorFromRules(rules, Object.assign({ node,

@@ -158,12 +162,18 @@ flagsString, ownsFlags: true, regexpNode: node }, base));

const newOrCall = node;
const [patternNode, flagsNode] = newOrCall.arguments;
if (!patternNode || patternNode.type === "SpreadElement") {
const args = newOrCall.arguments;
const [patternArg, flagsArg] = args;
if (!patternArg || patternArg.type === "SpreadElement") {
continue;
}
const patternSource = pattern_source_1.PatternSource.fromExpression(context, patternNode);
const patternSource = pattern_source_1.PatternSource.fromExpression(context, patternArg);
patternSource === null || patternSource === void 0 ? void 0 : patternSource.getOwnedRegExpLiterals().forEach((n) => ownedRegExpLiterals.add(n));
let flagsNode = null;
let flagsString = null;
let ownsFlags = false;
if (flagsNode && flagsNode.type !== "SpreadElement") {
flagsString = ast_utils_1.getStringIfConstant(context, flagsNode);
ownsFlags = utils_1.isStringLiteral(flagsNode);
if (flagsArg) {
if (flagsArg.type !== "SpreadElement") {
flagsNode = flagsArg;
flagsString = ast_utils_1.getStringIfConstant(context, flagsArg);
ownsFlags = utils_1.isStringLiteral(flagsArg);
}
}

@@ -173,7 +183,9 @@ else if (patternSource && patternSource.regexpValue) {

ownsFlags = Boolean(patternSource.regexpValue.ownedNode);
flagsNode = patternSource.regexpValue.ownedNode;
}
regexpDataList.push({
call: newOrCall,
patternNode,
patternNode: patternArg,
patternSource,
flagsNode,
flagsString,

@@ -183,4 +195,4 @@ ownsFlags,

}
for (const { call, patternNode, patternSource, flagsString, ownsFlags, } of regexpDataList) {
verify(patternNode, call, patternSource, flagsString, ownsFlags, (base) => {
for (const { call, patternNode, patternSource, flagsNode, flagsString, ownsFlags, } of regexpDataList) {
verify(patternNode, flagsNode, call, patternSource, flagsString, ownsFlags, (base) => {
return createSourceVisitorFromRules(rules, Object.assign({ node: patternNode, flagsString,

@@ -260,3 +272,3 @@ ownsFlags, regexpNode: call }, base));

exports.compositingVisitors = compositingVisitors;
function buildRegExpContextBase({ patternSource, regexpNode, context, flags, parsedPattern, }) {
function buildRegExpContextBase({ patternSource, regexpNode, flagsNode, context, flags, parsedPattern, }) {
const sourceCode = context.getSourceCode();

@@ -287,3 +299,4 @@ const cacheCharSet = new WeakMap();

},
getFlagsLocation: () => getFlagsLocation(sourceCode, regexpNode),
getFlagsLocation: () => getFlagsLocation(sourceCode, regexpNode, flagsNode),
getFlagLocation: (flag) => getFlagLocation(sourceCode, regexpNode, flagsNode, flag),
fixReplaceNode: (node, replacement) => {

@@ -296,3 +309,3 @@ return fixReplaceNode(patternSource, node, replacement);

fixReplaceFlags: (newFlags) => {
return fixReplaceFlags(patternSource, regexpNode, newFlags);
return fixReplaceFlags(patternSource, regexpNode, flagsNode, newFlags);
},

@@ -306,3 +319,3 @@ getUsageOfPattern: () => (cacheUsageOfPattern !== null && cacheUsageOfPattern !== void 0 ? cacheUsageOfPattern : (cacheUsageOfPattern = get_usage_of_pattern_1.getUsageOfPattern(regexpNode, context))),

}
function buildUnparsableRegExpContextBase({ patternSource, patternNode, regexpNode, context, flags, flagsString, ownsFlags, }) {
function buildUnparsableRegExpContextBase({ patternSource, patternNode, regexpNode, context, flags, flagsString, flagsNode, ownsFlags, }) {
const sourceCode = context.getSourceCode();

@@ -315,3 +328,4 @@ return {

ownsFlags,
getFlagsLocation: () => getFlagsLocation(sourceCode, regexpNode),
getFlagsLocation: () => getFlagsLocation(sourceCode, regexpNode, flagsNode),
getFlagLocation: (flag) => getFlagLocation(sourceCode, regexpNode, flagsNode, flag),
fixReplaceFlags: (newFlags) => {

@@ -321,25 +335,27 @@ if (!patternSource) {

}
return fixReplaceFlags(patternSource, regexpNode, newFlags);
return fixReplaceFlags(patternSource, regexpNode, flagsNode, newFlags);
},
};
}
function getFlagsRange(regexpNode) {
if (utils_1.isRegexpLiteral(regexpNode)) {
function getFlagsRange(flagsNode) {
if (!flagsNode) {
return null;
}
if (utils_1.isRegexpLiteral(flagsNode)) {
return [
regexpNode.range[1] - regexpNode.regex.flags.length,
regexpNode.range[1],
flagsNode.range[1] - flagsNode.regex.flags.length,
flagsNode.range[1],
];
}
const flagsArg = regexpNode.arguments[1];
if (flagsArg &&
flagsArg.type === "Literal" &&
typeof flagsArg.value === "string") {
return [flagsArg.range[0] + 1, flagsArg.range[1] - 1];
if (utils_1.isStringLiteral(flagsNode)) {
return [flagsNode.range[0] + 1, flagsNode.range[1] - 1];
}
return null;
}
function getFlagsLocation(sourceCode, regexpNode) {
const range = getFlagsRange(regexpNode);
exports.getFlagsRange = getFlagsRange;
function getFlagsLocation(sourceCode, regexpNode, flagsNode) {
var _a;
const range = getFlagsRange(flagsNode);
if (range == null) {
return regexpNode.loc;
return (_a = flagsNode === null || flagsNode === void 0 ? void 0 : flagsNode.loc) !== null && _a !== void 0 ? _a : regexpNode.loc;
}

@@ -351,2 +367,35 @@ return {

}
exports.getFlagsLocation = getFlagsLocation;
function getFlagRange(sourceCode, flagsNode, flag) {
if (!flagsNode || !flag) {
return null;
}
if (utils_1.isRegexpLiteral(flagsNode)) {
const index = flagsNode.regex.flags.indexOf(flag);
if (index === -1) {
return null;
}
const start = flagsNode.range[1] - flagsNode.regex.flags.length + index;
return [start, start + 1];
}
if (utils_1.isStringLiteral(flagsNode)) {
const index = flagsNode.value.indexOf(flag);
if (index === -1) {
return null;
}
return utils_1.getStringValueRange(sourceCode, flagsNode, index, index + 1);
}
return null;
}
function getFlagLocation(sourceCode, regexpNode, flagsNode, flag) {
var _a;
const range = getFlagRange(sourceCode, flagsNode, flag);
if (range == null) {
return (_a = flagsNode === null || flagsNode === void 0 ? void 0 : flagsNode.loc) !== null && _a !== void 0 ? _a : regexpNode.loc;
}
return {
start: sourceCode.getLocFromIndex(range[0]),
end: sourceCode.getLocFromIndex(range[1]),
};
}
function fixReplaceNode(patternSource, regexpNode, replacement) {

@@ -401,3 +450,3 @@ return (fixer) => {

}
function fixReplaceFlags(patternSource, regexpNode, replacement) {
function fixReplaceFlags(patternSource, regexpNode, flagsNode, replacement) {
return (fixer) => {

@@ -420,3 +469,3 @@ let newFlags;

}
const range = getFlagsRange(regexpNode);
const range = getFlagsRange(flagsNode);
if (range == null) {

@@ -423,0 +472,0 @@ return null;

{
"name": "eslint-plugin-regexp",
"version": "1.0.0",
"version": "1.1.0",
"description": "ESLint plugin for finding RegExp mistakes and RegExp style guide violations.",

@@ -55,3 +55,3 @@ "engines": {

"devDependencies": {
"@ota-meshi/eslint-plugin": "^0.7.0",
"@ota-meshi/eslint-plugin": "^0.8.0",
"@types/chai": "^4.2.18",

@@ -68,3 +68,3 @@ "@types/eslint": "^7.2.0",

"env-cmd": "^10.1.0",
"eslint": "^7.3.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.0.0",

@@ -76,4 +76,4 @@ "eslint-plugin-eslint-comments": "^3.2.0",

"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-regexp": "^0.13.1",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-regexp": "^1.0.0",
"eslint-plugin-vue": "^7.5.0",

@@ -80,0 +80,0 @@ "eslint-plugin-yml": "^0.10.0",