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

@b9g/match-pattern

v0.2.1

Published

High-performance URLPattern-compatible implementation for web routing with enhanced search parameter handling.

Readme

MatchPattern

High-performance URLPattern-compatible implementation for web routing with enhanced search parameter handling.

Overview

This package provides two classes:

  • URLPattern: A 100% WPT-compliant implementation that's ~40-60x faster than the polyfill/native
  • MatchPattern: Same performance with routing enhancements (order-independent search params, unified params object)

Both compile patterns directly to RegExp in a single pass, bypassing the multi-stage pipeline used by polyfill/native implementations.

Installation

npm install @b9g/match-pattern

Basic Usage

import {MatchPattern, URLPattern} from '@b9g/match-pattern';

// URLPattern: 100% WPT-compliant, ~60x faster than polyfill/native
const strict = new URLPattern({ pathname: '/api/posts/:id' });

// MatchPattern: Same performance + DX improvements
const pattern = new MatchPattern('/api/posts/:id&format=:format');
const url = new URL('http://example.com/api/posts/123?format=json&page=1');

if (pattern.test(url)) {
  const result = pattern.exec(url);
  console.log(result.params);
  // { id: '123', format: 'json', page: '1' }
}

Performance

MatchPattern compiles patterns directly to optimized RegExp in a single pass, while the URLPattern polyfill uses a multi-stage pipeline (lexer → parser → RegExp generator). This results in ~40-60x faster pattern matching:

| Benchmark | URLPattern | MatchPattern | Polyfill | Native | |-----------|------------|--------------|----------|--------| | Static test() | 37ns | 72ns | 3.02µs | 2.32µs | | Dynamic exec() | 304ns | 483ns | 2.45µs | 2.42µs | | Construction | 760ns | 634ns | 16.58µs | 16.17µs |

Benchmarks run on Apple M1, Bun 1.3.3. See bench/urlpattern.bench.js.

MatchPattern adds ~35ns overhead for order-independent search parameter matching - a feature the URLPattern spec explicitly doesn't support.

All URLPattern syntax is fully supported including:

  • Named parameters with regex constraints: :id(\d+)
  • Optional parameters: :id?
  • Repeat modifiers: :path+, :path*
  • Wildcards: *
  • Regex groups: (\d+)
  • Explicit delimiters: {/old}?
  • Escaped characters: \.

Key Differences from URLPattern

1. Order-Independent Search Parameters

URLPattern requires exact parameter order. MatchPattern allows any order:

const pattern = new MatchPattern({search: 'type=:type&sort=:sort'});

// URLPattern: Only first URL matches
// MatchPattern: Both URLs match
pattern.test('/?type=blog&sort=date');  // Both: true
pattern.test('/?sort=date&type=blog');  // MatchPattern: true, URLPattern: false

2. Non-Exhaustive Search Matching

URLPattern uses greedy capture that lumps extra params into the last parameter value. MatchPattern properly parses them:

const pattern = new MatchPattern({search: 'q=:query'});

// URLPattern greedy capture issue
const urlPattern = new URLPattern({search: 'q=:query'});
urlPattern.exec('?q=hello&page=1').search.groups;  // { query: "hello&page=1" }

// MatchPattern proper parsing
const result = pattern.exec('/?q=hello&page=1&limit=10');
console.log(result.params);  // {q: 'hello', page: '1', limit: '10'}

Required parameters must be present, but extra parameters are allowed:

pattern.test('/search');                         // false (q missing)
pattern.test('/search?q=hello');                 // true
pattern.test('/search?q=hello&page=1&limit=10'); // true (extras captured)

3. Unified Parameter Object

URLPattern separates pathname and search groups. MatchPattern merges everything:

const pattern = new MatchPattern('/api/:version/posts/:id&format=:format');
const result = pattern.exec('/api/v1/posts/123?format=json&page=1');

// URLPattern: result.pathname.groups + result.search.groups (separate)
// MatchPattern: result.params (unified)
console.log(result.params); // {version: 'v1', id: '123', format: 'json', page: '1'}

4. Enhanced String Pattern Syntax

It's not possible to separate pathname from search with ? because the syntax is used to indicate optionality, so MatchPattern supports convenient string patterns with & separator:

// Pathname only (URLPattern throws a TypeError when passing a relative path without a baseURL)
new MatchPattern('/api/posts/:id')

// Pathname with search parameters
new MatchPattern('/api/posts/:id&format=:format&page=:page')

// Search parameters only
new MatchPattern('&q=:query&sort=:sort')

// Full URL patterns
new MatchPattern('https://api.example.com/v1/posts/:id&format=:format')

// Object syntax (same as URLPattern, enhanced behavior)
new MatchPattern({
  pathname: '/api/posts/:id',
  search: 'format=:format'
})

Trailing Slash Handling

