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, whichView on GitHub (pinned to e1e7af627c)
Solutions
- Name every group: `(\d+)` becomes `(?<num>\d+)` and update consumers to `match.groups.num`.
- Drop groups that do not need capturing: `(?:...)` for non-capturing grouping.
- If you must support runtimes without named groups (or older transpilers), disable the rule for that file.
- 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
- Name every capture group when writing new regexes: `(?<year>\\d{4})`.
- Use `(?:...)` for groups you never read back.
- Consume matches via `match.groups.name` so group reordering cannot break code.
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
- Disallow using `Object.assign` with an object literal as the
- Backreference '{back_reference}' will be ignored. It referen
- Backreference '{back_reference}' will be ignored. It referen
- Backreference '{back_reference}' will be ignored. It referen
- Backreference '{back_reference}' will be ignored. It referen
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/e4c344801db0cd8f.
Report an issue: GitHub.