codeowners-parser
Parse, match against, and validate GitHub CODEOWNERS files — with the position information editor tooling needs.
Why this crate
The Rust ecosystem's original codeowners crate was abandoned in 2018
with two open RUSTSEC advisories in its transitive dependencies
(RUSTSEC-2022-0013, RUSTSEC-2022-0006) and no LSP-grade features.
This crate is extracted from codeowners-lsp, where it has been
hardened against real-world CODEOWNERS files from large monorepos.
What it does
- Parse CODEOWNERS into structured lines, with optional character offsets for every pattern, owner, and inline comment — exactly what an LSP needs for hover, rename, go-to-definition, and semantic tokens.
- Match file paths against rules using GitHub's glob semantics
(
*,**,?, anchored/prefix, trailing-slash directories). Each pattern is compiled once and dispatches to a specialized matcher based on shape —*.rsbecomes a rawends_withon bytes, not a regex. - Resolve ownership for a path following "last match wins" semantics.
Pre-parse once for hot loops via
check_file_ownership_parsed. - Detect dead rules via
pattern_subsumes— used by linters to find patterns that will never match because a later rule shadows them. - Validate owner format (
@user,@org/team,email@host) and glob syntax — with the specific subset of globs CODEOWNERS actually supports (no[...]character classes, no!negation). - Locate the CODEOWNERS file in a repo (
.github/CODEOWNERS,CODEOWNERS, ordocs/CODEOWNERS).
What it doesn't do
- No file-system enumeration. Matchers take a
file_path: &str; callers supply paths however they like (walkdir,git ls-files, HTTP API, etc.). - No GitHub API calls. Validation is syntactic —
@ghostis accepted even though GitHub would reject it. - No diagnostic rendering. You get
Option<String>from validators and structured results from matchers; turn those into whatever diagnostic format your tool needs.
Quick start
[]
= "0.1"
use ;
let codeowners = "\
# Default owners
* @core-team
/docs/ @docs-team
*.rs @rust-team @reviewer
";
// Who owns a file?
let result = check_file_ownership.unwrap;
assert_eq!;
assert_eq!;
// Validate owner syntax
assert!;
assert!; // underscore not allowed
assert!;
// Validate glob syntax
assert!;
assert!;
Position-aware parsing (for editor tooling)
use ;
let lines = parse_codeowners_file_with_positions;
let line = &lines;
assert_eq!;
assert_eq!;
assert_eq!; // just past "*.rs"
assert_eq!; // at "@owner"
if let Rule = &line.content
Hot-loop ownership checks
When you need to check many paths against the same CODEOWNERS content, parse once and reuse:
use ;
let parsed = parse_codeowners_file_with_positions;
for path in
Detecting dead rules
pattern_subsumes(a, b) — is everything a matches also matched by b?
If yes, and b comes after a in the file, a is dead code.
use pattern_subsumes;
// `*` subsumes everything — any rule before a final `*` is dead.
assert!;
assert!;
// `/src/lib/` is subsumed by `/src/` (parent directory contains child).
assert!;
// Anchored dir is subsumed by the unanchored version (unanchored matches more).
assert!;
assert!;
Design notes
- Zero-copy is not a goal. Owners and patterns are returned as
String/Vec<String>. The alternative (&strtied to the input) is hostile for interactive tooling that edits CODEOWNERS content. - Pattern compilation caches per call. If you need pattern reuse
across paths, hold a
CompiledPatternyourself viaCompiledPattern::new. - Glob semantics match
git check-ignoreclosely, not gitignore's full spec. CODEOWNERS is a subset: no[...]character classes, no!negation.validate_patternrejects those.
Feature flags
None. The crate has four runtime dependencies: fast-glob, glob,
once_cell, and regex — all common and well-maintained.
Minimum supported Rust version
Rust 1.70 (the current stable-minus-a-while). Bumping MSRV is a minor-version change; we will not bump it casually.
Related
codeowners-lsp— the language server this was extracted from. Uses this crate plus a GitHub client, diagnostic engine, file cache, and the full LSP plumbing.codeowners-cli— the CLI, shipped alongside the LSP.
License
MIT