Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

glob-path-matcher

CI

Zero-dependency glob path matching for TypeScript/JavaScript: *, **, ?, [abc]/[a-z]/[!abc] character classes, {a,b} brace alternation, ! negation, a configurable dotfile policy, case sensitivity, and a matchList() with .gitignore-style negation-order semantics.

Why

Agents constantly need to test paths against include/exclude patterns — tool allow-lists, file-scoping rules, .gitignore-style filters — without pulling in minimatch/micromatch. This package implements the common glob subset with zero runtime dependencies and safe pattern-to-regex conversion (every literal character is escaped; nothing from the input pattern is ever interpreted as raw regex).

Install

npm install @ferrow/glob-path-matcher

Quickstart

import { compile, match, matchList } from "glob-path-matcher";

match("src/**/*.{js,ts}", "src/deep/nested/file.js"); // true

const matcher = compile("*.log", { caseSensitive: false });
matcher.test("DEBUG.LOG"); // true

matchList(["*.log", "!important.log"], ["debug.log", "important.log", "notes.txt"]);
// ["debug.log"] — matched by *.log, not re-excluded; important.log matched then un-matched by !important.log

API

compile(pattern: string, options?: GlobOptions): CompiledMatcher

Compiles a pattern once for reuse. CompiledMatcher = { pattern: string; negated: boolean; test(path: string): boolean }. A leading ! sets .negated but does not affect .test() itself — negation is a list-level concept, handled by matchList.

match(pattern: string, path: string, options?: GlobOptions): boolean

One-shot convenience: compile(pattern, options).test(path).

matchList(patterns: string[], paths: string[], options?: GlobOptions): string[]

Applies patterns to paths in order, .gitignore-style: a path is included in the result if the last pattern that matches it is not negated. A later !pattern can un-match an earlier hit, and a later positive pattern can re-match again after that. Paths matched by no pattern are excluded.

expandBraces(pattern: string): string[]

The brace-expansion step used internally, exported standalone — e.g. expandBraces("*.{js,ts}") -> ["*.js", "*.ts"].

interface GlobOptions {
  caseSensitive?: boolean; // default true
  dot?: boolean;           // default false — see Dotfile policy below
}

Glob syntax supported

Token Meaning
* any run of characters within one path segment (no /), including empty
** any number of whole path segments (including zero)
? exactly one character within a segment
[abc], [a-z], [!abc]/[^abc] character class / negated class
{a,b,c} brace alternation (expanded before matching; not nested)
!pattern (as the whole pattern) negation marker, used by matchList

Dotfile policy

By default (dot: false), *, **, and ? never match a path segment starting with . — matching shell-glob/.gitignore convention — unless the corresponding pattern segment itself literally starts with . (e.g. .env* matches .env.local even with dot: false, but *.js does not match .hidden.js unless dot: true).

Limits

  • Patterns are relative, /-separated segment lists — no leading-/ absolute-path semantics, no Windows \ separators (normalize first).
  • {a,b} brace groups are not nested ({a,{b,c}} expands its literal text rather than recursing) — flat/multiple groups in one pattern work fine.
  • Character classes don't support escaped ] inside the class or POSIX classes like [[:alpha:]].
  • ** only has its "span zero-or-more segments" meaning as a whole path segment; a**b is treated as two ordinary * wildcards, not a ** span.

Part of the ferrow-toolkit collection · Sponsored by Ferrow

About

Zero-dependency glob matching: **, braces, classes, negation, dotfile policy, compile() and .gitignore-style matchList()

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages