You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
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
0.8.0

dist/rules/confusing-quantifier.js

9

dist/rules/letter-case.js

@@ -70,10 +70,3 @@ "use strict";

},
fix(fixer) {
const range = utils_1.getRegexpRange(sourceCode, node, reportNode);
if (range == null) {
return null;
}
const newText = convertText(CONVERTER[letterCase]);
return fixer.replaceTextRange(range, utils_1.fixerApplyEscape(newText, node));
},
fix: utils_1.fixReplaceNode(sourceCode, node, reportNode, () => convertText(CONVERTER[letterCase])),
});

@@ -80,0 +73,0 @@ }

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const regexp_ast_analysis_1 = require("regexp-ast-analysis");
const OPTION_SS1 = "[\\s\\S]";

@@ -8,9 +9,2 @@ const OPTION_SS2 = "[\\S\\s]";

const OPTION_DOTALL = "dotAll";
function getCharacterSetKey(node) {
if (node.kind === "property") {
return `\\p{${node.kind +
(node.value == null ? node.key : `${node.key}=${node.value}`)}}`;
}
return node.kind;
}
exports.default = utils_1.createRule("match-any", {

@@ -46,3 +40,3 @@ meta: {

messages: {
unexpected: 'Unexpected using "{{expr}}" to match any character.',
unexpected: "Unexpected using '{{expr}}' to match any character.",
},

@@ -54,9 +48,15 @@ type: "suggestion",

const sourceCode = context.getSourceCode();
const allowList = (_b = (_a = context.options[0]) === null || _a === void 0 ? void 0 : _a.allows) !== null && _b !== void 0 ? _b : [OPTION_SS1, OPTION_DOTALL];
const allowList = (_b = (_a = context.options[0]) === null || _a === void 0 ? void 0 : _a.allows) !== null && _b !== void 0 ? _b : [
OPTION_SS1,
OPTION_DOTALL,
];
const allows = new Set(allowList);
const prefer = (allowList[0] !== OPTION_DOTALL && allowList[0]) || null;
function fix(fixer, node, regexpNode) {
if (!prefer) {
const preference = allowList[0] || null;
function fix(fixer, node, regexpNode, flags) {
if (!preference) {
return null;
}
if (preference === OPTION_DOTALL && !flags.dotAll) {
return null;
}
const range = utils_1.getRegexpRange(sourceCode, node, regexpNode);

@@ -67,118 +67,45 @@ if (range == null) {

if (regexpNode.type === "CharacterClass" &&
prefer.startsWith("[") &&
prefer.endsWith("]")) {
return fixer.replaceTextRange([range[0] + 1, range[1] - 1], utils_1.fixerApplyEscape(prefer.slice(1, -1), node));
preference.startsWith("[") &&
preference.endsWith("]")) {
return fixer.replaceTextRange([range[0] + 1, range[1] - 1], utils_1.fixerApplyEscape(preference.slice(1, -1), node));
}
return fixer.replaceTextRange(range, utils_1.fixerApplyEscape(prefer, node));
const replacement = preference === OPTION_DOTALL ? "." : preference;
return fixer.replaceTextRange(range, utils_1.fixerApplyEscape(replacement, node));
}
function createVisitor(node, _pattern, flags) {
let characterClassData = null;
function createVisitor(node, _pattern, flagsStr) {
const flags = utils_1.parseFlags(flagsStr);
return {
onCharacterSetEnter(csNode) {
if (csNode.kind === "any") {
if (flags.includes(utils_1.FLAG_DOTALL)) {
if (!allows.has(OPTION_DOTALL)) {
context.report({
node,
loc: utils_1.getRegexpLocation(sourceCode, node, csNode),
messageId: "unexpected",
data: {
expr: ".",
},
fix(fixer) {
return fix(fixer, node, csNode);
},
});
}
}
return;
if (csNode.kind === "any" &&
flags.dotAll &&
!allows.has(OPTION_DOTALL)) {
context.report({
node,
loc: utils_1.getRegexpLocation(sourceCode, node, csNode),
messageId: "unexpected",
data: {
expr: ".",
},
fix(fixer) {
return fix(fixer, node, csNode, flags);
},
});
}
if (characterClassData &&
!characterClassData.reported &&
!characterClassData.node.negate) {
const key = getCharacterSetKey(csNode);
const alreadyCharSet = characterClassData.charSets.get(key);
if (alreadyCharSet != null &&
alreadyCharSet.negate === !csNode.negate) {
const ccNode = characterClassData.node;
if (!ccNode.negate &&
ccNode.elements.length === 2 &&
alreadyCharSet.kind === "space") {
if (!alreadyCharSet.negate) {
if (allows.has(OPTION_SS1)) {
return;
}
}
else {
if (allows.has(OPTION_SS2)) {
return;
}
}
}
context.report({
node,
loc: utils_1.getRegexpLocation(sourceCode, node, ccNode),
messageId: "unexpected",
data: {
expr: ccNode.raw,
},
fix(fixer) {
return fix(fixer, node, ccNode);
},
});
characterClassData.reported = true;
}
else {
characterClassData.charSets.set(key, csNode);
}
}
},
onCharacterClassRangeEnter(ccrNode) {
if (ccrNode.min.value === 0 &&
ccrNode.max.value === 65535) {
if (characterClassData &&
!characterClassData.reported &&
!characterClassData.node.negate) {
const ccNode = characterClassData.node;
context.report({
node,
loc: utils_1.getRegexpLocation(sourceCode, node, ccNode),
messageId: "unexpected",
data: {
expr: ccNode.raw,
},
fix(fixer) {
return fix(fixer, node, ccNode);
},
});
characterClassData.reported = true;
}
}
},
onCharacterClassEnter(ccNode) {
if (ccNode.elements.length === 0) {
if (ccNode.negate && !allows.has(OPTION_CARET)) {
context.report({
node,
loc: utils_1.getRegexpLocation(sourceCode, node, ccNode),
messageId: "unexpected",
data: {
expr: "[^]",
},
fix(fixer) {
return fix(fixer, node, ccNode);
},
});
}
return;
if (regexp_ast_analysis_1.matchesAllCharacters(ccNode, flags) &&
!allows.has(ccNode.raw)) {
context.report({
node,
loc: utils_1.getRegexpLocation(sourceCode, node, ccNode),
messageId: "unexpected",
data: {
expr: ccNode.raw,
},
fix(fixer) {
return fix(fixer, node, ccNode, flags);
},
});
}
characterClassData = {
node: ccNode,
charSets: new Map(),
reported: false,
};
},
onCharacterClassLeave() {
characterClassData = null;
},
};

@@ -185,0 +112,0 @@ }

@@ -33,9 +33,3 @@ "use strict";

data: { negatedCharSet },
fix(fixer) {
const range = utils_1.getRegexpRange(sourceCode, node, ccNode);
if (range == null) {
return null;
}
return fixer.replaceTextRange(range, utils_1.fixerApplyEscape(negatedCharSet, node));
},
fix: utils_1.fixReplaceNode(sourceCode, node, ccNode, negatedCharSet),
});

@@ -42,0 +36,0 @@ }

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const CPS_SINGLE_SPACES = [...utils_1.CPS_SINGLE_SPACES];
function isCharacterInCharacterClassRange(char, range) {

@@ -30,3 +31,3 @@ return range.min.value <= char.value && char.value <= range.max.value;

if (set.negate) {
return [];
return { intersections: [] };
}

@@ -37,2 +38,8 @@ const codePointRange = [range.min.value, range.max.value];

}
function isCodePointInRange(codePoint) {
return codePointRange[0] <= codePoint && codePoint <= codePointRange[1];
}
function isRangeInRange(cpRange) {
return (codePointRange[0] <= cpRange[0] && cpRange[1] <= codePointRange[1]);
}
function getIntersectionAndNotSeparate(otherRange) {

@@ -50,7 +57,14 @@ const intersection = getRangesIntersection(codePointRange, otherRange);

const intersection = getRangesIntersection(codePointRange, utils_1.CP_RANGE_DIGIT);
return intersection ? [intersection] : [];
return { intersections: intersection ? [intersection] : [] };
}
if (set.kind === "space") {
if (isRangeInRange(utils_1.CP_RANGE_SPACES) &&
CPS_SINGLE_SPACES.every((codePoint) => isCodePointInRange(codePoint))) {
return {
intersections: [],
set,
};
}
const result = [];
for (const codePoint of utils_1.CPS_SINGLE_SPACES) {
for (const codePoint of CPS_SINGLE_SPACES) {
if (isCodePointIsRangeEdge(codePoint)) {

@@ -61,5 +75,14 @@ result.push(codePoint);

const intersection = getIntersectionAndNotSeparate(utils_1.CP_RANGE_SPACES);
return intersection ? [...result, intersection] : result;
return {
intersections: intersection ? [...result, intersection] : result,
};
}
if (set.kind === "word") {
if (isCodePointInRange(utils_1.CP_LOW_LINE) &&
utils_1.CP_RANGES_WORDS.every((r) => isRangeInRange(r))) {
return {
intersections: [],
set,
};
}
const intersections = [];

@@ -72,7 +95,9 @@ for (const wordRange of utils_1.CP_RANGES_WORDS) {

}
return isCodePointIsRangeEdge(utils_1.CP_LOW_LINE)
? [...intersections, utils_1.CP_LOW_LINE]
: intersections;
return {
intersections: isCodePointIsRangeEdge(utils_1.CP_LOW_LINE)
? [...intersections, utils_1.CP_LOW_LINE]
: intersections,
};
}
return [];
return { intersections: [] };
}

@@ -116,5 +141,5 @@ function groupingElements(elements) {

return {
characters,
characterClassRanges,
characterSets,
characters: [...characters.values()],
characterClassRanges: [...characterClassRanges.values()],
characterSets: [...characterSets.values()],
};

@@ -148,5 +173,6 @@ function buildCharacterSetKey(characterSet) {

messages: {
duplicates: 'Unexpected element "{{element}}" duplication.',
charIsIncluded: 'The "{{char}}" is included in "{{element}}".',
intersect: 'Unexpected intersection of "{{elementA}}" and "{{elementB}}" was found "{{intersection}}".',
duplicates: "Unexpected element '{{element}}' duplication.",
charIsIncluded: "The '{{char}}' is included in '{{element}}'.",
charSetIsInRange: "The '{{charSet}}' is included in '{{range}}'.",
intersect: "Unexpected intersection of '{{elementA}}' and '{{elementB}}' was found '{{intersection}}'.",
},

@@ -200,2 +226,13 @@ },

}
function reportCharSetInRange(node, set, range) {
context.report({
node,
loc: utils_1.getRegexpLocation(sourceCode, node, set),
messageId: "charSetIsInRange",
data: {
charSet: set.raw,
range: range.raw,
},
});
}
function createVisitor(node) {

@@ -205,7 +242,7 @@ return {

const { characters, characterClassRanges, characterSets, } = groupingElements(ccNode.elements);
for (const [char, ...dupeChars] of characters.values()) {
for (const [char, ...dupeChars] of characters) {
if (dupeChars.length) {
reportDuplicates(node, [char, ...dupeChars]);
}
for (const [range] of characterClassRanges.values()) {
for (const [range] of characterClassRanges) {
if (isCharacterInCharacterClassRange(char, range)) {

@@ -215,3 +252,3 @@ reportCharIncluded(node, [char, ...dupeChars], range);

}
for (const [set] of characterSets.values()) {
for (const [set] of characterSets) {
if (isCharacterInCharacterSet(char, set)) {

@@ -222,10 +259,7 @@ reportCharIncluded(node, [char, ...dupeChars], set);

}
for (const [key, [range, ...dupeRanges],] of characterClassRanges) {
for (const [range, ...dupeRanges] of characterClassRanges) {
if (dupeRanges.length) {
reportDuplicates(node, [range, ...dupeRanges]);
}
for (const [keyOther, [rangeOther],] of characterClassRanges) {
if (keyOther === key) {
continue;
}
for (const [rangeOther] of characterClassRanges.filter(([ccr]) => ccr !== range)) {
const intersection = getCharacterClassRangesIntersection(range, rangeOther);

@@ -236,4 +270,7 @@ if (intersection) {

}
for (const [set] of characterSets.values()) {
const intersections = getCharacterClassRangeAndCharacterSetIntersections(range, set);
for (const [set] of characterSets) {
const { set: reportSet, intersections, } = getCharacterClassRangeAndCharacterSetIntersections(range, set);
if (reportSet) {
reportCharSetInRange(node, reportSet, range);
}
for (const intersection of intersections) {

@@ -244,3 +281,3 @@ reportIntersect(node, [range, ...dupeRanges], set, intersection);

}
for (const [set, ...dupeSets] of characterSets.values()) {
for (const [set, ...dupeSets] of characterSets) {
if (dupeSets.length) {

@@ -247,0 +284,0 @@ reportDuplicates(node, [set, ...dupeSets]);

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const regexp_ast_analysis_1 = require("regexp-ast-analysis");
const utils_1 = require("../utils");

@@ -12,4 +13,3 @@ exports.default = utils_1.createRule("no-empty-lookarounds-assertion", {

messages: {
unexpectedLookahead: "Unexpected empty lookahead.",
unexpectedLookbehind: "Unexpected empty lookbehind.",
unexpected: "Unexpected empty {{kind}}. It will trivially {{result}} all inputs.",
},

@@ -27,9 +27,11 @@ type: "suggestion",

}
if (aNode.alternatives.every((alt) => alt.elements.length === 0)) {
if (regexp_ast_analysis_1.isPotentiallyEmpty(aNode.alternatives)) {
context.report({
node,
loc: utils_1.getRegexpLocation(sourceCode, node, aNode),
messageId: aNode.kind === "lookahead"
? "unexpectedLookahead"
: "unexpectedLookbehind",
messageId: "unexpected",
data: {
kind: aNode.kind,
result: aNode.negate ? "reject" : "accept",
},
});

@@ -36,0 +38,0 @@ }

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

messages: {
unexpected: 'Unexpected "[\\b]". Use "\\u0008" instead.',
unexpected: "Unexpected '[\\b]'. Use '\\u0008' instead.",
},

@@ -15,0 +15,0 @@ type: "suggestion",

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

messages: {
unexpected: 'Unexpected invisible character. Use "{{instead}}" instead.',
unexpected: "Unexpected invisible character. Use '{{instead}}' instead.",
},

@@ -16,0 +16,0 @@ type: "suggestion",

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

messages: {
unexpected: 'Unexpected octal escape sequence "{{expr}}".',
unexpected: "Unexpected octal escape sequence '{{expr}}'.",
},

@@ -22,3 +22,12 @@ type: "suggestion",

onCharacterEnter(cNode) {
if (cNode.raw.startsWith("\\0") && cNode.raw !== "\\0") {
if (cNode.raw === "\\0") {
return;
}
if (!/^\\[0-7]+$/.test(cNode.raw)) {
return;
}
const report = cNode.raw.startsWith("\\0") ||
!(cNode.parent.type === "CharacterClass" ||
cNode.parent.type === "CharacterClassRange");
if (report) {
context.report({

@@ -25,0 +34,0 @@ node,

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

},
fix(fixer) {
const range = utils_1.getRegexpRange(sourceCode, node, ccNode);
if (range == null) {
return null;
}
fix: utils_1.fixReplaceNode(sourceCode, node, ccNode, () => {
let text = element.type === "CharacterClassRange"

@@ -103,4 +99,4 @@ ? element.min.raw

}
return fixer.replaceTextRange(range, utils_1.fixerApplyEscape(text, node));
},
return text;
}),
});

@@ -107,0 +103,0 @@ },

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

messages: {
unexpected: 'Unexpected quantifier "{{expr}}".',
unexpected: "Unexpected quantifier '{{expr}}'.",
},

@@ -15,0 +15,0 @@ type: "suggestion",

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

messageId: "unexpected",
fix(fixer) {
const range = utils_1.getRegexpRange(sourceCode, node, ccrNode);
if (range == null) {
return null;
}
fix: utils_1.fixReplaceNode(sourceCode, node, ccrNode, () => {
let text = ccrNode.min.value < ccrNode.max.value

@@ -44,6 +40,6 @@ ? ccrNode.min.raw + ccrNode.max.raw

next.raw === "-") {
text += utils_1.fixerApplyEscape("\\", node);
text += "\\";
}
return fixer.replaceTextRange(range, text);
},
return text;
}),
});

@@ -50,0 +46,0 @@ },

@@ -10,5 +10,6 @@ "use strict";

},
fixable: "code",
schema: [],
messages: {
unexpected: 'Unexpected quantifier "{{expr}}".',
unexpected: "Unexpected quantifier '{{expr}}'.",
},

@@ -38,2 +39,3 @@ type: "suggestion",

},
fix: utils_1.fixReplaceQuant(sourceCode, node, qNode, `{${qNode.min}}`),
});

@@ -40,0 +42,0 @@ }

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

messages: {
unexpected: 'Unexpected the disjunction of single element alternatives. Use character class "[...]" instead.',
unexpected: "Unexpected the disjunction of single element alternatives. Use character class '[...]' instead.",
},

@@ -16,0 +16,0 @@ type: "suggestion",

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

messages: {
unexpected: 'Unexpected {{type}} "{{expr}}". Use "{{instead}}" instead.',
unexpected: "Unexpected {{type}} '{{expr}}'. Use '{{instead}}' instead.",
},

@@ -46,9 +46,3 @@ type: "suggestion",

},
fix(fixer) {
const range = utils_1.getRegexpRange(sourceCode, node, reportNode);
if (range == null) {
return null;
}
return fixer.replaceTextRange(range, utils_1.fixerApplyEscape(instead, node));
},
fix: utils_1.fixReplaceNode(sourceCode, node, reportNode, instead),
});

@@ -55,0 +49,0 @@ }

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

messages: {
unexpected: 'Unexpected quantifier "{{expr}}". Use "+" instead.',
unexpected: "Unexpected quantifier '{{expr}}'. Use '+' instead.",
},

@@ -34,12 +34,3 @@ type: "suggestion",

},
fix(fixer) {
const range = utils_1.getRegexpRange(sourceCode, node, qNode);
if (range == null) {
return null;
}
return fixer.replaceTextRange([
range[0] + startOffset,
range[0] + endOffset,
], "+");
},
fix: utils_1.fixReplaceQuant(sourceCode, node, qNode, "+"),
});

@@ -46,0 +37,0 @@ }

@@ -89,19 +89,7 @@ "use strict";

getQuantifier() {
const greedy = this.greedy === false ? "?" : "";
if (this.min === 0 && this.max === Number.POSITIVE_INFINITY) {
return `*${greedy}`;
}
else if (this.min === 1 && this.max === Number.POSITIVE_INFINITY) {
return `+${greedy}`;
}
else if (this.min === 0 && this.max === 1) {
return `?${greedy}`;
}
else if (this.min === this.max) {
return `{${this.min}}`;
}
else if (this.max === Number.POSITIVE_INFINITY) {
return `{${this.min},}${greedy}`;
}
return `{${this.min},${this.max}}${greedy}`;
return utils_1.quantToString({
min: this.min,
max: this.max,
greedy: this.greedy !== false,
});
}

@@ -118,3 +106,3 @@ }

messages: {
unexpected: 'Unexpected consecutive same {{type}}. Use "{{quantifier}}" instead.',
unexpected: "Unexpected consecutive same {{type}}. Use '{{quantifier}}' instead.",
},

@@ -121,0 +109,0 @@ type: "suggestion",

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

messages: {
unexpected: 'Unexpected quantifier "{{expr}}". Use "?" instead.',
unexpectedGroup: 'Unexpected group "{{expr}}". Use "{{instead}}" instead.',
unexpected: "Unexpected quantifier '{{expr}}'. Use '?' instead.",
unexpectedGroup: "Unexpected group '{{expr}}'. Use '{{instead}}' instead.",
},

@@ -35,12 +35,3 @@ type: "suggestion",

},
fix(fixer) {
const range = utils_1.getRegexpRange(sourceCode, node, qNode);
if (range == null) {
return null;
}
return fixer.replaceTextRange([
range[0] + startOffset,
range[0] + endOffset,
], "?");
},
fix: utils_1.fixReplaceQuant(sourceCode, node, qNode, "?"),
});

@@ -87,9 +78,3 @@ }

},
fix(fixer) {
const range = utils_1.getRegexpRange(sourceCode, node, reportNode);
if (range == null) {
return null;
}
return fixer.replaceTextRange(range, utils_1.fixerApplyEscape(instead, node));
},
fix: utils_1.fixReplaceNode(sourceCode, node, reportNode, instead),
});

@@ -96,0 +81,0 @@ }

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

messages: {
unexpected: 'Unexpected multiple adjacent characters. Use "{{range}}" instead.',
unexpected: "Unexpected multiple adjacent characters. Use '{{range}}' instead.",
},

@@ -74,0 +74,0 @@ type: "suggestion",

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

messages: {
unexpected: 'Unexpected quantifier "{{expr}}". Use "*" instead.',
unexpected: "Unexpected quantifier '{{expr}}'. Use '*' instead.",
},

@@ -34,12 +34,3 @@ type: "suggestion",

},
fix(fixer) {
const range = utils_1.getRegexpRange(sourceCode, node, qNode);
if (range == null) {
return null;
}
return fixer.replaceTextRange([
range[0] + startOffset,
range[0] + endOffset,
], "*");
},
fix: utils_1.fixReplaceQuant(sourceCode, node, qNode, "*"),
});