MatchPattern does not automatically normalize trailing slashes. Use explicit patterns:

// Exact matching
const exactPattern = new MatchPattern('/api/posts/:id');
exactPattern.test('/api/posts/123');   // true
exactPattern.test('/api/posts/123/');  // false

// Optional trailing slash
const flexiblePattern = new MatchPattern('/api/posts/:id{/}?');
flexiblePattern.test('/api/posts/123');   // true
flexiblePattern.test('/api/posts/123/');  // true

Implementation Notes

Direct RegExp Compilation

MatchPattern compiles URLPattern syntax directly to RegExp in a single pass, while the URLPattern polyfill uses a multi-stage pipeline (lexer → parser → RegExp generator). This approach provides:

  • Performance: ~40-60x faster than the URLPattern polyfill and native implementations
  • Consistency: Same behavior across all JavaScript runtimes
  • Zero dependencies: No polyfill required
  • Simplicity: Direct pattern-to-RegExp compilation with minimal overhead

URLPattern Spec Compliance

The URLPattern class passes 100% of the Web Platform Tests (755 tests). It implements the full URLPattern specification:

  • Named parameters: :id, :id(\d+)
  • Optional parameters: :id?
  • Repeat modifiers: :path+, :path*
  • Wildcards: *
  • Regex groups: (\d+)
  • Explicit delimiters: {/old}?
  • Escaped characters: \.
  • Protocol, hostname, port, pathname, search, and hash matching
  • baseURL parameter for relative pattern resolution
  • ignoreCase option

MatchPattern intentionally deviates from strict spec compliance in two areas to provide better routing ergonomics:

  • Allows relative patterns without baseURL (convenience for routing)
  • Order-independent search parameter matching

Exports

Classes

  • URLPattern - 100% WPT-compliant URLPattern implementation
  • MatchPattern - URLPattern with routing enhancements (order-independent search params, unified params)

Types

  • MatchPatternResult - Result type for MatchPattern.exec()
  • URLPatternOptions - Options for URLPattern constructor (ignoreCase, etc.)
  • ParsedPattern - Parsed pattern structure
  • PatternSegment - Individual segment of a parsed pattern
  • CompiledPattern - Internal compiled pattern representation

Utility Functions

Advanced functions for pattern inspection and compilation for optimized routers

  • isSimplePattern(pathname: string): boolean - Check if pathname is a simple pattern (no regex features)
  • parseSimplePattern(pathname: string): ParsedPattern | null - Parse a simple pattern into segments
  • compilePathname(pathname: string, options?: object): CompiledPattern - Compile a pathname pattern to RegExp

API Reference

URLPattern

class URLPattern {
  constructor(input?: string | URLPatternInit, baseURL?: string, options?: URLPatternOptions)

  test(input: string | URL | URLPatternInit, baseURL?: string): boolean
  exec(input: string | URL | URLPatternInit, baseURL?: string): URLPatternResult | null

  readonly protocol: string
  readonly username: string
  readonly password: string
  readonly hostname: string
  readonly port: string
  readonly pathname: string
  readonly search: string
  readonly hash: string
}

MatchPattern

class MatchPattern {
  constructor(input: string | URLPatternInit, baseURL?: string)

  test(input: string | URL): boolean
  exec(input: string | URL): MatchPatternResult | null
}

Utility Functions

Advanced functions for pattern inspection and compilation (used by router optimizations):

// Check if a pathname pattern contains only literal segments and named parameters
function isSimplePattern(pathname: string): boolean

// Parse a simple pattern into its component segments
function parseSimplePattern(pathname: string): ParsedPattern | null

// Compile a pathname pattern to optimized RegExp
function compilePathname(
  pathname: string,
  options?: { ignoreCase?: boolean }
): CompiledPattern

Types

interface MatchPatternResult extends URLPatternResult {
  params: Record<string, string>;  // Unified parameters from pathname and search
}

interface URLPatternOptions {
  ignoreCase?: boolean;  // Case-insensitive matching
}

interface ParsedPattern {
  segments: PatternSegment[];
  paramNames: string[];
}

type PatternSegment =
  | { type: 'literal'; value: string }
  | { type: 'param'; name: string; pattern?: string }
  | { type: 'wildcard' }
  | { type: 'group'; segments: PatternSegment[] }

interface CompiledPattern {
  regexp: RegExp;
  paramNames: string[];
}

Compatibility

  • Runtimes: Node, Deno, Bun, Cloudflare Workers, Edge Runtime, any JavaScript environment
  • Browsers: All browsers (no polyfill required)
  • TypeScript: 5.0+ recommended

Contributing

MatchPattern follows the WHATWG URLPattern specification while extending it for routing use cases.

Report issues related to:

  • URLPattern compatibility problems
  • Performance issues with complex patterns
  • Cross-runtime behavior differences

License

MIT