eslint-plugin-regexp
Advanced tools
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const regexp_ast_analysis_1 = require("regexp-ast-analysis"); | ||
const utils_1 = require("../utils"); | ||
const no_empty_capturing_group_1 = __importDefault(require("./no-empty-capturing-group")); | ||
exports.default = utils_1.createRule("no-assertion-capturing-group", { | ||
meta: { | ||
docs: { | ||
description: "disallow capturing group that captures assertions.", | ||
category: "Possible Errors", | ||
recommended: true, | ||
}, | ||
schema: [], | ||
messages: { | ||
unexpected: "Unexpected capture assertions.", | ||
}, | ||
type: "suggestion", | ||
}, | ||
meta: Object.assign(Object.assign({}, no_empty_capturing_group_1.default.meta), { docs: Object.assign(Object.assign({}, no_empty_capturing_group_1.default.meta.docs), { recommended: true, replacedBy: ["no-empty-capturing-group"] }) }), | ||
create(context) { | ||
function createVisitor({ node, getRegexpLocation, }) { | ||
return { | ||
onCapturingGroupEnter(cgNode) { | ||
if (regexp_ast_analysis_1.isZeroLength(cgNode)) { | ||
context.report({ | ||
node, | ||
loc: getRegexpLocation(cgNode), | ||
messageId: "unexpected", | ||
}); | ||
} | ||
}, | ||
}; | ||
} | ||
return utils_1.defineRegexpVisitor(context, { | ||
createVisitor, | ||
}); | ||
return no_empty_capturing_group_1.default.create(context); | ||
}, | ||
}); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const utils_1 = require("../utils"); | ||
const get_usage_of_pattern_1 = require("../utils/get-usage-of-pattern"); | ||
function* extractLazyEndQuantifiers(alternatives) { | ||
@@ -39,3 +40,11 @@ for (const { elements } of alternatives) { | ||
}, | ||
schema: [], | ||
schema: [ | ||
{ | ||
type: "object", | ||
properties: { | ||
ignorePartial: { type: "boolean" }, | ||
}, | ||
additionalProperties: false, | ||
}, | ||
], | ||
messages: { | ||
@@ -49,3 +58,11 @@ uselessElement: "The quantifier and the quantified element can be removed because the quantifier is lazy and has a minimum of 0.", | ||
create(context) { | ||
function createVisitor({ node, getRegexpLocation, }) { | ||
var _a, _b; | ||
const ignorePartial = (_b = (_a = context.options[0]) === null || _a === void 0 ? void 0 : _a.ignorePartial) !== null && _b !== void 0 ? _b : true; | ||
function createVisitor({ node, getRegexpLocation, getUsageOfPattern, }) { | ||
if (ignorePartial) { | ||
const usageOfPattern = getUsageOfPattern(); | ||
if (usageOfPattern !== get_usage_of_pattern_1.UsageOfPattern.whole) { | ||
return {}; | ||
} | ||
} | ||
return { | ||
@@ -52,0 +69,0 @@ onPatternEnter(pNode) { |
@@ -96,118 +96,2 @@ "use strict"; | ||
} | ||
function getProperty(node) { | ||
if (node.type === "MemberExpression") { | ||
if (node.computed) { | ||
if (node.property.type === "Literal") { | ||
if (typeof node.property.value === "string" || | ||
typeof node.property.value === "number") | ||
return String(node.property.value); | ||
} | ||
} | ||
else if (node.property.type === "Identifier") { | ||
return node.property.name; | ||
} | ||
return null; | ||
} | ||
if (node.type === "Property") { | ||
if (node.computed) { | ||
if (node.key.type === "Literal") { | ||
if (typeof node.key.value === "string" || | ||
typeof node.key.value === "number") | ||
return String(node.key.value); | ||
} | ||
} | ||
else if (node.key.type === "Identifier") { | ||
return node.key.name; | ||
} | ||
return null; | ||
} | ||
return null; | ||
} | ||
function extractUsedReferencesFromPattern(node, context) { | ||
const references = []; | ||
if (node.type === "ArrayPattern") { | ||
for (let index = 0; index < node.elements.length; index++) { | ||
const element = node.elements[index]; | ||
if (!element) { | ||
continue; | ||
} | ||
if (element.type === "RestElement") { | ||
return null; | ||
} | ||
references.push({ | ||
ref: String(index), | ||
node: element, | ||
getSubReferences: () => extractUsedReferencesFromPattern(element, context), | ||
}); | ||
} | ||
return references; | ||
} | ||
if (node.type === "ObjectPattern") { | ||
for (const prop of node.properties) { | ||
if (prop.type === "RestElement") { | ||
return null; | ||
} | ||
const property = getProperty(prop); | ||
if (property == null) | ||
return null; | ||
references.push({ | ||
ref: property, | ||
node: prop.value, | ||
getSubReferences: () => extractUsedReferencesFromPattern(prop.value, context), | ||
}); | ||
} | ||
return references; | ||
} | ||
if (node.type === "AssignmentPattern") { | ||
return extractUsedReferencesFromPattern(node.left, context); | ||
} | ||
if (node.type === "Identifier") { | ||
const variable = ast_utils_1.findVariable(context, node); | ||
if (!variable) { | ||
return null; | ||
} | ||
for (const reference of variable.references) { | ||
if (reference.isRead()) { | ||
const res = extractUsedReferencesFromExpression(reference.identifier, context); | ||
if (res == null) { | ||
return null; | ||
} | ||
references.push(...res); | ||
} | ||
} | ||
return references; | ||
} | ||
return null; | ||
} | ||
function extractUsedReferencesFromExpression(node, context) { | ||
const parent = node.parent; | ||
if (parent.type === "MemberExpression") { | ||
if (parent.object !== node) { | ||
return null; | ||
} | ||
const property = getProperty(parent); | ||
if (property == null) | ||
return null; | ||
return [ | ||
{ | ||
ref: property, | ||
node: parent, | ||
getSubReferences: () => extractUsedReferencesFromExpression(parent, context), | ||
}, | ||
]; | ||
} | ||
else if (parent.type === "AssignmentExpression") { | ||
if (parent.right !== node || parent.operator !== "=") { | ||
return null; | ||
} | ||
return extractUsedReferencesFromPattern(parent.left, context); | ||
} | ||
else if (parent.type === "VariableDeclarator") { | ||
if (parent.init !== node) { | ||
return null; | ||
} | ||
return extractUsedReferencesFromPattern(parent.id, context); | ||
} | ||
return null; | ||
} | ||
exports.default = utils_1.createRule("no-unused-capturing-group", { | ||
@@ -231,20 +115,2 @@ meta: { | ||
const capturingDataMap = new Map(); | ||
function getCapturingData(node) { | ||
const re = capturingDataMap.get(node); | ||
if (re) { | ||
return re; | ||
} | ||
if (node.type === "Identifier") { | ||
const variable = ast_utils_1.findVariable(context, node); | ||
if (variable && variable.defs.length === 1) { | ||
const def = variable.defs[0]; | ||
if (def.type === "Variable" && | ||
def.parent.kind === "const" && | ||
def.node.init) { | ||
return getCapturingData(def.node.init); | ||
} | ||
} | ||
} | ||
return null; | ||
} | ||
function reportUnused(capturingData) { | ||
@@ -273,3 +139,3 @@ const { node, getRegexpLocation } = capturingData.regexpContext; | ||
function verifyForMatch(node) { | ||
const capturingData = getCapturingData(node.arguments[0]); | ||
const capturingData = capturingDataMap.get(node.arguments[0]); | ||
if (capturingData == null || capturingData.isAllUsed()) { | ||
@@ -291,3 +157,3 @@ return; | ||
function verifyForSearch(node) { | ||
const capturingData = getCapturingData(node.arguments[0]); | ||
const capturingData = capturingDataMap.get(node.arguments[0]); | ||
if (capturingData == null || capturingData.isAllUsed()) { | ||
@@ -303,3 +169,3 @@ return; | ||
function verifyForTest(node) { | ||
const capturingData = getCapturingData(node.callee.object); | ||
const capturingData = capturingDataMap.get(node.callee.object); | ||
if (capturingData == null || capturingData.isAllUsed()) { | ||
@@ -311,3 +177,3 @@ return; | ||
function verifyForReplace(node) { | ||
const capturingData = getCapturingData(node.arguments[0]); | ||
const capturingData = capturingDataMap.get(node.arguments[0]); | ||
if (capturingData == null || capturingData.isAllUsed()) { | ||
@@ -367,3 +233,3 @@ return; | ||
function verifyForExec(node) { | ||
const capturingData = getCapturingData(node.callee.object); | ||
const capturingData = capturingDataMap.get(node.callee.object); | ||
if (capturingData == null || capturingData.isAllUsed()) { | ||
@@ -376,21 +242,21 @@ return; | ||
function verifyForExecResult(node, capturingData) { | ||
const refs = extractUsedReferencesFromExpression(node, context); | ||
if (refs == null) { | ||
capturingData.markAsCannotTrack(); | ||
return; | ||
} | ||
for (const ref of refs) { | ||
if (ref.ref === "groups") { | ||
const sub = ref.getSubReferences(); | ||
if (sub == null) { | ||
capturingData.usedAllNames(); | ||
for (const ref of ast_utils_1.extractPropertyReferences(node, context)) { | ||
if (hasNameRef(ref)) { | ||
if (ref.name === "groups") { | ||
for (const namedRef of ref.extractPropertyReferences()) { | ||
if (hasNameRef(namedRef)) { | ||
capturingData.usedName(namedRef.name); | ||
} | ||
else { | ||
capturingData.usedAllNames(); | ||
} | ||
} | ||
} | ||
else { | ||
for (const namedRef of sub) { | ||
capturingData.usedName(namedRef.ref); | ||
} | ||
capturingData.usedIndex(Number(ref.name)); | ||
} | ||
} | ||
else { | ||
capturingData.usedIndex(Number(ref.ref)); | ||
capturingData.markAsCannotTrack(); | ||
return; | ||
} | ||
@@ -400,3 +266,3 @@ } | ||
function verifyForMatchAll(node) { | ||
const capturingData = getCapturingData(node.arguments[0]); | ||
const capturingData = capturingDataMap.get(node.arguments[0]); | ||
if (capturingData == null || capturingData.isAllUsed()) { | ||
@@ -410,72 +276,37 @@ return; | ||
capturingData.markAsUsed(); | ||
const refs = extractUsedReferencesForIteration(node); | ||
if (refs == null) { | ||
capturingData.markAsCannotTrack(); | ||
return; | ||
} | ||
for (const ref of refs) { | ||
if (ref.ref === "groups") { | ||
const sub = ref.getSubReferences(); | ||
if (sub == null) { | ||
capturingData.usedAllNames(); | ||
} | ||
else { | ||
for (const namedRef of sub) { | ||
capturingData.usedName(namedRef.ref); | ||
} | ||
} | ||
for (const iterationRef of ast_utils_1.extractPropertyReferences(node, context)) { | ||
if (!iterationRef.extractPropertyReferences) { | ||
capturingData.markAsCannotTrack(); | ||
return; | ||
} | ||
else { | ||
capturingData.usedIndex(Number(ref.ref)); | ||
} | ||
} | ||
function extractUsedReferencesForIteration(expr) { | ||
const parent = expr.parent; | ||
if (parent.type === "AssignmentExpression") { | ||
if (parent.right !== expr || parent.operator !== "=") { | ||
return null; | ||
if (hasNameRef(iterationRef)) { | ||
if (Number.isNaN(Number(iterationRef.name))) { | ||
continue; | ||
} | ||
return extractUsedReferencesForIdIteration(parent.left); | ||
} | ||
else if (parent.type === "VariableDeclarator") { | ||
if (parent.init !== expr) { | ||
return null; | ||
} | ||
return extractUsedReferencesForIdIteration(parent.id); | ||
} | ||
else if (parent.type === "ForOfStatement") { | ||
if (parent.right !== expr) { | ||
return null; | ||
} | ||
let left = parent.left; | ||
if (left.type === "VariableDeclaration") { | ||
left = left.declarations[0].id; | ||
} | ||
return extractUsedReferencesFromPattern(left, context); | ||
} | ||
return null; | ||
} | ||
function extractUsedReferencesForIdIteration(ptn) { | ||
if (ptn.type === "Identifier") { | ||
const references = []; | ||
const variable = ast_utils_1.findVariable(context, ptn); | ||
if (!variable) { | ||
return null; | ||
} | ||
for (const reference of variable.references) { | ||
if (reference.isRead()) { | ||
const resForId = extractUsedReferencesForIteration(reference.identifier); | ||
if (resForId == null) { | ||
return null; | ||
for (const ref of iterationRef.extractPropertyReferences()) { | ||
if (hasNameRef(ref)) { | ||
if (ref.name === "groups") { | ||
for (const namedRef of ref.extractPropertyReferences()) { | ||
if (hasNameRef(namedRef)) { | ||
capturingData.usedName(namedRef.name); | ||
} | ||
else { | ||
capturingData.usedAllNames(); | ||
} | ||
} | ||
references.push(...resForId); | ||
} | ||
else { | ||
capturingData.usedIndex(Number(ref.name)); | ||
} | ||
} | ||
return references; | ||
else { | ||
capturingData.markAsCannotTrack(); | ||
return; | ||
} | ||
} | ||
return null; | ||
} | ||
} | ||
function verifyForSplit(node) { | ||
const capturingData = getCapturingData(node.arguments[0]); | ||
const capturingData = capturingDataMap.get(node.arguments[0]); | ||
if (capturingData == null || capturingData.isAllUsed()) { | ||
@@ -495,2 +326,10 @@ return; | ||
capturingDataMap.set(regexpNode, capturingData); | ||
for (const ref of ast_utils_1.extractExpressionReferences(regexpNode, context)) { | ||
if (ref.type === "argument" || ref.type === "member") { | ||
capturingDataMap.set(ref.node, capturingData); | ||
} | ||
else { | ||
capturingData.markAsCannotTrack(); | ||
} | ||
} | ||
return capturingData.visitor(); | ||
@@ -502,3 +341,3 @@ } | ||
"Program:exit"() { | ||
for (const capturingData of capturingDataMap.values()) { | ||
for (const capturingData of new Set(capturingDataMap.values())) { | ||
if (capturingData.isNeedReport()) { | ||
@@ -548,1 +387,4 @@ reportUnused(capturingData); | ||
}); | ||
function hasNameRef(ref) { | ||
return ref.type === "destructuring" || ref.type === "member"; | ||
} |
@@ -26,2 +26,3 @@ "use strict"; | ||
]); | ||
const POTENTIAL_ESCAPE_SEQUENCE = new Set("uxkpP"); | ||
exports.default = utils_1.createRule("no-useless-escape", { | ||
@@ -34,2 +35,3 @@ meta: { | ||
}, | ||
fixable: "code", | ||
schema: [], | ||
@@ -42,4 +44,4 @@ messages: { | ||
create(context) { | ||
function createVisitor({ node, getRegexpLocation, }) { | ||
function report(cNode, offset, character) { | ||
function createVisitor({ node, getRegexpLocation, fixReplaceNode, }) { | ||
function report(cNode, offset, character, fix) { | ||
context.report({ | ||
@@ -52,2 +54,3 @@ node, | ||
}, | ||
fix: fix ? fixReplaceNode(cNode, character) : null, | ||
}); | ||
@@ -87,3 +90,3 @@ } | ||
} | ||
report(cNode, 0, char); | ||
report(cNode, 0, char, !POTENTIAL_ESCAPE_SEQUENCE.has(char)); | ||
} | ||
@@ -90,0 +93,0 @@ } |
@@ -6,7 +6,7 @@ "use strict"; | ||
const type_tracker_1 = require("../utils/type-tracker"); | ||
class GlobalRegExpData { | ||
class RegExpReference { | ||
constructor(defineNode) { | ||
this.readNodes = new Map(); | ||
this.state = { | ||
used: false, | ||
usedIn: {}, | ||
track: true, | ||
@@ -16,42 +16,3 @@ }; | ||
} | ||
isNeedReport() { | ||
if (!this.readNodes.size) { | ||
return false; | ||
} | ||
if (this.state.used) { | ||
return false; | ||
} | ||
if (!this.state.track) { | ||
return false; | ||
} | ||
let countOfUsedInExecOrTest = 0; | ||
for (const readData of this.readNodes.values()) { | ||
if (!readData.marked) { | ||
return false; | ||
} | ||
if (readData.usedInSearchOrSplit) { | ||
continue; | ||
} | ||
if (readData.usedInExecOrTest) { | ||
if (!this.defineId) { | ||
return false; | ||
} | ||
if (this.defineId.codePathId === | ||
readData.usedInExecOrTest.id.codePathId && | ||
this.defineId.loopNode === | ||
readData.usedInExecOrTest.id.loopNode) { | ||
countOfUsedInExecOrTest++; | ||
if (countOfUsedInExecOrTest > 1) { | ||
return false; | ||
} | ||
continue; | ||
} | ||
else { | ||
return false; | ||
} | ||
} | ||
} | ||
return true; | ||
} | ||
pushReadNode(node) { | ||
addReadNode(node) { | ||
this.readNodes.set(node, {}); | ||
@@ -62,22 +23,48 @@ } | ||
} | ||
markAsUsedInSearchOrSplit(node) { | ||
markAsUsedInSearch(node) { | ||
const exprState = this.readNodes.get(node); | ||
if (exprState) { | ||
exprState.marked = true; | ||
exprState.usedInSearchOrSplit = true; | ||
exprState.usedInSearch = true; | ||
} | ||
this.state.usedIn.search = true; | ||
} | ||
markAsUsedInExecOrTest(node, codePathId, loopNode) { | ||
markAsUsedInSplit(node) { | ||
const exprState = this.readNodes.get(node); | ||
if (exprState) { | ||
exprState.marked = true; | ||
exprState.usedInExecOrTest = { id: { codePathId, loopNode } }; | ||
exprState.usedInSplit = true; | ||
} | ||
this.state.usedIn.split = true; | ||
} | ||
isUsed() { | ||
return this.state.used; | ||
markAsUsedInExec(node, codePathId, loopNode) { | ||
const exprState = this.readNodes.get(node); | ||
if (exprState) { | ||
exprState.marked = true; | ||
exprState.usedInExec = { id: { codePathId, loopNode } }; | ||
} | ||
this.state.usedIn.exec = true; | ||
} | ||
markAsUsed() { | ||
this.state.used = true; | ||
markAsUsedInTest(node, codePathId, loopNode) { | ||
const exprState = this.readNodes.get(node); | ||
if (exprState) { | ||
exprState.marked = true; | ||
exprState.usedInTest = { id: { codePathId, loopNode } }; | ||
} | ||
this.state.usedIn.test = true; | ||
} | ||
isUsed(kinds) { | ||
for (const kind of kinds) { | ||
if (this.state.usedIn[kind]) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
isCannotTrack() { | ||
return !this.state.track; | ||
} | ||
markAsUsed(kind) { | ||
this.state.usedIn[kind] = true; | ||
} | ||
markAsCannotTrack() { | ||
@@ -87,16 +74,2 @@ this.state.track = false; | ||
} | ||
function getVariableId(node) { | ||
const parent = ast_utils_1.getParent(node); | ||
if (!parent || | ||
parent.type !== "VariableDeclarator" || | ||
parent.init !== node || | ||
parent.id.type !== "Identifier") { | ||
return null; | ||
} | ||
const decl = ast_utils_1.getParent(parent); | ||
if (decl && decl.type === "VariableDeclaration" && decl.kind === "const") { | ||
return parent.id; | ||
} | ||
return null; | ||
} | ||
function getFlagLocation(context, node, flag) { | ||
@@ -230,8 +203,4 @@ const sourceCode = context.getSourceCode(); | ||
function createUselessGlobalFlagVisitor(context) { | ||
const typeTracer = type_tracker_1.createTypeTracker(context); | ||
let stack = null; | ||
const globalRegExpMap = new Map(); | ||
const globalRegExpList = []; | ||
function reportUselessGlobalFlag(globalRegExp) { | ||
const node = globalRegExp.defineNode; | ||
function reportUselessGlobalFlag(regExpReference) { | ||
const node = regExpReference.defineNode; | ||
context.report({ | ||
@@ -243,56 +212,136 @@ node, | ||
} | ||
function extractReadReferences(node) { | ||
const references = []; | ||
const variable = ast_utils_1.findVariable(context, node); | ||
if (!variable) { | ||
return references; | ||
} | ||
for (const reference of variable.references) { | ||
if (reference.isRead()) { | ||
const id = getVariableId(reference.identifier); | ||
if (id) { | ||
references.push(...extractReadReferences(id)); | ||
function isNeedReport(regExpReference) { | ||
let countOfUsedInExecOrTest = 0; | ||
for (const readData of regExpReference.readNodes.values()) { | ||
if (!readData.marked) { | ||
return false; | ||
} | ||
const usedInExecOrTest = readData.usedInExec || readData.usedInTest; | ||
if (usedInExecOrTest) { | ||
if (!regExpReference.defineId) { | ||
return false; | ||
} | ||
if (regExpReference.defineId.codePathId === | ||
usedInExecOrTest.id.codePathId && | ||
regExpReference.defineId.loopNode === | ||
usedInExecOrTest.id.loopNode) { | ||
countOfUsedInExecOrTest++; | ||
if (countOfUsedInExecOrTest > 1) { | ||
return false; | ||
} | ||
continue; | ||
} | ||
else { | ||
references.push(reference.identifier); | ||
return false; | ||
} | ||
} | ||
} | ||
return references; | ||
return true; | ||
} | ||
function verifyForSearchOrSplit(node) { | ||
const globalRegExp = globalRegExpMap.get(node.arguments[0]); | ||
if (globalRegExp == null || globalRegExp.isUsed()) { | ||
return createRegExpReferenceExtractVisitor(context, { | ||
flag: "global", | ||
exit(regExpReferenceList) { | ||
for (const regExpReference of regExpReferenceList) { | ||
if (isNeedReport(regExpReference)) { | ||
reportUselessGlobalFlag(regExpReference); | ||
} | ||
} | ||
}, | ||
isUsedShortCircuit(regExpReference) { | ||
return regExpReference.isUsed([ | ||
"match", | ||
"matchAll", | ||
"replace", | ||
"replaceAll", | ||
]); | ||
}, | ||
}); | ||
} | ||
function createUselessStickyFlagVisitor(context) { | ||
function reportUselessGlobalFlag(regExpReference) { | ||
const node = regExpReference.defineNode; | ||
context.report({ | ||
node, | ||
loc: getFlagLocation(context, node, "y"), | ||
messageId: "uselessStickyFlag", | ||
}); | ||
} | ||
function isNeedReport(regExpReference) { | ||
for (const readData of regExpReference.readNodes.values()) { | ||
if (!readData.marked) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
return createRegExpReferenceExtractVisitor(context, { | ||
flag: "sticky", | ||
exit(regExpReferenceList) { | ||
for (const regExpReference of regExpReferenceList) { | ||
if (isNeedReport(regExpReference)) { | ||
reportUselessGlobalFlag(regExpReference); | ||
} | ||
} | ||
}, | ||
isUsedShortCircuit(regExpReference) { | ||
return regExpReference.isUsed([ | ||
"search", | ||
"exec", | ||
"test", | ||
"match", | ||
"matchAll", | ||
"replace", | ||
"replaceAll", | ||
]); | ||
}, | ||
}); | ||
} | ||
function createRegExpReferenceExtractVisitor(context, { flag, exit, isUsedShortCircuit, }) { | ||
const typeTracer = type_tracker_1.createTypeTracker(context); | ||
let stack = null; | ||
const regExpReferenceMap = new Map(); | ||
const regExpReferenceList = []; | ||
function verifyForSearchOrSplit(node, kind) { | ||
const regExpReference = regExpReferenceMap.get(node.arguments[0]); | ||
if (regExpReference == null || isUsedShortCircuit(regExpReference)) { | ||
return; | ||
} | ||
if (!typeTracer.isString(node.callee.object)) { | ||
globalRegExp.markAsCannotTrack(); | ||
regExpReference.markAsCannotTrack(); | ||
return; | ||
} | ||
globalRegExp.markAsUsedInSearchOrSplit(node.arguments[0]); | ||
if (kind === "search") { | ||
regExpReference.markAsUsedInSearch(node.arguments[0]); | ||
} | ||
else { | ||
regExpReference.markAsUsedInSplit(node.arguments[0]); | ||
} | ||
} | ||
function verifyForExecOrTest(node) { | ||
const globalRegExp = globalRegExpMap.get(node.callee.object); | ||
if (globalRegExp == null || globalRegExp.isUsed()) { | ||
function verifyForExecOrTest(node, kind) { | ||
const regExpReference = regExpReferenceMap.get(node.callee.object); | ||
if (regExpReference == null || isUsedShortCircuit(regExpReference)) { | ||
return; | ||
} | ||
globalRegExp.markAsUsedInExecOrTest(node.callee.object, stack.codePathId, stack.loopStack[0]); | ||
if (kind === "exec") { | ||
regExpReference.markAsUsedInExec(node.callee.object, stack.codePathId, stack.loopStack[0]); | ||
} | ||
else { | ||
regExpReference.markAsUsedInTest(node.callee.object, stack.codePathId, stack.loopStack[0]); | ||
} | ||
} | ||
return utils_1.compositingVisitors(utils_1.defineRegexpVisitor(context, { | ||
createVisitor({ flags, regexpNode }) { | ||
if (flags.global) { | ||
const globalRegExp = new GlobalRegExpData(regexpNode); | ||
globalRegExpList.push(globalRegExp); | ||
globalRegExpMap.set(regexpNode, globalRegExp); | ||
const id = getVariableId(regexpNode); | ||
if (id) { | ||
const readReferences = extractReadReferences(id); | ||
for (const ref of readReferences) { | ||
globalRegExpMap.set(ref, globalRegExp); | ||
globalRegExp.pushReadNode(ref); | ||
if (flags[flag]) { | ||
const regExpReference = new RegExpReference(regexpNode); | ||
regExpReferenceList.push(regExpReference); | ||
regExpReferenceMap.set(regexpNode, regExpReference); | ||
for (const ref of ast_utils_1.extractExpressionReferences(regexpNode, context)) { | ||
if (ref.type === "argument" || ref.type === "member") { | ||
regExpReferenceMap.set(ref.node, regExpReference); | ||
regExpReference.addReadNode(ref.node); | ||
} | ||
else { | ||
regExpReference.markAsCannotTrack(); | ||
} | ||
} | ||
else { | ||
globalRegExp.pushReadNode(regexpNode); | ||
} | ||
} | ||
@@ -303,7 +352,14 @@ return {}; | ||
"Program:exit"() { | ||
for (const globalRegExp of globalRegExpList) { | ||
if (globalRegExp.isNeedReport()) { | ||
reportUselessGlobalFlag(globalRegExp); | ||
exit(regExpReferenceList.filter((regExpReference) => { | ||
if (!regExpReference.readNodes.size) { | ||
return false; | ||
} | ||
} | ||
if (regExpReference.isCannotTrack()) { | ||
return false; | ||
} | ||
if (isUsedShortCircuit(regExpReference)) { | ||
return false; | ||
} | ||
return true; | ||
})); | ||
}, | ||
@@ -334,7 +390,7 @@ onCodePathStart(codePath) { | ||
} | ||
const globalRegExp = globalRegExpMap.get(node); | ||
if (!globalRegExp || globalRegExp.defineNode !== node) { | ||
const regExpReference = regExpReferenceMap.get(node); | ||
if (!regExpReference || regExpReference.defineNode !== node) { | ||
return; | ||
} | ||
globalRegExp.setDefineId(stack.codePathId, stack.loopStack[0]); | ||
regExpReference.setDefineId(stack.codePathId, stack.loopStack[0]); | ||
}, | ||
@@ -359,7 +415,7 @@ "CallExpression:exit"(node) { | ||
node.callee.property.name === "split") { | ||
verifyForSearchOrSplit(node); | ||
verifyForSearchOrSplit(node, node.callee.property.name); | ||
} | ||
else if (node.callee.property.name === "test" || | ||
node.callee.property.name === "exec") { | ||
verifyForExecOrTest(node); | ||
verifyForExecOrTest(node, node.callee.property.name); | ||
} | ||
@@ -370,4 +426,4 @@ else if (node.callee.property.name === "match" || | ||
node.callee.property.name === "replaceAll") { | ||
const globalRegExp = globalRegExpMap.get(node.arguments[0]); | ||
globalRegExp === null || globalRegExp === void 0 ? void 0 : globalRegExp.markAsUsed(); | ||
const regExpReference = regExpReferenceMap.get(node.arguments[0]); | ||
regExpReference === null || regExpReference === void 0 ? void 0 : regExpReference.markAsUsed(node.callee.property.name); | ||
} | ||
@@ -393,3 +449,3 @@ }, | ||
items: { | ||
enum: ["i", "m", "s", "g"], | ||
enum: ["i", "m", "s", "g", "y"], | ||
}, | ||
@@ -407,2 +463,3 @@ uniqueItems: true, | ||
uselessGlobalFlag: "The 'g' flag is unnecessary because not using global testing.", | ||
uselessStickyFlag: "The 'y' flag is unnecessary because not using sticky search.", | ||
}, | ||
@@ -427,4 +484,7 @@ type: "suggestion", | ||
} | ||
if (!ignore.has("y")) { | ||
visitor = utils_1.compositingVisitors(visitor, createUselessStickyFlagVisitor(context)); | ||
} | ||
return visitor; | ||
}, | ||
}); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const utils_1 = require("../utils"); | ||
const get_usage_of_pattern_1 = require("../utils/get-usage-of-pattern"); | ||
function isTopLevel(group) { | ||
@@ -27,3 +28,10 @@ const parent = group.parent; | ||
properties: { | ||
allowTop: { type: "boolean" }, | ||
allowTop: { | ||
anyOf: [ | ||
{ | ||
type: "boolean", | ||
}, | ||
{ enum: ["always", "never", "partial"] }, | ||
], | ||
}, | ||
}, | ||
@@ -39,8 +47,27 @@ additionalProperties: false, | ||
create(context) { | ||
var _a, _b; | ||
const allowTop = (_b = (_a = context.options[0]) === null || _a === void 0 ? void 0 : _a.allowTop) !== null && _b !== void 0 ? _b : false; | ||
function createVisitor({ node, getRegexpLocation, fixReplaceNode, }) { | ||
var _a, _b, _c, _d; | ||
const allowTop = ((_a = context.options[0]) === null || _a === void 0 ? void 0 : _a.allowTop) === true | ||
? "always" | ||
: ((_b = context.options[0]) === null || _b === void 0 ? void 0 : _b.allowTop) === false | ||
? "never" | ||
: (_d = (_c = context.options[0]) === null || _c === void 0 ? void 0 : _c.allowTop) !== null && _d !== void 0 ? _d : "partial"; | ||
function createVisitor({ node, getRegexpLocation, fixReplaceNode, getUsageOfPattern, }) { | ||
let isIgnored; | ||
if (allowTop === "always") { | ||
isIgnored = isTopLevel; | ||
} | ||
else if (allowTop === "partial") { | ||
if (getUsageOfPattern() !== get_usage_of_pattern_1.UsageOfPattern.whole) { | ||
isIgnored = isTopLevel; | ||
} | ||
else { | ||
isIgnored = () => false; | ||
} | ||
} | ||
else { | ||
isIgnored = () => false; | ||
} | ||
return { | ||
onGroupEnter(gNode) { | ||
if (allowTop && isTopLevel(gNode)) { | ||
if (isIgnored(gNode)) { | ||
return; | ||
@@ -76,3 +103,10 @@ } | ||
messageId: "unexpected", | ||
fix: fixReplaceNode(gNode, gNode.raw.slice(3, -1)), | ||
fix: fixReplaceNode(gNode, () => { | ||
if (allowTop === "never" && | ||
isTopLevel(gNode) && | ||
getUsageOfPattern() !== get_usage_of_pattern_1.UsageOfPattern.whole) { | ||
return null; | ||
} | ||
return gNode.raw.slice(3, -1); | ||
}), | ||
}); | ||
@@ -79,0 +113,0 @@ }, |
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const utils_1 = require("../utils"); | ||
const DEFAULT_ORDER = [ | ||
"\\s", | ||
"\\w", | ||
"\\d", | ||
"\\p", | ||
"*", | ||
]; | ||
function getCharacterClassElementKind(node) { | ||
if (node.type === "CharacterSet") { | ||
return node.kind === "word" | ||
? "\\w" | ||
: node.kind === "digit" | ||
? "\\d" | ||
: node.kind === "space" | ||
? "\\s" | ||
: "\\p"; | ||
} | ||
return "*"; | ||
} | ||
const sort_character_class_elements_1 = __importDefault(require("./sort-character-class-elements")); | ||
exports.default = utils_1.createRule("order-in-character-class", { | ||
meta: { | ||
docs: { | ||
description: "enforces elements order in character class", | ||
category: "Stylistic Issues", | ||
recommended: false, | ||
}, | ||
fixable: "code", | ||
schema: [ | ||
{ | ||
type: "object", | ||
properties: { | ||
order: { | ||
type: "array", | ||
items: { enum: ["\\w", "\\d", "\\s", "\\p", "*"] }, | ||
}, | ||
}, | ||
additionalProperties: false, | ||
}, | ||
], | ||
messages: { | ||
sortElements: "Expected character class elements to be in ascending order. '{{next}}' should be before '{{prev}}'.", | ||
}, | ||
type: "layout", | ||
}, | ||
meta: Object.assign(Object.assign({}, sort_character_class_elements_1.default.meta), { docs: Object.assign(Object.assign({}, sort_character_class_elements_1.default.meta.docs), { recommended: false, replacedBy: ["sort-character-class-elements"] }) }), | ||
create(context) { | ||
var _a, _b; | ||
const orderOption = { "*": Infinity }; | ||
((_b = (_a = context.options[0]) === null || _a === void 0 ? void 0 : _a.order) !== null && _b !== void 0 ? _b : DEFAULT_ORDER).forEach((o, i) => { | ||
orderOption[o] = i + 1; | ||
}); | ||
function createVisitor({ node, fixerApplyEscape, getRegexpLocation, getRegexpRange, }) { | ||
return { | ||
onCharacterClassEnter(ccNode) { | ||
const prevList = []; | ||
for (const next of ccNode.elements) { | ||
if (prevList.length) { | ||
const prev = prevList[0]; | ||
if (!isValidOrder(prev, next)) { | ||
let moveTarget = prev; | ||
for (const p of prevList) { | ||
if (isValidOrder(p, next)) { | ||
break; | ||
} | ||
else { | ||
moveTarget = p; | ||
} | ||
} | ||
context.report({ | ||
node, | ||
loc: getRegexpLocation(next), | ||
messageId: "sortElements", | ||
data: { | ||
next: next.raw, | ||
prev: moveTarget.raw, | ||
}, | ||
*fix(fixer) { | ||
const nextRange = getRegexpRange(next); | ||
const targetRange = getRegexpRange(moveTarget); | ||
if (!targetRange || !nextRange) { | ||
return; | ||
} | ||
yield fixer.insertTextBeforeRange(targetRange, fixerApplyEscape(escapeRaw(next, moveTarget))); | ||
yield fixer.removeRange(nextRange); | ||
}, | ||
}); | ||
} | ||
} | ||
prevList.unshift(next); | ||
} | ||
}, | ||
}; | ||
} | ||
function isValidOrder(prev, next) { | ||
var _a, _b; | ||
const prevKind = getCharacterClassElementKind(prev); | ||
const nextKind = getCharacterClassElementKind(next); | ||
const prevOrder = (_a = orderOption[prevKind]) !== null && _a !== void 0 ? _a : orderOption["*"]; | ||
const nextOrder = (_b = orderOption[nextKind]) !== null && _b !== void 0 ? _b : orderOption["*"]; | ||
if (prevOrder < nextOrder) { | ||
return true; | ||
} | ||
else if (prevOrder > nextOrder) { | ||
return false; | ||
} | ||
if (prev.type === "CharacterSet" && prev.kind === "property") { | ||
if (next.type === "CharacterSet") { | ||
if (next.kind === "property") { | ||
return isValidOrderForUnicodePropertyCharacterSet(prev, next); | ||
} | ||
return false; | ||
} | ||
return true; | ||
} | ||
else if (next.type === "CharacterSet" && | ||
next.kind === "property") { | ||
if (prev.type === "CharacterSet") { | ||
return true; | ||
} | ||
return false; | ||
} | ||
if (prev.type === "CharacterSet" && next.type === "CharacterSet") { | ||
if (prev.kind === "word" && next.kind === "digit") { | ||
return true; | ||
} | ||
if (prev.kind === "digit" && next.kind === "word") { | ||
return false; | ||
} | ||
} | ||
const prevCP = getTargetCodePoint(prev); | ||
const nextCP = getTargetCodePoint(next); | ||
if (prevCP <= nextCP) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
function isValidOrderForUnicodePropertyCharacterSet(prev, next) { | ||
if (prev.key < next.key) { | ||
return true; | ||
} | ||
else if (prev.key > next.key) { | ||
return false; | ||
} | ||
if (prev.value) { | ||
if (next.value) { | ||
if (prev.value <= next.value) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
return false; | ||
} | ||
return true; | ||
} | ||
function getTargetCodePoint(node) { | ||
if (node.type === "CharacterSet") { | ||
if (node.kind === "digit" || node.kind === "word") { | ||
return utils_1.CP_DIGIT_ZERO; | ||
} | ||
if (node.kind === "space") { | ||
return utils_1.CP_SPACE; | ||
} | ||
return Infinity; | ||
} | ||
if (node.type === "CharacterClassRange") { | ||
return node.min.value; | ||
} | ||
return node.value; | ||
} | ||
return utils_1.defineRegexpVisitor(context, { | ||
createVisitor, | ||
}); | ||
return sort_character_class_elements_1.default.create(context); | ||
}, | ||
}); | ||
function escapeRaw(node, target) { | ||
let raw = node.raw; | ||
if (raw.startsWith("-")) { | ||
const parent = target.parent; | ||
const prev = parent.elements[parent.elements.indexOf(target) - 1]; | ||
if (prev && | ||
(prev.type === "Character" || prev.type === "CharacterSet")) { | ||
raw = `\\${raw}`; | ||
} | ||
} | ||
if (target.raw.startsWith("-")) { | ||
if (node.type === "Character" || node.type === "CharacterSet") { | ||
raw = `${raw}\\`; | ||
} | ||
} | ||
return raw; | ||
} |
@@ -75,4 +75,12 @@ "use strict"; | ||
} | ||
const group = groups.find((gp) => gp.min.value - 1 <= data.max.value && | ||
data.min.value <= gp.max.value + 1); | ||
const group = groups.find((gp) => { | ||
const adjacent = gp.min.value - 1 <= data.max.value && | ||
data.min.value <= gp.max.value + 1; | ||
if (!adjacent) { | ||
return false; | ||
} | ||
const min = Math.min(gp.min.value, data.min.value); | ||
const max = Math.max(gp.max.value, data.max.value); | ||
return char_ranges_1.inRange(allowedRanges, min, max); | ||
}); | ||
if (group) { | ||
@@ -79,0 +87,0 @@ if (data.min.value < group.min.value) { |
@@ -14,3 +14,3 @@ "use strict"; | ||
const usageSet = new Set(); | ||
for (const usage of iterateUsageOfPatternForExpression(node, context, new Map())) { | ||
for (const usage of iterateUsageOfPattern(node, context)) { | ||
if (usage === UsageOfPattern.unknown) { | ||
@@ -31,41 +31,14 @@ return UsageOfPattern.unknown; | ||
exports.getUsageOfPattern = getUsageOfPattern; | ||
function* iterateUsageOfPatternForExpression(node, context, alreadyFn) { | ||
const parent = ast_utils_1.getParent(node); | ||
if (!parent) { | ||
return; | ||
} | ||
if (parent.type === "MemberExpression") { | ||
if (parent.object === node) { | ||
yield* iterateUsageOfPatternForMemberExpression(parent, context); | ||
function* iterateUsageOfPattern(node, context) { | ||
for (const ref of ast_utils_1.extractExpressionReferences(node, context)) { | ||
if (ref.type === "member") { | ||
yield* iterateUsageOfPatternForMemberExpression(ref.memberExpression, context); | ||
} | ||
else { | ||
yield UsageOfPattern.unknown; | ||
else if (ref.type === "destructuring") { | ||
if (ref.pattern.type === "ObjectPattern") | ||
yield* iterateUsageOfPatternForObjectPattern(ref.pattern, context); | ||
} | ||
} | ||
else if (parent.type === "AssignmentExpression") { | ||
if (parent.right === node) { | ||
yield* iterateUsageOfPatternForESPattern(parent.left, context, alreadyFn); | ||
else if (ref.type === "unused") { | ||
} | ||
else { | ||
yield UsageOfPattern.unknown; | ||
} | ||
} | ||
else if (parent.type === "VariableDeclarator") { | ||
if (parent.init === node) { | ||
yield* iterateUsageOfPatternForESPattern(parent.id, context, alreadyFn); | ||
} | ||
else { | ||
yield UsageOfPattern.unknown; | ||
} | ||
} | ||
else if (parent.type === "CallExpression") { | ||
const argIndex = parent.arguments.indexOf(node); | ||
if (argIndex > -1) { | ||
if (parent.callee.type === "Identifier") { | ||
const fn = findFunction(context, parent.callee); | ||
if (fn) { | ||
yield* iterateUsageOfPatternForFunctionArgument(fn, argIndex, context, alreadyFn); | ||
return; | ||
} | ||
} | ||
else if (ref.type === "argument") { | ||
yield UsageOfPattern.whole; | ||
@@ -77,8 +50,2 @@ } | ||
} | ||
else if (parent.type === "ChainExpression") { | ||
yield* iterateUsageOfPatternForExpression(parent, context, alreadyFn); | ||
} | ||
else { | ||
yield UsageOfPattern.unknown; | ||
} | ||
} | ||
@@ -109,13 +76,2 @@ function* iterateUsageOfPatternForMemberExpression(node, context) { | ||
} | ||
function* iterateUsageOfPatternForESPattern(node, context, alreadyFn) { | ||
if (node.type === "Identifier") { | ||
yield* iterateUsageOfPatternForVariable(node, context, alreadyFn); | ||
} | ||
else if (node.type === "ObjectPattern") { | ||
yield* iterateUsageOfPatternForObjectPattern(node, context); | ||
} | ||
else { | ||
yield UsageOfPattern.unknown; | ||
} | ||
} | ||
function* iterateUsageOfPatternForObjectPattern(node, context) { | ||
@@ -139,58 +95,1 @@ for (const prop of node.properties) { | ||
} | ||
function* iterateUsageOfPatternForVariable(node, context, alreadyFn) { | ||
const variable = ast_utils_1.findVariable(context, node); | ||
if (!variable) { | ||
yield UsageOfPattern.unknown; | ||
return; | ||
} | ||
const readReferences = variable.references.filter((ref) => ref.isRead()); | ||
if (!readReferences.length) { | ||
yield UsageOfPattern.unknown; | ||
return; | ||
} | ||
for (const reference of readReferences) { | ||
yield* iterateUsageOfPatternForExpression(reference.identifier, context, alreadyFn); | ||
} | ||
} | ||
function* iterateUsageOfPatternForFunctionArgument(node, argIndex, context, alreadyFn) { | ||
let alreadyIndexes = alreadyFn.get(node); | ||
if (!alreadyIndexes) { | ||
alreadyIndexes = new Set(); | ||
alreadyFn.set(node, alreadyIndexes); | ||
} | ||
if (alreadyIndexes.has(argIndex)) { | ||
return; | ||
} | ||
alreadyIndexes.add(argIndex); | ||
const argNode = node.params[argIndex]; | ||
if (argNode && argNode.type === "Identifier") { | ||
yield* iterateUsageOfPatternForVariable(argNode, context, alreadyFn); | ||
} | ||
else { | ||
yield UsageOfPattern.unknown; | ||
} | ||
} | ||
function findFunction(context, id) { | ||
const calleeVariable = ast_utils_1.findVariable(context, id); | ||
if (!calleeVariable) { | ||
return null; | ||
} | ||
if (calleeVariable.defs.length === 1) { | ||
const def = calleeVariable.defs[0]; | ||
if (def.node.type === "FunctionDeclaration") { | ||
return def.node; | ||
} | ||
if (def.type === "Variable" && | ||
def.parent.kind === "const" && | ||
def.node.init) { | ||
if (def.node.init.type === "FunctionExpression" || | ||
def.node.init.type === "ArrowFunctionExpression") { | ||
return def.node.init; | ||
} | ||
if (def.node.init.type === "Identifier") { | ||
return findFunction(context, def.node.init); | ||
} | ||
} | ||
} | ||
return null; | ||
} |
@@ -17,2 +17,3 @@ "use strict"; | ||
const no_empty_alternative_1 = __importDefault(require("../rules/no-empty-alternative")); | ||
const no_empty_capturing_group_1 = __importDefault(require("../rules/no-empty-capturing-group")); | ||
const no_empty_group_1 = __importDefault(require("../rules/no-empty-group")); | ||
@@ -65,3 +66,6 @@ const no_empty_lookarounds_assertion_1 = __importDefault(require("../rules/no-empty-lookarounds-assertion")); | ||
const prefer_w_1 = __importDefault(require("../rules/prefer-w")); | ||
const sort_alternatives_1 = __importDefault(require("../rules/sort-alternatives")); | ||
const sort_character_class_elements_1 = __importDefault(require("../rules/sort-character-class-elements")); | ||
const sort_flags_1 = __importDefault(require("../rules/sort-flags")); | ||
const strict_1 = __importDefault(require("../rules/strict")); | ||
const unicode_escape_1 = __importDefault(require("../rules/unicode-escape")); | ||
@@ -79,2 +83,3 @@ exports.rules = [ | ||
no_empty_alternative_1.default, | ||
no_empty_capturing_group_1.default, | ||
no_empty_group_1.default, | ||
@@ -127,4 +132,7 @@ no_empty_lookarounds_assertion_1.default, | ||
prefer_w_1.default, | ||
sort_alternatives_1.default, | ||
sort_character_class_elements_1.default, | ||
sort_flags_1.default, | ||
strict_1.default, | ||
unicode_escape_1.default, | ||
]; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.CP_SMALL_Z = exports.CP_SMALL_A = exports.CP_DIGIT_NINE = exports.CP_DIGIT_ZERO = exports.CP_BOM = exports.CP_IDEOGRAPHIC_SPACE = exports.CP_BRAILLE_PATTERN_BLANK = exports.CP_MMSP = exports.CP_NNBSP = exports.CP_PARAGRAPH_SEPARATOR = exports.CP_LINE_SEPARATOR = exports.CP_RLM = exports.CP_LRM = exports.CP_ZWJ = exports.CP_ZWNJ = exports.CP_ZWSP = exports.CP_HAIR_SPACE = exports.CP_EN_QUAD = exports.CP_MONGOLIAN_VOWEL_SEPARATOR = exports.CP_OGHAM_SPACE_MARK = exports.CP_NBSP = exports.CP_NEL = exports.CP_TILDE = exports.CP_CLOSING_BRACE = exports.CP_PIPE = exports.CP_OPENING_BRACE = exports.CP_BACKTICK = exports.CP_CARET = exports.CP_CLOSING_BRACKET = exports.CP_BACK_SLASH = exports.CP_OPENING_BRACKET = exports.CP_AT = exports.CP_QUESTION = exports.CP_COLON = exports.CP_SLASH = exports.CP_DOT = exports.CP_MINUS = exports.CP_PLUS = exports.CP_STAR = exports.CP_CLOSING_PAREN = exports.CP_OPENING_PAREN = exports.CP_DOLLAR = exports.CP_BAN = exports.CP_SPACE = exports.CP_CR = exports.CP_FF = exports.CP_VT = exports.CP_LF = exports.CP_TAB = exports.CP_BACKSPACE = void 0; | ||
exports.isInvisible = exports.isWord = exports.isSpace = exports.isSymbol = exports.toUpperCodePoint = exports.toLowerCodePoint = exports.isLetter = exports.isUppercaseLetter = exports.isLowercaseLetter = exports.isDigit = exports.CP_RANGE_CAPITAL_LETTER = exports.CP_RANGE_SMALL_LETTER = exports.CP_LOW_LINE = exports.CP_CAPITAL_Z = exports.CP_CAPITAL_A = void 0; | ||
exports.CP_SMALL_A = exports.CP_DIGIT_NINE = exports.CP_DIGIT_ZERO = exports.CP_BOM = exports.CP_IDEOGRAPHIC_SPACE = exports.CP_BRAILLE_PATTERN_BLANK = exports.CP_MMSP = exports.CP_NNBSP = exports.CP_PARAGRAPH_SEPARATOR = exports.CP_LINE_SEPARATOR = exports.CP_RLM = exports.CP_LRM = exports.CP_ZWJ = exports.CP_ZWNJ = exports.CP_ZWSP = exports.CP_HAIR_SPACE = exports.CP_EN_QUAD = exports.CP_MONGOLIAN_VOWEL_SEPARATOR = exports.CP_OGHAM_SPACE_MARK = exports.CP_NBSP = exports.CP_NEL = exports.CP_TILDE = exports.CP_CLOSING_BRACE = exports.CP_PIPE = exports.CP_OPENING_BRACE = exports.CP_APOSTROPHE = exports.CP_BACKTICK = exports.CP_CARET = exports.CP_CLOSING_BRACKET = exports.CP_BACK_SLASH = exports.CP_OPENING_BRACKET = exports.CP_AT = exports.CP_QUESTION = exports.CP_COLON = exports.CP_SLASH = exports.CP_DOT = exports.CP_MINUS = exports.CP_PLUS = exports.CP_STAR = exports.CP_CLOSING_PAREN = exports.CP_OPENING_PAREN = exports.CP_DOLLAR = exports.CP_BAN = exports.CP_SPACE = exports.CP_CR = exports.CP_FF = exports.CP_VT = exports.CP_LF = exports.CP_TAB = exports.CP_BACKSPACE = void 0; | ||
exports.isInvisible = exports.isWord = exports.isSpace = exports.isSymbol = exports.toUpperCodePoint = exports.toLowerCodePoint = exports.isLetter = exports.isUppercaseLetter = exports.isLowercaseLetter = exports.isDigit = exports.CP_RANGE_CAPITAL_LETTER = exports.CP_RANGE_SMALL_LETTER = exports.CP_LOW_LINE = exports.CP_CAPITAL_Z = exports.CP_CAPITAL_A = exports.CP_SMALL_Z = void 0; | ||
const regexp_ast_analysis_1 = require("regexp-ast-analysis"); | ||
@@ -30,2 +30,3 @@ exports.CP_BACKSPACE = 8; | ||
exports.CP_BACKTICK = "`".codePointAt(0); | ||
exports.CP_APOSTROPHE = "'".codePointAt(0); | ||
exports.CP_OPENING_BRACE = "{".codePointAt(0); | ||
@@ -32,0 +33,0 @@ exports.CP_PIPE = "|".codePointAt(0); |
{ | ||
"name": "eslint-plugin-regexp", | ||
"version": "0.11.0", | ||
"version": "0.12.0", | ||
"description": "ESLint plugin for finding RegExp mistakes and RegExp style guide violations.", | ||
@@ -55,3 +55,3 @@ "main": "dist/index.js", | ||
"@types/eslint-scope": "^3.7.0", | ||
"@types/estree": "^0.0.47", | ||
"@types/estree": "^0.0.48", | ||
"@types/mocha": "^8.0.0", | ||
@@ -71,7 +71,7 @@ "@types/node": "^14.14.39", | ||
"eslint-plugin-prettier": "^3.4.0", | ||
"eslint-plugin-regexp": "^0.10.0", | ||
"eslint-plugin-regexp": "^0.11.0", | ||
"eslint-plugin-vue": "^7.5.0", | ||
"eslint-plugin-yml": "^0.9.0", | ||
"eslint4b": "^7.3.1", | ||
"mocha": "^8.0.0", | ||
"mocha": "^9.0.0", | ||
"nyc": "^15.1.0", | ||
@@ -82,3 +82,3 @@ "prettier": "^2.0.5", | ||
"stylelint-config-standard": "^22.0.0", | ||
"stylelint-plugin-stylus": "^0.10.0", | ||
"stylelint-plugin-stylus": "^0.11.0", | ||
"ts-node": "^10.0.0", | ||
@@ -95,5 +95,5 @@ "typescript": "^4.0.0", | ||
"refa": "^0.8.0", | ||
"regexp-ast-analysis": "^0.2.0", | ||
"regexp-ast-analysis": "^0.2.2", | ||
"regexpp": "^3.1.0" | ||
} | ||
} |
@@ -102,5 +102,6 @@ # Introduction | ||
|:--------|:------------|:---| | ||
| [regexp/no-assertion-capturing-group](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-assertion-capturing-group.html) | disallow capturing group that captures assertions. | :star: | | ||
| [regexp/no-assertion-capturing-group](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-assertion-capturing-group.html) | disallow capturing group that captures empty. | :star: | | ||
| [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-capturing-group](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-empty-capturing-group.html) | disallow capturing group that captures empty. | | | ||
| [regexp/no-empty-group](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-empty-group.html) | disallow empty group | :star: | | ||
@@ -115,2 +116,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-useless-dollar-replacements](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-useless-dollar-replacements.html) | disallow useless `$` replacements in replacement string | | | ||
| [regexp/strict](https://ota-meshi.github.io/eslint-plugin-regexp/rules/strict.html) | disallow not strictly valid regular expressions | :wrench: | | ||
@@ -151,2 +153,3 @@ ### Best Practices | ||
| [regexp/prefer-regexp-test](https://ota-meshi.github.io/eslint-plugin-regexp/rules/prefer-regexp-test.html) | enforce that `RegExp#test` is used instead of `String#match` and `RegExp#exec` | :wrench: | | ||
| [regexp/sort-alternatives](https://ota-meshi.github.io/eslint-plugin-regexp/rules/sort-alternatives.html) | sort alternatives if order doesn't matter | :wrench: | | ||
@@ -160,3 +163,3 @@ ### Stylistic Issues | ||
| [regexp/match-any](https://ota-meshi.github.io/eslint-plugin-regexp/rules/match-any.html) | enforce match any character style | :star::wrench: | | ||
| [regexp/no-useless-escape](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-useless-escape.html) | disallow unnecessary escape characters in RegExp | | | ||
| [regexp/no-useless-escape](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-useless-escape.html) | disallow unnecessary escape characters in RegExp | :wrench: | | ||
| [regexp/no-useless-non-capturing-group](https://ota-meshi.github.io/eslint-plugin-regexp/rules/no-useless-non-capturing-group.html) | disallow unnecessary Non-capturing group | :wrench: | | ||
@@ -173,2 +176,3 @@ | [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: | | ||
| [regexp/prefer-w](https://ota-meshi.github.io/eslint-plugin-regexp/rules/prefer-w.html) | enforce using `\w` | :star::wrench: | | ||
| [regexp/sort-character-class-elements](https://ota-meshi.github.io/eslint-plugin-regexp/rules/sort-character-class-elements.html) | enforces elements order in character class | :wrench: | | ||
| [regexp/sort-flags](https://ota-meshi.github.io/eslint-plugin-regexp/rules/sort-flags.html) | require regex flags to be sorted | :wrench: | | ||
@@ -175,0 +179,0 @@ | [regexp/unicode-escape](https://ota-meshi.github.io/eslint-plugin-regexp/rules/unicode-escape.html) | enforce consistent usage of unicode escape or unicode codepoint escape | :wrench: | |
469406
7.2%106
7.07%11679
6.35%207
1.97%