@@ -46,0 +37,0 @@ }

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

messages: {
unexpected: 'Unexpected character "{{expr}}". Use "\\t" instead.',
unexpected: "Unexpected character '{{expr}}'. Use '\\t' instead.",
},

@@ -33,9 +33,3 @@ type: "suggestion",

},
fix(fixer) {
const range = utils_1.getRegexpRange(sourceCode, node, cNode);
if (range == null) {
return null;
}
return fixer.replaceTextRange(range, utils_1.fixerApplyEscape("\\t", node));
},
fix: utils_1.fixReplaceNode(sourceCode, node, cNode, "\\t"),
});

@@ -42,0 +36,0 @@ }

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

messageId: "disallowSurrogatePair",
fix(fixer) {
const range = utils_1.getRegexpRange(sourceCode, node, cNode);
if (range == null) {
return null;
}
fix: utils_1.fixReplaceNode(sourceCode, node, cNode, () => {
let text = String.fromCodePoint(cNode.value)

@@ -43,4 +39,4 @@ .codePointAt(0)

}
return fixer.replaceTextRange(range, utils_1.fixerApplyEscape(`\\u{${text}}`, node));
},
return `\\u{${text}}`;
}),
});

@@ -47,0 +43,0 @@ }

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

messages: {
unexpected: 'Unexpected {{type}} "{{expr}}". Use "{{instead}}" instead.',
unexpected: "Unexpected {{type}} '{{expr}}'. Use '{{instead}}' instead.",
},

