Efficiently match URL paths against a collection of URL patterns using a fixed pathname-literal index with conservative fallback.
Fork note: this is the OpenElement-maintained fork of justinfagnani/url-pattern-list v0.5.0. See PROVENANCE.md for sources and license, and DIVERGENCE.md for what differs and why.
url-pattern-list is a JavaScript library that provides an efficient way to
match URLs against multiple
URLPattern
instances. Instead of testing every pattern linearly, URLPatternList
indexes patterns whose pathname is a canonical literal in a fixed prefix
tree, keeps all other patterns in a conservative list, and merges both by
registration order at match time — so only patterns that can possibly match
are exec'd.
URLPatternList has exactly the same matching semantics as scanning a
linear list of patterns, and is differentially tested against such a linear
oracle for both native and polyfill URLPattern constructors. The first
pattern (in the order patterns were added to the list) whose complete
exec() matches a URL is returned as the match.
Patterns are added to the list along with an additional value that is returned with the match. This makes it easy to associate a URLPattern with metadata or an object like a server route handler.
npm i @openelement/url-pattern-listimport {URLPatternList} from '@openelement/url-pattern-list';
// Create a new pattern list
const routes = new URLPatternList<string>();
// Add patterns with associated values
routes.addPattern(new URLPattern({pathname: '/api/users/:id'}), 'user-detail');
routes.addPattern(new URLPattern({pathname: '/api/users'}), 'user-list');
routes.addPattern(new URLPattern({pathname: '/api/posts/:id'}), 'post-detail');
// Match against a URL
const match = routes.match('/api/users/123');
if (match) {
console.log('Route:', match.value); // 'user-detail'
console.log('User ID:', match.result.pathname.groups.id); // '123'
}Lookup cost is driven by the number of candidate patterns exec'd, not the number of patterns registered: static-heavy workloads exec a handful of candidates at any scale, while workloads dominated by non-literal patterns (regex, groups, wildcards) degrade gracefully to linear scan. Benchmarks cover construction, hit, miss and memory against a linear oracle and upstream v0.5.0; see BENCHMARKS.md for numbers and methodology.
To run the benchmark on your machine:
npm i --prefix .tmp-upstream url-pattern-list@0.5.0 # optional comparison
npm run benchmarkThe main class for managing and matching URL patterns.
import {URLPatternList} from '@openelement/url-pattern-list';Add a URL pattern to the collection with an associated value. ListPattern
is any object with a pathname getter and the exec() method of the
URLPattern interface — native URLPattern and urlpattern-polyfill
instances both work.
const list = new URLPatternList<RouteHandler>();
list.addPattern(new URLPattern({pathname: '/users/:id'}), handleUserDetail);Match a URL against all patterns, returning the first match found. Relative
string input requires baseUrl; invalid input throws a TypeError, even
for an empty list.
const match = list.match('/users/123', 'https://example.com');
if (match) {
// match.result contains the URLPatternResult
// match.value contains your associated value
}Diagnostic upper bound on how many patterns match() would exec for the
given input. Not part of the matching semantics.
interface URLPatternListMatch<T> {
result: URLPatternResult; // Standard URLPattern match result
value: T; // Your associated value
}This library works with any URLPattern implementation you supply — native:
- Chrome 95+
- Firefox 142+ (Preview support)
- Safari 26.0+ (Preview support)
— or the URLPattern polyfill (patterns built from either constructor can be mixed in one list).
The upstream visualizer was removed in 0.6.0 because it rendered the internals of the removed per-component prefix tree. See DIVERGENCE.md.
Contributions are welcome! Please feel free to submit a Pull Request.
MIT License. See LICENSE file for details.