Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Fixer for missing unicode flag in no-misleading-character-class #15279

Closed
wants to merge 7 commits into from
Closed
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
57 changes: 41 additions & 16 deletions lib/rules/no-misleading-character-class.js
Expand Up @@ -108,14 +108,19 @@ module.exports = {
url: "https://eslint.org/docs/rules/no-misleading-character-class"
},

hasSuggestions: true,

schema: [],

fixable: "whitespace",

mathiasvr marked this conversation as resolved.
Show resolved Hide resolved
messages: {
surrogatePairWithoutUFlag: "Unexpected surrogate pair in character class. Use 'u' flag.",
combiningClass: "Unexpected combined character in character class.",
emojiModifier: "Unexpected modified Emoji in character class.",
regionalIndicatorSymbol: "Unexpected national flag in character class.",
zwj: "Unexpected joined character sequence in character class."
zwj: "Unexpected joined character sequence in character class.",
suggestUnicodeFlag: "Add unicode 'u' flag to regex."
}
},
create(context) {
Expand All @@ -126,17 +131,10 @@ module.exports = {
* @param {Node} node The node to report.
* @param {string} pattern The regular expression pattern to verify.
* @param {string} flags The flags of the regular expression.
* @param {Function} unicodeFixer Fixer for missing "u" flag.
* @returns {void}
*/
function verify(node, pattern, flags) {
const has = {
surrogatePairWithoutUFlag: false,
combiningClass: false,
variationSelector: false,
emojiModifier: false,
regionalIndicatorSymbol: false,
zwj: false
};
function verify(node, pattern, flags, unicodeFixer) {
let patternNode;

try {
Expand All @@ -152,26 +150,41 @@ module.exports = {
return;
}

const foundKinds = new Set();

visitRegExpAST(patternNode, {
onCharacterClassEnter(ccNode) {
for (const chars of iterateCharacterSequence(ccNode.elements)) {
for (const kind of kinds) {
has[kind] = has[kind] || hasCharacterSequence[kind](chars);
if (hasCharacterSequence[kind](chars)) {
foundKinds.add(kind);
}
}
}
}
});

for (const kind of kinds) {
if (has[kind]) {
context.report({ node, messageId: kind });
for (const kind of foundKinds) {
let suggest;

if (kind === "surrogatePairWithoutUFlag") {
suggest = [{
messageId: "suggestUnicodeFlag",
fix: unicodeFixer
}];
}

context.report({
node,
messageId: kind,
suggest
});
}
}

return {
"Literal[regex]"(node) {
verify(node, node.regex.pattern, node.regex.flags);
verify(node, node.regex.pattern, node.regex.flags, fixer => fixer.insertTextAfter(node, "u"));
},
"Program"() {
const scope = context.getScope();
Expand All @@ -190,7 +203,19 @@ module.exports = {
const flags = getStringIfConstant(flagsNode, scope);

if (typeof pattern === "string") {
verify(node, pattern, flags || "");
verify(node, pattern, flags || "", fixer => {
if (node.arguments.length === 1) {
return fixer.insertTextAfterRange(patternNode.range, ', "u"');
}
Comment on lines +205 to +207
Copy link
Member

Choose a reason for hiding this comment

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

First argument may be parenthesised:

new RegExp(("[👍]")); // regex is /[👍]/

In that case, the suggested fix wouldn't work as intended:

new RegExp(("[👍]", "u")); // regex is /u/


if (flagsNode.type === "Literal" || flagsNode.type === "TemplateLiteral") {
mathiasvr marked this conversation as resolved.
Show resolved Hide resolved
const range = [flagsNode.range[0], flagsNode.range[1] - 1];

return fixer.insertTextAfterRange(range, "u");
}

return null;
});
}
}
}
Expand Down