Skip to Content

Regular expressions

Regular-expression rules from eslint-plugin-regexp.

These rules check regex literal structure: emptiness, uselessness, flag ordering, shorthand classes, and Unicode support.

Some rules duplicate (and supersede) the regex-related rules in Core; both ids exist so projects can keep the legacy ESLint names alongside the regexp-plugin variants.

Source: eslint-plugin-regexp (MIT).

Corrections

A rule in this family offers an automatic fix only where the rewrite provably matches the same strings — reordering flags, swapping a count quantifier for its shorthand, deleting a flag the pattern cannot exercise. Where the correction changes what the literal matches, or where more than one repair is valid, the rule offers editor suggestions instead; ttsc fix and source.fixAll.ttsc never apply those.

Every candidate rewrite is re-parsed by the compiler’s own regexp parser before it is offered. A regex repair is a splice into live syntax, so an edit that is locally right can still leave a pattern the engine rejects: /{1,}/ has no atom in front of the brace run, which makes it four literal characters rather than a quantifier, and rewriting it would produce /+/. Such a literal keeps its diagnostic and is left untouched. A rule may also decline an individual edit whose neighbours make it unsafe even though the result would parse — see regexp/no-useless-quantifier.

Rule index

Each rule name links to the detailed section below.

Examples come from the checked lint corpus  or package-level rule tests when project layout matters.

Rules

regexp/no-control-character

Reject ASCII control characters in regex literals. Alias of the bare core check.

Example:

// reports: regexp/no-control-character (error) const control = /\x1f/;

regexp/no-dupe-characters-character-class

Reject duplicate literal characters inside simple regex character classes (/[aa]/).

Example:

// reports: regexp/no-dupe-characters-character-class (error) const duplicate = /[aba]/;

regexp/no-empty-alternative

Reject empty alternatives in a disjunction (/a||b/), which silently match the empty string.

Example:

// reports: regexp/no-empty-alternative (error) const emptyAlt = /a||b/;

regexp/no-empty-capturing-group

Reject empty capturing groups such as /()/.

The group shifts the numbering of every later backreference and capture slot while only ever capturing the empty string, almost always a leftover from an unfinished edit.

Example:

// reports: regexp/no-empty-capturing-group (error) const emptyCap = /()/;

regexp/no-empty-character-class

Reject non-negated empty regex character classes ([]), including nested classes in Unicode Sets (v) mode. The negated form [^] matches any character and is allowed. Alias of the bare core check.

Example:

// reports: regexp/no-empty-character-class (error) const empty = /[]/;

regexp/no-empty-group

Reject empty non-capturing groups such as /(?:)/.

The group contributes nothing to the match and is virtually always a leftover from a deleted inner pattern.

Example:

// reports: regexp/no-empty-group (error) const emptyGroup = /(?:)/;

regexp/no-empty-lookarounds-assertion

Reject empty lookaround assertions such as /(?=)/ or /(?!)/.

An empty positive lookaround always matches; an empty negative lookaround never matches. The assertion either collapses to a no-op or breaks the surrounding pattern.

Example:

// reports: regexp/no-empty-lookarounds-assertion (error) const emptyLook = /(?=)/;

regexp/no-misleading-unicode-character

Reject misleading Unicode characters in regex classes. Alias of the bare misleading-character check.

Example:

// reports: regexp/no-misleading-unicode-character (error) const unicode = /[👍]/;

regexp/no-useless-character-class

Reject single-character character classes such as /[x]/, /x/ is equivalent.

Example:

// reports: regexp/no-useless-character-class (error) const single = /[x]/;

regexp/no-useless-escape

Reject unnecessary escapes inside regex literals. Alias of core no-useless-escape for regex contexts.

Example:

// reports: regexp/no-useless-escape (error) const escape = /\a/;

regexp/no-useless-flag

Reject regex flags that the literal does not exercise: i on a pattern with no case-variable character, and m on a pattern with no ^/$ assertion.

Cleans up flag combos that suggest behavior the pattern can never trigger.

A character is case-variable when the i flag widens what it matches, wherever it sits: /[a-z]/i, /[abc]/i and /^[a-z]+$/i all keep their flag, as do escapes that decode to a cased character (/[\x41]/i), non-ASCII case pairs, and \w/\b under u or v. A ^ or $ inside a character class is a plain character, so it does not save the m flag.

Undecidable patterns are left alone rather than reported: a Unicode property escape (/\p{Nd}/iu), a backreference (i makes the backreference comparison itself case-insensitive, so /(.)\1/i genuinely needs the flag), and a v-mode set-notation class all count as using the flag.

The diagnostic names the dead flags, and the autofix deletes exactly those, leaving the live flags in place (/\d+/gim becomes /\d+/g). Because the analysis is one-sided — anything it cannot settle counts as using the flag — a flag it does report is provably inert.

Example:

// reports: regexp/no-useless-flag (error) const deadIgnoreCase = /\d+/i; // not reported: `i` is what extends the class to A-Z const liveLowercaseRange = /[a-z]/i;

regexp/no-useless-quantifier

Reject quantifiers that do not change the match, constant-one counts (/a{1}/), ? on patterns already matching the empty string (/(?:a+|b*)?/), and quantifiers on non-consuming atoms (/(?:\b)+/).

Autofixable for the constant-one count: /a{1}b/ becomes /ab/. Two following characters make the deletion unsafe, and both still parse afterwards, so the rule declines the edit and reports only:

  • A lazy or nested marker (?, *, +, {). /a{1}?/ is “exactly one, lazily”; dropping the braces would leave the optional /a?/.
  • A digit. /\1{1}2/ would fuse into \12, backreference twelve rather than backreference one followed by a literal 2.

Example:

// reports: regexp/no-useless-quantifier (error) const value = /a{1}/;

regexp/no-useless-two-nums-quantifier

Reject equal min/max quantifiers (/a{2,2}/) in favor of /a{2}/. Autofixable; the braces stay in place, so the count collapses without exposing the atom to its neighbours.

Example:

// reports: regexp/no-useless-two-nums-quantifier (error) const value = /a{2,2}/;

regexp/no-zero-quantifier

Reject zero-repeat quantifiers (/a{0}/, /a{0,0}/), the atom never matches, so the quantifier is either dead code or a typo for {1,...}.

Diagnostic-only, unlike the rest of the quantifier family. The correction is to delete the atom or repair the bound, and which one was meant is not recoverable from the source; deleting only the braces would turn “never” into “once”.

Example:

// reports: regexp/no-zero-quantifier (error) const value = /a{0}/;

regexp/prefer-d

Prefer \d over [0-9] in regex literals. Autofixable; every spelled-out digit class in the literal is rewritten in one edit. \d is defined as exactly [0-9] under every flag combination.

The fix is located by walking real character classes, so a literal whose bracket is escaped (/\[0-9]/, which contains no class at all) keeps its diagnostic without being rewritten.

Example:

// reports: regexp/prefer-d (error) const digit = /[0-9]/;

regexp/prefer-plus-quantifier

Prefer + over {1,} in regex literals. Autofixable; + and {1,} bind identically, so a trailing lazy marker survives the swap (/a{1,}?/ becomes /a+?/).

Example:

// reports: regexp/prefer-plus-quantifier (error) const value = /a{1,}/;

regexp/prefer-question-quantifier

Prefer ? over {0,1} in regex literals. Autofixable. ? is both the shorthand and the lazy marker, so a lazy {0,1} correctly stutters: /a{0,1}?/ becomes /a??/.

Example:

// reports: regexp/prefer-question-quantifier (error) const value = /a{0,1}/;

regexp/prefer-star-quantifier

Prefer * over {0,} in regex literals. Autofixable, on the same terms as regexp/prefer-plus-quantifier.

Example:

// reports: regexp/prefer-star-quantifier (error) const value = /a{0,}/;

regexp/prefer-w

Prefer \w over [A-Za-z0-9_] in regex literals. Autofixable for both accepted spellings ([A-Za-z0-9_] and [a-zA-Z0-9_]). \w matches the same set under every flag combination, including iu, where the flag widens the shorthand and the spelled-out class to the same two extra code points.

Example:

// reports: regexp/prefer-w (error) const word = /[A-Za-z0-9_]/;

regexp/require-unicode-regexp

Require regex literals to use the u or v flag, so Unicode-property escapes and surrogate-pair handling stay predictable.

Offers u and v as editor suggestions rather than an automatic fix: both satisfy the rule, and both change what the pattern matches, since a surrogate pair stops being two independent code units. The flag is inserted at its canonical position instead of appended, so adding it does not leave a run that regexp/sort-flags immediately re-reports. A pattern that is only legal without a Unicode flag (/\-/, whose \- is an identity escape the stricter modes reject) is reported with no suggestion at all.

Example:

// reports: regexp/require-unicode-regexp (error) const value = /a/;

regexp/require-unicode-sets-regexp

Require regex literals to use the v flag specifically, the stricter Unicode-sets mode that enables set notation, string properties, and stricter escape rules on top of u.

Choose this over require-unicode-regexp only on engines that ship ES2024-era regex.

Offers one editor suggestion, for the same reason as its sibling: v is a stricter matching mode, not a respelling. Because u and v are mutually exclusive, the suggestion replaces an existing u (/a/giu becomes /a/giv) rather than appending.

Example:

// reports: regexp/require-unicode-sets-regexp (error) const value = /a/u;

regexp/sort-flags

Require regex flags to appear in canonical alphabetical order (dgimsuvy).

Stable ordering keeps diffs small and lets readers compare flag sets at a glance.

Autofixable: the sorted run the check already built to decide the finding is what gets written back. A permutation of a flag run cannot change what the literal matches.

Example:

// reports: regexp/sort-flags (error) const value = /a/mi; // not reported: `im` is already the canonical order const sorted = /a/im;
Last updated on