From 98b880ed8613d88eae8f48005926935d6915d5c5 Mon Sep 17 00:00:00 2001 From: ota-meshi Date: Sat, 9 Sep 2023 11:21:33 +0900 Subject: [PATCH 1/3] Add support for v flag to `regexp/no-misleading-unicode-character` rule --- lib/rules/no-misleading-unicode-character.ts | 37 +++++++++--- .../rules/no-misleading-unicode-character.ts | 56 ++++++++++++++++++- 2 files changed, 85 insertions(+), 8 deletions(-) diff --git a/lib/rules/no-misleading-unicode-character.ts b/lib/rules/no-misleading-unicode-character.ts index e85fbfc16..c64765427 100644 --- a/lib/rules/no-misleading-unicode-character.ts +++ b/lib/rules/no-misleading-unicode-character.ts @@ -35,7 +35,11 @@ function getProblem(grapheme: string, flags: ReadonlyFlags): Problem | null { (grapheme.length === 2 && !startsWithSurrogate(grapheme)) ) { return "Multi" - } else if (!flags.unicode && startsWithSurrogate(grapheme)) { + } else if ( + !flags.unicode && + !flags.unicodeSets && + startsWithSurrogate(grapheme) + ) { return "Surrogate" } return null @@ -84,6 +88,13 @@ function getGraphemeProblems( ): GraphemeProblem[] { let offset = cc.negate ? 2 : 1 + const ignoreElements = cc.elements.filter( + (element) => + element.type === "CharacterClass" || // Nesting CharacterClass + element.type === "ExpressionCharacterClass" || // Nesting ExpressionCharacterClass + element.type === "ClassStringDisjunction", + ) + const graphemes = splitter.splitGraphemes(cc.raw.slice(offset, -1)) const problems: GraphemeProblem[] = [] @@ -93,6 +104,14 @@ function getGraphemeProblems( const start = offset + cc.start const end = start + grapheme.length + if ( + ignoreElements.some( + (ignore) => ignore.start <= start && end <= ignore.end, + ) + ) { + continue + } + problems.push({ grapheme, problem, @@ -113,6 +132,7 @@ function getGraphemeProblems( function getGraphemeProblemsFix( problems: readonly GraphemeProblem[], cc: CharacterClass, + flags: ReadonlyFlags, ): string | null { if (cc.negate) { // we can't fix a negated character class @@ -131,10 +151,7 @@ function getGraphemeProblemsFix( } // The prefix of graphemes - const prefix = problems - .map((p) => p.grapheme) - .sort((a, b) => b.length - a.length) - .join("|") + const prefixGraphemes = problems.map((p) => p.grapheme) // The rest of the character class let ccRaw = cc.raw @@ -142,10 +159,17 @@ function getGraphemeProblemsFix( const { start, end } = problems[i] ccRaw = ccRaw.slice(0, start - cc.start) + ccRaw.slice(end - cc.start) } + + if (flags.unicodeSets) { + const prefix = prefixGraphemes.join("|") + return `[\\q{${prefix}}${ccRaw.slice(1, -1)}]` + } + if (ccRaw.startsWith("[^")) { ccRaw = `[\\${ccRaw.slice(1)}` } + const prefix = prefixGraphemes.sort((a, b) => b.length - a.length).join("|") let fix = prefix let singleAlternative = problems.length === 1 if (ccRaw !== "[]") { @@ -242,8 +266,7 @@ export default createRule("no-misleading-unicode-character", { start: problems[0].start, end: problems[problems.length - 1].end, } - - const fix = getGraphemeProblemsFix(problems, ccNode) + const fix = getGraphemeProblemsFix(problems, ccNode, flags) const graphemes = problems .map((p) => mention(p.grapheme)) diff --git a/tests/lib/rules/no-misleading-unicode-character.ts b/tests/lib/rules/no-misleading-unicode-character.ts index 6c871afd1..69c8bb25f 100644 --- a/tests/lib/rules/no-misleading-unicode-character.ts +++ b/tests/lib/rules/no-misleading-unicode-character.ts @@ -3,7 +3,7 @@ import rule from "../../../lib/rules/no-misleading-unicode-character" const tester = new RuleTester({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: "latest", sourceType: "module", }, }) @@ -46,6 +46,13 @@ tester.run("no-misleading-unicode-character", rule as any, { // Ignore escaped symbols because it's obvious they aren't together `/[\\uD83D\\uDC4D]/`, + + // ES2024 + "var r = /[πŸ‘]/v", + String.raw`var r = /^[\q{πŸ‘ΆπŸ»}]$/v`, + String.raw`var r = /[πŸ‡―\q{abc}πŸ‡΅]/v`, + "var r = /[πŸ‡―[A]πŸ‡΅]/v", + "var r = /[πŸ‡―[A--B]πŸ‡΅]/v", ], invalid: [ { @@ -262,5 +269,52 @@ tester.run("no-misleading-unicode-character", rule as any, { options: [{ fixable: true }], errors: [{ messageId: "characterClass" }], }, + + // ES2024 + { + code: String.raw`/[[πŸ‘ΆπŸ»]]/v`, + output: String.raw`/[[\q{πŸ‘ΆπŸ»}]]/v`, + options: [{ fixable: true }], + errors: [{ messageId: "characterClass" }], + }, + { + code: String.raw`/[πŸ‘ΆπŸ»[πŸ‘¨β€πŸ‘©β€πŸ‘¦]]/v`, + output: String.raw`/[\q{πŸ‘ΆπŸ»}[πŸ‘¨β€πŸ‘©β€πŸ‘¦]]/v`, + options: [{ fixable: true }], + errors: [ + { messageId: "characterClass", column: 3 }, + { messageId: "characterClass", column: 8 }, + ], + }, + { + code: String.raw`/[πŸ‘ΆπŸ»πŸ‘¨β€πŸ‘©β€πŸ‘¦]/v`, + output: String.raw`/[\q{πŸ‘ΆπŸ»|πŸ‘¨β€πŸ‘©β€πŸ‘¦}]/v`, + options: [{ fixable: true }], + errors: [{ messageId: "characterClass" }], + }, + { + code: String.raw`/[πŸ‘ΆπŸ»&πŸ‘¨β€πŸ‘©β€πŸ‘¦]/v`, + output: String.raw`/[\q{πŸ‘ΆπŸ»|πŸ‘¨β€πŸ‘©β€πŸ‘¦}&]/v`, + options: [{ fixable: true }], + errors: [{ messageId: "characterClass" }], + }, + { + code: String.raw`/[^πŸ‘¨β€πŸ‘©β€πŸ‘¦]/v`, + output: null, + options: [{ fixable: true }], + errors: [{ messageId: "characterClass" }], + }, + { + code: String.raw`new RegExp("[πŸ‘¨β€πŸ‘©β€πŸ‘¦]", "v")`, + output: String.raw`new RegExp("[\\q{πŸ‘¨β€πŸ‘©β€πŸ‘¦}]", "v")`, + options: [{ fixable: true }], + errors: [{ messageId: "characterClass" }], + }, + { + code: `/πŸ‘¨β€πŸ‘©β€πŸ‘¦+/v`, + output: `/(?:πŸ‘¨β€πŸ‘©β€πŸ‘¦)+/v`, + options: [{ fixable: true }], + errors: [{ messageId: "quantifierMulti" }], + }, ], }) From 032e28ceffb63c14e623a7bb08c3d40305aa59aa Mon Sep 17 00:00:00 2001 From: Yosuke Ota Date: Sat, 9 Sep 2023 11:22:22 +0900 Subject: [PATCH 2/3] Create smart-chefs-poke.md --- .changeset/smart-chefs-poke.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/smart-chefs-poke.md diff --git a/.changeset/smart-chefs-poke.md b/.changeset/smart-chefs-poke.md new file mode 100644 index 000000000..aeabb6dd3 --- /dev/null +++ b/.changeset/smart-chefs-poke.md @@ -0,0 +1,5 @@ +--- +"eslint-plugin-regexp": minor +--- + +Add support for v flag to `regexp/no-misleading-unicode-character` rule From 9349413610887742b65d65b0161e683d92a46bc0 Mon Sep 17 00:00:00 2001 From: ota-meshi Date: Sun, 10 Sep 2023 10:32:40 +0900 Subject: [PATCH 3/3] test: add test case --- tests/lib/rules/no-misleading-unicode-character.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/lib/rules/no-misleading-unicode-character.ts b/tests/lib/rules/no-misleading-unicode-character.ts index 69c8bb25f..0fe3ada14 100644 --- a/tests/lib/rules/no-misleading-unicode-character.ts +++ b/tests/lib/rules/no-misleading-unicode-character.ts @@ -298,6 +298,12 @@ tester.run("no-misleading-unicode-character", rule as any, { options: [{ fixable: true }], errors: [{ messageId: "characterClass" }], }, + { + code: String.raw`/[^πŸ‘ΆπŸ»&πŸ‘¨β€πŸ‘©β€πŸ‘¦]/v`, + output: null, + options: [{ fixable: true }], + errors: [{ messageId: "characterClass" }], + }, { code: String.raw`/[^πŸ‘¨β€πŸ‘©β€πŸ‘¦]/v`, output: null,