oxc-project/oxc · warning · OxcDiagnostic

Capture group should be named.

Error message

Capture group should be named.

What it means

Diagnostic from the oxlint `prefer-named-capture-group` rule. It fires when a regular expression literal or `new RegExp(...)` contains unnamed capture groups; the help text (prefer_named_capture_group.rs:23-31) reports the count of unnamed groups and shows the named syntax `(?<name>...)`. Named groups (ES2018) make match indices addressable by name instead of position.

Source

Thrown at crates/oxc_linter/src/rules/eslint/prefer_named_capture_group.rs:23

};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_regular_expression::{
    LiteralParser, Options,
    ast::Pattern,
    visit::{RegExpAstKind, Visit},
};
use oxc_span::{GetSpan, Span};

use crate::{
    AstNode,
    context::LintContext,
    rule::Rule,
    utils::{is_regexp_callee, run_on_regex_node, static_string_value},
};

fn prefer_named_capture_group_diagnostic(span: Span, unnamed_count: usize) -> OxcDiagnostic {
    OxcDiagnostic::warn("Capture group should be named.")
        .with_help(format!(
            "Use a named capture group like \"(?<name>...)\" — this regex has {unnamed_count} unnamed group{}.",
            if unnamed_count == 1 { "" } else { "s" }
        ))
        .with_label(span)
}

#[derive(Debug, Default, Clone)]
pub struct PreferNamedCaptureGroup;

declare_oxc_lint!(
    /// ### What it does
    ///
    /// Enforces the use of named capture groups in regular expressions.
    ///
    /// ### Why is this bad?
    ///
    /// Unnamed capturing groups (`(...)`) are referenced only by position, which

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Name every group: `(\d+)` becomes `(?<num>\d+)` and update consumers to `match.groups.num`.
  2. Drop groups that do not need capturing: `(?:...)` for non-capturing grouping.
  3. If you must support runtimes without named groups (or older transpilers), disable the rule for that file.
  4. For `new RegExp` strings, apply the same naming inside the pattern string.

Example fix

// before
const m = /(\d{4})-(\d{2})/.exec(s);

// after
const m = /(?<year>\d{4})-(?<month>\d{2})/.exec(s);
const { year, month } = m.groups;
Defensive patterns

Strategy: validation

Validate before calling

// pre-check regexes in review; lint gate:
// package.json script: "lint:regex": "oxlint --rules prefer-named-capture-group=warn src/"

Prevention

When it happens

Trigger: Enable the rule and write any regex with a bare group: `/@(\w+)/`, `/(\d{4})-(\d{2})/`, or a dynamic regex passed through run_on_regex_node (imported in the file, which also runs on `new RegExp` strings when static).

Common situations: Date/URL parsing regexes written before ES2018; porting ESLint configs that include this rule; regexes shared with older tooling that cannot parse named groups; multi-group regexes where positional matches (`m[1]`, `m[2]`) silently break after group reordering — exactly the bug named groups prevent.

Related errors


AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20). Data as JSON: /api/errors/e4c344801db0cd8f. Report an issue: GitHub.