Skip to content

@neodx/glob

Simple glob matching low-level APIs inspired by zeptomatch.

  • Tiny, fast and works similarly to picomatch
  • Lightweight
  • Opinionated for simplicity
  • Provides a walkGlob, which you can use to develop your own glob-based logic

Installation

bash
npm install -D @neodx/glob
bash
yarn add -D @neodx/glob
bash
pnpm add -D @neodx/glob

Usage

Match a string against a glob pattern

typescript
import { createGlobMatcher, matchGlob } from '@neodx/glob';

// As a reusable function
const isSourceFile = createGlobMatcher('**/*.[jt]s');

console.log(isSourceFile('foo.js')); // true
console.log(isSourceFile('some/path/foo.ts')); // true
console.log(isSourceFile('some/path/foo.js.map')); // false

// As a one-off function
console.log(matchGlob('**/*.[jt]s', 'foo.js')); // true

Create your own glob scanner

walkGlob provides a simple low-level API to create your own glob reader. For example, the simplest implementation on the top of it could look like this:

typescript
import { walkGlob } from '@neodx/glob';
import { readdir } from 'node:fs/promises';
import { join, resolve } from 'node:path';

async function glob(patterns, { cwd = process.cwd(), ...params } = {}) {
  return await walkGlob(patterns, {
    ...params,
    // The reader will be called for each static path extracted from the glob pattern(s)
    reader: ({ path }) => readdir(resolve(cwd, path), { recursive: true })
  });
}

console.log(
  await glob(['{src,tests}/**/*.ts', 'server/*.config.ts'], {
    ignore: ['**/*.test.ts']
  })
);
// [
//   'src/index.ts',
//   'tests/common/utils.ts',
//   'server/app.config.ts',
// ]

Static paths extraction

Extracts all the static paths from a glob pattern(s) and associates them with the pattern(s) they belong to.

typescript
import { extractGlobPaths } from '@neodx/glob';

console.log(
  extractGlobPaths(['*.config.js', 'src/**/*.ts', 'src/*.vendor.js', '{src,tests}/**/*.ts'])
);
// [
//   ['', ['*.config.js']],               // no base path
//   ['src', ['**/*.ts', '*.vendor.js']], // base path is `src`, multiple patterns with same base path are grouped
//   ['tests', ['**/*.ts']],              // base path is `src`, a single pattern with a different base path
// ]

Escaping

Escapes a glob pattern to match literal characters.

typescript
import { unescapeGlob, escapeGlob, matchGlob } from '@neodx/glob';

const escaped = escapeGlob('**/*.[jt]s'); // \*\*\/\*\.\[jt\]s

console.log(matchGlob(escaped, '**/*.[jt]s')); // true
console.log(matchGlob(escaped, 'foo.js')); // false

// You can unescape the glob to get the original pattern back:
console.log(unescapeGlob(escaped)); // **/*.[jt]s

API Reference

Special Characters Cheat Sheet

SyntaxDescription
*Matches any character, except for the path separator, zero or more times.
**Matches any character zero or more times. If it doesn't span the entire length of a path segment it's interpreted as a * instead.
?Matches any character, except for the path separator, one time.
\Matches the character after it in the glob literally. This is the escape operator.
[abc]Matches any of the characters in the class one time.
[a-z]Matches any of the characters in the range in the class one time.
[^abc]Matches any character, except for the characters the class, and the path separator, o∏ne time. Aliased as [!abc] also.
[^a-z]Matches any character, except for the characters in the range in the class, and the path separator, one time. Aliased as [!a-z] also.
{foo,bar}Matches any of the alternations, which are separated by a comma, inside the braces.
{01..99}Matches any of the numbers in the expanded range. Padding is supported and opt-in.
{a..zz}Matches any of the strings in the expanded range. Upper-cased ranges are supported and opt-in.
!globMatches anything except the provided glob. Negations can only be used at the start of the glob.
!!globMatches the provided glob. Negations can only be used at the start of the glob.

Released under the MIT License.