@@ -89,9 +89,3 @@ type: "suggestion",

},
fix(fixer) {
const range = utils_1.getRegexpRange(sourceCode, node, ccNode);
if (range == null) {
return null;
}
return fixer.replaceTextRange(range, utils_1.fixerApplyEscape(instead, node));
},
fix: utils_1.fixReplaceNode(sourceCode, node, ccNode, instead),
});

@@ -98,0 +92,0 @@ }

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

Object.defineProperty(exports, "__esModule", { value: true });
exports.canUnwrapped = exports.getQuantifierOffsets = exports.fixerApplyEscape = exports.getRegexpLocation = exports.getRegexpRange = exports.defineRegexpVisitor = exports.createRule = exports.FLAG_UNICODE = exports.FLAG_STICKY = exports.FLAG_MULTILINE = exports.FLAG_IGNORECASE = exports.FLAG_DOTALL = exports.FLAG_GLOBAL = void 0;
exports.canUnwrapped = exports.quantToString = exports.getQuantifierOffsets = exports.fixReplaceQuant = exports.fixReplaceNode = exports.fixerApplyEscape = exports.getRegexpLocation = exports.getRegexpRange = 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");

@@ -27,2 +27,19 @@ const eslint_utils_1 = require("eslint-utils");

exports.FLAG_UNICODE = "u";
const flagsCache = new Map();
function parseFlags(flags) {
let cached = flagsCache.get(flags);
if (cached === undefined) {
cached = {
dotAll: flags.includes(exports.FLAG_DOTALL),
global: flags.includes(exports.FLAG_GLOBAL),
ignoreCase: flags.includes(exports.FLAG_IGNORECASE),
multiline: flags.includes(exports.FLAG_MULTILINE),
sticky: flags.includes(exports.FLAG_STICKY),
unicode: flags.includes(exports.FLAG_UNICODE),
};
flagsCache.set(flags, cached);
}
return cached;
}
exports.parseFlags = parseFlags;
function createRule(ruleName, rule) {

@@ -259,2 +276,43 @@ return {

exports.fixerApplyEscape = fixerApplyEscape;
function fixReplaceNode(sourceCode, node, regexpNode, replacement) {
return (fixer) => {
const range = getRegexpRange(sourceCode, node, regexpNode);
if (range == null) {
return null;
}
let text;
if (typeof replacement === "string") {
text = replacement;
}
else {
text = replacement();
if (text == null) {
return null;
}
}
return fixer.replaceTextRange(range, fixerApplyEscape(text, node));
};
}
exports.fixReplaceNode = fixReplaceNode;
function fixReplaceQuant(sourceCode, node, quantifier, replacement) {
return (fixer) => {
const range = getRegexpRange(sourceCode, node, quantifier);
if (range == null) {
return null;
}
let text;
if (typeof replacement === "string") {
text = replacement;
}
else {
text = replacement();
if (text == null) {
return null;
}
}
const [startOffset, endOffset] = getQuantifierOffsets(quantifier);
return fixer.replaceTextRange([range[0] + startOffset, range[0] + endOffset], text);
};
}
exports.fixReplaceQuant = fixReplaceQuant;
function getQuantifierOffsets(qNode) {

@@ -266,2 +324,34 @@ const startOffset = qNode.element.end - qNode.start;

exports.getQuantifierOffsets = getQuantifierOffsets;
function quantToString(quant) {
if (quant.max < quant.min ||
quant.min < 0 ||
!Number.isInteger(quant.min) ||
!(Number.isInteger(quant.max) || quant.max === Infinity)) {
throw new Error(`Invalid quantifier { min: ${quant.min}, max: ${quant.max} }`);
}
let value;
if (quant.min === 0 && quant.max === 1) {
value = "?";
}
else if (quant.min === 0 && quant.max === Infinity) {
value = "*";
}
else if (quant.min === 1 && quant.max === Infinity) {
value = "+";
}
else if (quant.min === quant.max) {
value = `{${quant.min}}`;
}
else if (quant.max === Infinity) {
value = `{${quant.min},}`;
}
else {
value = `{${quant.min},${quant.max}}`;
}
if (!quant.greedy) {
return `${value}?`;
}
return value;
}
exports.quantToString = quantToString;
function canUnwrapped(node, text) {

@@ -268,0 +358,0 @@ const parent = node.parent;

@@ -463,4 +463,4 @@ "use strict";

function isCoveredAltNodes(leftNodes, rightNodes, options) {
const left = options.canOmitRight ? omitEnds(leftNodes) : leftNodes;
const right = options.canOmitRight ? omitEnds(rightNodes) : rightNodes;
const left = options.canOmitRight ? omitEnds(leftNodes) : [...leftNodes];
const right = options.canOmitRight ? omitEnds(rightNodes) : [...rightNodes];
while (left.length && right.length) {

@@ -467,0 +467,0 @@ const le = left.shift();

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

exports.rules = void 0;
const confusing_quantifier_1 = __importDefault(require("../rules/confusing-quantifier"));
const letter_case_1 = __importDefault(require("../rules/letter-case"));

@@ -14,2 +15,3 @@ const match_any_1 = __importDefault(require("../rules/match-any"));

const no_dupe_disjunctions_1 = __importDefault(require("../rules/no-dupe-disjunctions"));
const no_empty_alternative_1 = __importDefault(require("../rules/no-empty-alternative"));
const no_empty_group_1 = __importDefault(require("../rules/no-empty-group"));

@@ -19,2 +21,3 @@ const no_empty_lookarounds_assertion_1 = __importDefault(require("../rules/no-empty-lookarounds-assertion"));

const no_invisible_character_1 = __importDefault(require("../rules/no-invisible-character"));
const no_lazy_ends_1 = __importDefault(require("../rules/no-lazy-ends"));
const no_legacy_features_1 = __importDefault(require("../rules/no-legacy-features"));

@@ -32,2 +35,3 @@ const no_octal_1 = __importDefault(require("../rules/no-octal"));

const no_useless_two_nums_quantifier_1 = __importDefault(require("../rules/no-useless-two-nums-quantifier"));
const optimal_lookaround_quantifier_1 = __importDefault(require("../rules/optimal-lookaround-quantifier"));
const order_in_character_class_1 = __importDefault(require("../rules/order-in-character-class"));

@@ -48,2 +52,3 @@ const prefer_character_class_1 = __importDefault(require("../rules/prefer-character-class"));

exports.rules = [
confusing_quantifier_1.default,
letter_case_1.default,

@@ -55,2 +60,3 @@ match_any_1.default,

no_dupe_disjunctions_1.default,
no_empty_alternative_1.default,
no_empty_group_1.default,

@@ -60,2 +66,3 @@ no_empty_lookarounds_assertion_1.default,

no_invisible_character_1.default,
no_lazy_ends_1.default,
no_legacy_features_1.default,

@@ -73,2 +80,3 @@ no_octal_1.default,

no_useless_two_nums_quantifier_1.default,
optimal_lookaround_quantifier_1.default,
order_in_character_class_1.default,

@@ -75,0 +83,0 @@ prefer_character_class_1.default,

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

@@ -39,3 +39,6 @@ "main": "dist/index.js",

],
"author": "Yosuke Ota",
"author": "Yosuke Ota (https://github.com/ota-meshi)",
"contributors": [
"Michael Schmidt (https://github.com/RunDevelopment)"
],
"license": "MIT",

@@ -63,3 +66,3 @@ "bugs": {

"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-eslint-plugin": "^2.3.0",
"eslint-plugin-eslint-plugin": "^3.0.0",
"eslint-plugin-json-schema-validator": "^1.0.0",

@@ -90,4 +93,6 @@ "eslint-plugin-jsonc": "^1.0.0",

"jsdoctypeparser": "^9.0.0",
"refa": "^0.7.1",
"regexp-ast-analysis": "^0.1.1",
"regexpp": "^3.1.0"
}
}

@@ -70,3 +70,3 @@ # Introduction

- `plugin:regexp/recommended` ... This is the recommended configuration for this plugin.
- `plugin:regexp/recommended` ... This is the recommended configuration for this plugin.
See [lib/configs/recommended.ts](https://github.com/ota-meshi/eslint-plugin-regexp/blob/master/lib/configs/recommended.ts) for details.

@@ -80,3 +80,3 @@

The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) automatically fixes problems reported by rules which have a wrench :wrench: below.
The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) automatically fixes problems reported by rules which have a wrench :wrench: below.
The rules with the following star :star: are included in the `plugin:regexp/recommended` config.

@@ -88,2 +88,3 @@

|:--------|:------------|:---|
| [regexp/confusing-quantifier](https://ota-meshi.github.io/eslint-plugin-regexp/rules/confusing-quantifier.html) | disallow confusing quantifiers | |
| [regexp/letter-case](https://ota-meshi.github.io/eslint-plugin-regexp/rules/letter-case.html) | enforce into your favorite case | :wrench: |

@@ -95,2 +96,3 @@ | [regexp/match-any](https://ota-meshi.github.io/eslint-plugin-regexp/rules/match-any.html) | enforce match any character style | :star::wrench: |

| [regexp/no-dupe-disjunctions](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-dupe-disjunctions.html) | disallow duplicate disjunctions | |
| [regexp/no-empty-alternative](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-empty-alternative.html) | disallow alternatives without elements | |
| [regexp/no-empty-group](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-empty-group.html) | disallow empty group | :star: |

@@ -100,2 +102,3 @@ | [regexp/no-empty-lookarounds-assertion](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-empty-lookarounds-assertion.html) | disallow empty lookahead assertion or empty lookbehind assertion | :star: |

| [regexp/no-invisible-character](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-invisible-character.html) | disallow invisible raw character | :star::wrench: |
| [regexp/no-lazy-ends](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-lazy-ends.html) | disallow lazy quantifiers at the end of an expression | |
| [regexp/no-legacy-features](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-legacy-features.html) | disallow legacy RegExp features | |

@@ -112,3 +115,4 @@ | [regexp/no-octal](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-octal.html) | disallow octal escape sequence | :star: |

| [regexp/no-useless-range](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-useless-range.html) | disallow unnecessary range of characters by using a hyphen | :wrench: |
| [regexp/no-useless-two-nums-quantifier](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-useless-two-nums-quantifier.html) | disallow unnecessary `{n,m}` quantifier | :star: |
| [regexp/no-useless-two-nums-quantifier](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-useless-two-nums-quantifier.html) | disallow unnecessary `{n,m}` quantifier | :star::wrench: |
| [regexp/optimal-lookaround-quantifier](https://ota-meshi.github.io/eslint-plugin-regexp/rules/optimal-lookaround-quantifier.html) | disallow the alternatives of lookarounds that end with a non-constant quantifier | |
| [regexp/order-in-character-class](https://ota-meshi.github.io/eslint-plugin-regexp/rules/order-in-character-class.html) | enforces elements order in character class | :wrench: |

@@ -146,4 +150,6 @@ | [regexp/prefer-character-class](https://ota-meshi.github.io/eslint-plugin-regexp/rules/prefer-character-class.html) | enforce using character class | :wrench: |

- `npm test` runs tests and measures coverage.
- `npm run update` runs in order to update readme and recommended configuration.
- `npm test` runs tests and measures coverage.
- `npm run update` runs in order to update readme and recommended configuration.
- `npm run new [new rule name]` runs to create the files needed for the new rule.
- `npm run docs:watch` starts the website locally.

@@ -150,0 +156,0 @@ <!--DOCS_IGNORE_END-->