npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

gex

v4.1.2

Published

Glob expressions for JavaScript

Readme

gex

npm version Build Coverage Status Maintainability

"When regular expressions are just too hard!"

Glob expressions for JavaScript / TypeScript. * matches any run of characters, ? matches one character, ** and *? escape literal * and ?. Patterns are anchored — they must match the whole string.

This README covers the JavaScript / TypeScript package. A Go port lives in go/ — see go/README.md for installation and API. Matching semantics are the same in both ports.


Tutorial: your first gex

Install:

npm install gex

Build a matcher and try it:

const { Gex } = require('gex')

Gex('a*c').on('abbbc')   // 'abbbc' — match, returns the input
Gex('a?c').on('abc')     // 'abc'   — match
Gex('a*c').on('xyz')     //  null   — no match

on() returns the input when it matches, or null when it doesn't. Two convenient extensions cover collections:

Gex('a*').on(['ab', 'zz', 'ac'])      // ['ab', 'ac']
Gex('a*').on({ ab: 1, zz: 2, ac: 3 }) // { ab: 1, ac: 3 }

A Gex can hold several specs; a value matches if any spec matches:

Gex(['a*', 'b*']).on('bx')                // 'bx'
Gex(['a*', 'b*']).on(['ax', 'zz', 'bx'])  // ['ax', 'bx']

That's the whole library.


How-to guides

Filter a list of files

const fs = require('fs')
fs.readdir('.', (err, files) => {
  const pngs = Gex('*.png').on(files)
})

Filter an object's keys

Gex('foo*').on({ foo: 1, doo: 2, food: 3 })
// { foo: 1, food: 3 }

Property values are copied by reference. The traversal does not recurse into nested objects or arrays.

Make a fuzzy assertion in a test

When a value has fields that are noisy in tests (timestamps, random ids), pattern-match the JSON form:

const entity = { created: Date.now(), name: 'foo' }
assert.ok(Gex('{"created":*,"name":"foo"}').on(JSON.stringify(entity)))

Combine several patterns

Gex(['*.png', '*.jpg']).on(files)

A value matches if any of the supplied specs match. Specs are tried in array order; the first match wins.

Escape literal * or ?

Gex('a**b').on('a*b')   // 'a*b' — '**' is a literal '*'
Gex('a*?b').on('a?b')   // 'a?b' — '*?' is a literal '?'

g.esc(s) doubles * to ** and ? to *? for you, so user-supplied text can be embedded safely:

Gex('').esc('a*b?c')   // 'a**b*?c'

Inspect the compiled regex

Gex('a*b').re()           // /^a[\s\S]*b$/
Gex(['a', 'b']).re()      // { a: /^a$/, b: /^b$/ }
Gex('a*').toString()      // 'Gex[a*]'

Reference

Gex(spec)

Construct a Gex. spec is one of:

| Type | Treated as | | ------------------------------------------ | ----------------------------------------- | | string | one glob spec | | string[] | several glob specs (any-of) | | number / boolean / Date / RegExp | stringified, then one spec | | null / undefined / NaN | a Gex that never matches |

.on(value)

| Input | Returns | | ----------------------------------------------------- | ---------------------------------------------------- | | string / number / boolean / Date / RegExp | the input if its string form matches, else null | | array | new array of matching elements (not recursive) | | object | new object with entries whose keys match | | null / undefined / NaN | null |

.match(value)

The boolean form of .on() for scalars: true if the value's string form matches any spec, otherwise false.

.esc(s)

Escape * and ? so the result, used as a spec, matches the input literally.

.re()

Returns the compiled RegExp if the Gex has a single spec, or the { spec: RegExp } map otherwise.

.toString() / .inspect()

Render as Gex[spec1,spec2,...].


Explanation

Why a separate library when JS has regex? Glob syntax is shorter, easier to read at a glance, and easier to assemble from user-supplied input than a regex. gex is a thin compiler from glob to anchored regex plus a small filtering API for arrays and objects.

How the regex is built. Specs are anchored (^...$); * becomes [\s\S]* and ? becomes [\s\S], so patterns cross newlines. ** and *? round-trip back to literal \* and \? after escaping, so escaping composes correctly.

What .on() is for. It collapses three common shapes into one call: "is this string a match?", "which of these strings match?", and "which of these keys match?". The same Gex object handles all three.

Use cases the API is shaped around.

  • Plugin name matching (Gex('seneca-*') to recognise plugin packages).
  • Filtering filenames returned by fs.readdir.
  • Test assertions on JSON snapshots where timestamps or UUIDs are irrelevant — pattern-match those fields with *.

Other languages. The Go port in go/ shares the same matching semantics. The Go API differs where Go's type system makes a different shape natural — see go/README.md for the details.


License

Copyright (c) 2010-2026, Richard Rodger and other contributors. Licensed under MIT.