diff --git a/.changeset/thin-insects-cover.md b/.changeset/thin-insects-cover.md new file mode 100644 index 000000000..fcd6b3d6f --- /dev/null +++ b/.changeset/thin-insects-cover.md @@ -0,0 +1,5 @@ +--- +"eslint-plugin-regexp": patch +--- + +Add more `v` flag tests diff --git a/tests/lib/rules/no-useless-assertions.ts b/tests/lib/rules/no-useless-assertions.ts index 63f3e9faa..5dedfa46e 100644 --- a/tests/lib/rules/no-useless-assertions.ts +++ b/tests/lib/rules/no-useless-assertions.ts @@ -3,7 +3,7 @@ import rule from "../../../lib/rules/no-useless-assertions" const tester = new RuleTester({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: "latest", sourceType: "module", }, }) @@ -67,6 +67,15 @@ tester.run("no-useless-assertions", rule as any, { }, ], }, + { + code: String.raw`/a\b[\q{foo}]/v`, + errors: [ + { + message: + "'\\b' will always reject because it is preceded by a word character and followed by a word character.", + }, + ], + }, { code: String.raw`/,\b,/`, errors: [ diff --git a/tests/lib/rules/no-useless-backreference.ts b/tests/lib/rules/no-useless-backreference.ts index c6363a323..bf79eb53f 100644 --- a/tests/lib/rules/no-useless-backreference.ts +++ b/tests/lib/rules/no-useless-backreference.ts @@ -3,7 +3,7 @@ import rule from "../../../lib/rules/no-useless-backreference" const tester = new RuleTester({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: "latest", sourceType: "module", }, }) @@ -31,6 +31,10 @@ tester.run("no-useless-backreference", rule as any, { code: "/(\\b)a\\1/", errors: [{ messageId: "empty" }], }, + { + code: "/([\\q{}])a\\1/v", + errors: [{ messageId: "empty" }], + }, { code: "/(\\b|a{0})a\\1/", errors: [{ messageId: "empty" }], diff --git a/tests/lib/rules/no-useless-flag.ts b/tests/lib/rules/no-useless-flag.ts index 004f68e5a..cb1bbe970 100644 --- a/tests/lib/rules/no-useless-flag.ts +++ b/tests/lib/rules/no-useless-flag.ts @@ -6,7 +6,7 @@ import { rules } from "../../../lib/utils/rules" const tester = new RuleTester({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: "latest", sourceType: "module", }, }) @@ -218,6 +218,8 @@ tester.run("no-useless-flag", rule as any, { const orig = /\w/i; // eslint-disable-line const clone = new RegExp(orig); `, + String.raw`/a/u`, + String.raw`/a/v`, ], invalid: [ // i diff --git a/tests/lib/rules/no-useless-lazy.ts b/tests/lib/rules/no-useless-lazy.ts index 3fbf3ec83..da0c5e2b5 100644 --- a/tests/lib/rules/no-useless-lazy.ts +++ b/tests/lib/rules/no-useless-lazy.ts @@ -3,7 +3,7 @@ import rule from "../../../lib/rules/no-useless-lazy" const tester = new RuleTester({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: "latest", sourceType: "module", }, }) @@ -34,6 +34,11 @@ tester.run("no-useless-lazy", rule as any, { }, ], }, + { + code: `/a{1}?/v`, + output: `/a{1}/v`, + errors: [{ messageId: "constant" }], + }, { code: `/a{4}?/`, output: `/a{4}/`, @@ -72,6 +77,11 @@ tester.run("no-useless-lazy", rule as any, { output: `/a+b+/`, errors: [{ messageId: "possessive" }], }, + { + code: String.raw`/[\q{aa|ab}]+?b+/v`, + output: String.raw`/[\q{aa|ab}]+b+/v`, + errors: [{ messageId: "possessive" }], + }, { code: `/a*?b+/`, output: `/a*b+/`, diff --git a/tests/lib/rules/no-useless-non-capturing-group.ts b/tests/lib/rules/no-useless-non-capturing-group.ts index 6ea70ed2c..2734196a7 100644 --- a/tests/lib/rules/no-useless-non-capturing-group.ts +++ b/tests/lib/rules/no-useless-non-capturing-group.ts @@ -3,7 +3,7 @@ import rule from "../../../lib/rules/no-useless-non-capturing-group" const tester = new RuleTester({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: "latest", sourceType: "module", }, }) @@ -91,6 +91,19 @@ tester.run("no-useless-non-capturing-group", rule as any, { }, ], }, + { + code: `/(?:abcd)/v.test(str)`, + output: `/abcd/v.test(str)`, + errors: [ + { + message: "Unexpected quantifier Non-capturing group.", + line: 1, + column: 2, + endLine: 1, + endColumn: 5, + }, + ], + }, { code: `/(?:[abcd])/.test(str)`, output: `/[abcd]/.test(str)`, diff --git a/tests/lib/rules/no-useless-quantifier.ts b/tests/lib/rules/no-useless-quantifier.ts index ffcea1df1..924ab4d89 100644 --- a/tests/lib/rules/no-useless-quantifier.ts +++ b/tests/lib/rules/no-useless-quantifier.ts @@ -3,7 +3,7 @@ import rule from "../../../lib/rules/no-useless-quantifier" const tester = new RuleTester({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: "latest", sourceType: "module", }, }) @@ -45,6 +45,21 @@ tester.run("no-useless-quantifier", rule as any, { }, ], }, + { + code: String.raw`/(?:[\q{}])+/v`, + output: null, + errors: [ + { + messageId: "empty", + suggestions: [ + { + messageId: "remove", + output: String.raw`/(?:[\q{}])/v`, + }, + ], + }, + ], + }, { code: String.raw`/(?:|(?:)){5,9}/`, output: null, diff --git a/tests/lib/rules/no-useless-range.ts b/tests/lib/rules/no-useless-range.ts index b687abdb6..a3e9962e1 100644 --- a/tests/lib/rules/no-useless-range.ts +++ b/tests/lib/rules/no-useless-range.ts @@ -3,7 +3,7 @@ import rule from "../../../lib/rules/no-useless-range" const tester = new RuleTester({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: "latest", sourceType: "module", }, }) @@ -23,6 +23,13 @@ tester.run("no-useless-range", rule as any, { }, ], }, + { + code: `/[a-a]/v`, + output: `/[a]/v`, + errors: [ + "Unexpected unnecessary character ranges. The hyphen is unnecessary.", + ], + }, { code: `/[a-b]/`, output: `/[ab]/`, @@ -35,6 +42,13 @@ tester.run("no-useless-range", rule as any, { }, ], }, + { + code: `/[a-b]/v`, + output: `/[ab]/v`, + errors: [ + "Unexpected unnecessary character ranges. The hyphen is unnecessary.", + ], + }, { code: `/[a-a-c-c]/`, output: `/[a\\-c]/`, diff --git a/tests/lib/rules/no-useless-two-nums-quantifier.ts b/tests/lib/rules/no-useless-two-nums-quantifier.ts index ad6c683e8..936700cfa 100644 --- a/tests/lib/rules/no-useless-two-nums-quantifier.ts +++ b/tests/lib/rules/no-useless-two-nums-quantifier.ts @@ -3,7 +3,7 @@ import rule from "../../../lib/rules/no-useless-two-nums-quantifier" const tester = new RuleTester({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: "latest", sourceType: "module", }, }) @@ -42,5 +42,10 @@ tester.run("no-useless-two-nums-quantifier", rule as any, { output: "/a{100}?/", errors: ["Unexpected quantifier '{100,100}'."], }, + { + code: "/a{100,100}?/v", + output: "/a{100}?/v", + errors: 1, + }, ], }) diff --git a/tests/lib/rules/no-zero-quantifier.ts b/tests/lib/rules/no-zero-quantifier.ts index 724730994..f3bdbb34a 100644 --- a/tests/lib/rules/no-zero-quantifier.ts +++ b/tests/lib/rules/no-zero-quantifier.ts @@ -3,7 +3,7 @@ import rule from "../../../lib/rules/no-zero-quantifier" const tester = new RuleTester({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: "latest", sourceType: "module", }, }) @@ -22,6 +22,15 @@ tester.run("no-zero-quantifier", rule as any, { }, ], }, + { + code: `/a{0}/v`, + errors: [ + { + messageId: "unexpected", + suggestions: [{ output: `/(?:)/v` }], + }, + ], + }, { code: `/a{0,0}/`, errors: [ diff --git a/tests/lib/rules/optimal-lookaround-quantifier.ts b/tests/lib/rules/optimal-lookaround-quantifier.ts index d3fd17301..1b65b4fa6 100644 --- a/tests/lib/rules/optimal-lookaround-quantifier.ts +++ b/tests/lib/rules/optimal-lookaround-quantifier.ts @@ -3,7 +3,7 @@ import rule from "../../../lib/rules/optimal-lookaround-quantifier" const tester = new RuleTester({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: "latest", sourceType: "module", }, }) @@ -22,6 +22,17 @@ tester.run("optimal-lookaround-quantifier", rule as any, { }, ], }, + { + code: `/(?=ba*)/v`, + errors: [ + { + message: + "The quantified expression 'a*' at the end of the expression tree should only be matched a constant number of times. The expression can be removed without affecting the lookaround.", + column: 6, + suggestions: [{ output: `/(?=b)/v` }], + }, + ], + }, { code: `/(?=(?:a|b|abc*))/`, errors: [ diff --git a/tests/lib/rules/prefer-escape-replacement-dollar-char.ts b/tests/lib/rules/prefer-escape-replacement-dollar-char.ts index 59795a666..c3bb7528a 100644 --- a/tests/lib/rules/prefer-escape-replacement-dollar-char.ts +++ b/tests/lib/rules/prefer-escape-replacement-dollar-char.ts @@ -3,7 +3,7 @@ import rule from "../../../lib/rules/prefer-escape-replacement-dollar-char" const tester = new RuleTester({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: "latest", sourceType: "module", }, }) @@ -34,6 +34,10 @@ tester.run("prefer-escape-replacement-dollar-char", rule as any, { }, ], }, + { + code: `'€1,234'.replace(/€/v, '$'); // "$1,234"`, + errors: 1, + }, { code: `'€1,234'.replaceAll(/€/, '$'); // "$1,234"`, errors: [ diff --git a/tests/lib/rules/prefer-lookaround.ts b/tests/lib/rules/prefer-lookaround.ts index f2a3a53b9..121d0dce4 100644 --- a/tests/lib/rules/prefer-lookaround.ts +++ b/tests/lib/rules/prefer-lookaround.ts @@ -3,7 +3,7 @@ import rule from "../../../lib/rules/prefer-lookaround" const tester = new RuleTester({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: "latest", sourceType: "module", }, }) @@ -544,6 +544,13 @@ tester.run("prefer-lookaround", rule as any, { }, ], }, + { + code: String.raw`var str = 'Java'.replace(/(?:^|\b|[\q{}])(J)ava/gv, '$1Query')`, + output: String.raw`var str = 'Java'.replace(/(?<=(?:^|\b|[\q{}])J)ava/gv, 'Query')`, + errors: [ + "This capturing group can be replaced with a lookbehind assertion ('(?<=(?:^|\\b|[\\q{}])J)').", + ], + }, { code: `var str = 'JavaScriptCode'.replace(/(?<=Java)(Script)Code/g, '$1Linter')`, output: `var str = 'JavaScriptCode'.replace(/(?<=JavaScript)Code/g, 'Linter')`, diff --git a/tests/lib/rules/prefer-named-backreference.ts b/tests/lib/rules/prefer-named-backreference.ts index 7baf9783a..cce7f8f7c 100644 --- a/tests/lib/rules/prefer-named-backreference.ts +++ b/tests/lib/rules/prefer-named-backreference.ts @@ -3,7 +3,7 @@ import rule from "../../../lib/rules/prefer-named-backreference" const tester = new RuleTester({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: "latest", sourceType: "module", }, }) @@ -16,5 +16,10 @@ tester.run("prefer-named-backreference", rule as any, { output: `/(?a)\\k/`, errors: [{ messageId: "unexpected" }], }, + { + code: `/(?a)\\1/v`, + output: `/(?a)\\k/v`, + errors: [{ messageId: "unexpected" }], + }, ], }) diff --git a/tests/lib/rules/prefer-named-capture-group.ts b/tests/lib/rules/prefer-named-capture-group.ts index f99318eec..d299c2e25 100644 --- a/tests/lib/rules/prefer-named-capture-group.ts +++ b/tests/lib/rules/prefer-named-capture-group.ts @@ -3,7 +3,7 @@ import rule from "../../../lib/rules/prefer-named-capture-group" const tester = new RuleTester({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: "latest", sourceType: "module", }, }) @@ -22,5 +22,11 @@ tester.run("prefer-named-capture-group", rule as any, { "Capture group '(foo)' should be converted to a named or non-capturing group.", ], }, + { + code: String.raw`/(foo)/v`, + errors: [ + "Capture group '(foo)' should be converted to a named or non-capturing group.", + ], + }, ], }) diff --git a/tests/lib/rules/prefer-named-replacement.ts b/tests/lib/rules/prefer-named-replacement.ts index 7cc5f2dba..3d0949e46 100644 --- a/tests/lib/rules/prefer-named-replacement.ts +++ b/tests/lib/rules/prefer-named-replacement.ts @@ -3,7 +3,7 @@ import rule from "../../../lib/rules/prefer-named-replacement" const tester = new RuleTester({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: "latest", sourceType: "module", }, }) @@ -34,6 +34,11 @@ tester.run("prefer-named-replacement", rule as any, { }, ], }, + { + code: `"str".replace(/a(?b)c/v, "_$1_")`, + output: `"str".replace(/a(?b)c/v, "_$_")`, + errors: ["Unexpected indexed reference in replacement string."], + }, { code: `"str".replaceAll(/a(?b)c/, "_$1_")`, output: `"str".replaceAll(/a(?b)c/, "_$_")`, diff --git a/tests/lib/rules/prefer-plus-quantifier.ts b/tests/lib/rules/prefer-plus-quantifier.ts index 3381b3f1a..b02de2e3d 100644 --- a/tests/lib/rules/prefer-plus-quantifier.ts +++ b/tests/lib/rules/prefer-plus-quantifier.ts @@ -3,7 +3,7 @@ import rule from "../../../lib/rules/prefer-plus-quantifier" const tester = new RuleTester({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: "latest", sourceType: "module", }, }) @@ -44,6 +44,11 @@ tester.run("prefer-plus-quantifier", rule as any, { }, ], }, + { + code: "/(a){1,}/v", + output: "/(a)+/v", + errors: ["Unexpected quantifier '{1,}'. Use '+' instead."], + }, { code: "/(a){1,}?/", output: "/(a)+?/", diff --git a/tests/lib/rules/prefer-quantifier.ts b/tests/lib/rules/prefer-quantifier.ts index 2de1f8123..9ae51f89e 100644 --- a/tests/lib/rules/prefer-quantifier.ts +++ b/tests/lib/rules/prefer-quantifier.ts @@ -3,7 +3,7 @@ import rule from "../../../lib/rules/prefer-quantifier" const tester = new RuleTester({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: "latest", sourceType: "module", }, }) @@ -47,6 +47,27 @@ tester.run("prefer-quantifier", rule as any, { }, ], }, + { + code: `/ /v`, + output: `/ {2}/v`, + errors: [ + "Unexpected consecutive same characters. Use '{2}' instead.", + ], + }, + { + code: String.raw`/\p{ASCII}\p{ASCII}/u`, + output: String.raw`/\p{ASCII}{2}/u`, + errors: [ + "Unexpected consecutive same character class escapes. Use '{2}' instead.", + ], + }, + { + code: String.raw`/\p{Basic_Emoji}\p{Basic_Emoji}/v`, + output: String.raw`/\p{Basic_Emoji}{2}/v`, + errors: [ + "Unexpected consecutive same character class escapes. Use '{2}' instead.", + ], + }, { code: `/(\\d\\d\\d*)/`, output: `/(\\d{2}\\d*)/`, diff --git a/tests/lib/rules/prefer-question-quantifier.ts b/tests/lib/rules/prefer-question-quantifier.ts index e481d3200..ef7adc09c 100644 --- a/tests/lib/rules/prefer-question-quantifier.ts +++ b/tests/lib/rules/prefer-question-quantifier.ts @@ -3,7 +3,7 @@ import rule from "../../../lib/rules/prefer-question-quantifier" const tester = new RuleTester({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: "latest", sourceType: "module", }, }) @@ -58,6 +58,11 @@ tester.run("prefer-question-quantifier", rule as any, { }, ], }, + { + code: "/(a){0,1}/v", + output: "/(a)?/v", + errors: ["Unexpected quantifier '{0,1}'. Use '?' instead."], + }, { code: "/(a){0,1}?/", output: "/(a)??/", diff --git a/tests/lib/rules/prefer-range.ts b/tests/lib/rules/prefer-range.ts index 8a6ba0ca8..3ea3faeba 100644 --- a/tests/lib/rules/prefer-range.ts +++ b/tests/lib/rules/prefer-range.ts @@ -3,7 +3,7 @@ import rule from "../../../lib/rules/prefer-range" const tester = new RuleTester({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: "latest", sourceType: "module", }, }) @@ -58,6 +58,8 @@ tester.run("prefer-range", rule as any, { code: `/[а-яА-Я][А-Яа-я]/`, options: [{ target: ["alphanumeric", "а-я", "А-Я"] }], }, + + String.raw`/[\q{a|b|c|d|e|f|abcdef}]/v`, ], invalid: [ { @@ -82,6 +84,14 @@ tester.run("prefer-range", rule as any, { "Unexpected multiple adjacent characters. Use 'a-d' instead.", ], }, + { + code: `/[ABCD abcd]/v`, + output: `/[A-D a-d]/v`, + errors: [ + "Unexpected multiple adjacent characters. Use 'A-D' instead.", + "Unexpected multiple adjacent characters. Use 'a-d' instead.", + ], + }, { code: `/[abc-f]/`, output: `/[a-f]/`, diff --git a/tests/lib/rules/prefer-star-quantifier.ts b/tests/lib/rules/prefer-star-quantifier.ts index 888916594..525994907 100644 --- a/tests/lib/rules/prefer-star-quantifier.ts +++ b/tests/lib/rules/prefer-star-quantifier.ts @@ -3,7 +3,7 @@ import rule from "../../../lib/rules/prefer-star-quantifier" const tester = new RuleTester({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: "latest", sourceType: "module", }, }) @@ -44,6 +44,11 @@ tester.run("prefer-star-quantifier", rule as any, { }, ], }, + { + code: "/(a){0,}/v", + output: "/(a)*/v", + errors: ["Unexpected quantifier '{0,}'. Use '*' instead."], + }, { code: "/(a){0,}?/", output: "/(a)*?/", diff --git a/tests/lib/rules/sort-flags.ts b/tests/lib/rules/sort-flags.ts index e40d54de5..3cc77f9dd 100644 --- a/tests/lib/rules/sort-flags.ts +++ b/tests/lib/rules/sort-flags.ts @@ -3,7 +3,7 @@ import rule from "../../../lib/rules/sort-flags" const tester = new RuleTester({ parserOptions: { - ecmaVersion: 2020, + ecmaVersion: "latest", sourceType: "module", }, }) @@ -14,10 +14,12 @@ tester.run("sort-flags", rule as any, { String.raw`/\w/im`, String.raw`/\w/gi`, String.raw`/\w/gimsuy`, + String.raw`/\w/gimsvy`, String.raw`new RegExp("\\w", "i")`, String.raw`new RegExp("\\w", "gi")`, String.raw`new RegExp("\\w", "gimsuy")`, String.raw`new RegExp("\\w", "dgimsuy")`, + String.raw`new RegExp("\\w", "dgimsvy")`, // ignore String.raw` @@ -38,6 +40,11 @@ tester.run("sort-flags", rule as any, { }, ], }, + { + code: String.raw`/\w/yvsimg`, + output: String.raw`/\w/gimsvy`, + errors: ["The flags 'yvsimg' should be in the order 'gimsvy'."], + }, { code: String.raw`new RegExp("\\w", "yusimg")`, output: String.raw`new RegExp("\\w", "gimsuy")`,