UNPKG

11.5 kBMarkdownView Raw
1# Path-to-RegExp
2
3> Turn a path string such as `/user/:name` into a regular expression.
4
5[![NPM version][npm-image]][npm-url]
6[![Build status][travis-image]][travis-url]
7[![Test coverage][coveralls-image]][coveralls-url]
8[![Dependency Status][david-image]][david-url]
9[![License][license-image]][license-url]
10[![Downloads][downloads-image]][downloads-url]
11
12## Installation
13
14```
15npm install path-to-regexp --save
16```
17
18## Usage
19
20```javascript
21const { pathToRegexp, match, parse, compile } = require("path-to-regexp");
22
23// pathToRegexp(path, keys?, options?)
24// match(path)
25// parse(path)
26// compile(path)
27```
28
29- **path** A string, array of strings, or a regular expression.
30- **keys** An array to populate with keys found in the path.
31- **options**
32 - **sensitive** When `true` the regexp will be case sensitive. (default: `false`)
33 - **strict** When `true` the regexp won't allow an optional trailing delimiter to match. (default: `false`)
34 - **end** When `true` the regexp will match to the end of the string. (default: `true`)
35 - **start** When `true` the regexp will match from the beginning of the string. (default: `true`)
36 - **delimiter** The default delimiter for segments, e.g. `[^/#?]` for `:named` patterns. (default: `'/#?'`)
37 - **endsWith** Optional character, or list of characters, to treat as "end" characters.
38 - **encode** A function to encode strings before inserting into `RegExp`. (default: `x => x`)
39 - **prefixes** List of characters to automatically consider prefixes when parsing. (default: `./`)
40
41```javascript
42const keys = [];
43const regexp = pathToRegexp("/foo/:bar", keys);
44// regexp = /^\/foo(?:\/([^\/#\?]+?))[\/#\?]?$/i
45// keys = [{ name: 'bar', prefix: '/', suffix: '', pattern: '[^\\/#\\?]+?', modifier: '' }]
46```
47
48**Please note:** The `RegExp` returned by `path-to-regexp` is intended for ordered data (e.g. pathnames, hostnames). It can not handle arbitrarily ordered data (e.g. query strings, URL fragments, JSON, etc). When using paths that contain query strings, you need to escape the question mark (`?`) to ensure it does not flag the parameter as [optional](#optional).
49
50### Parameters
51
52The path argument is used to define parameters and populate keys.
53
54#### Named Parameters
55
56Named parameters are defined by prefixing a colon to the parameter name (`:foo`).
57
58```js
59const regexp = pathToRegexp("/:foo/:bar");
60// keys = [{ name: 'foo', prefix: '/', ... }, { name: 'bar', prefix: '/', ... }]
61
62regexp.exec("/test/route");
63//=> [ '/test/route', 'test', 'route', index: 0, input: '/test/route', groups: undefined ]
64```
65
66**Please note:** Parameter names must use "word characters" (`[A-Za-z0-9_]`).
67
68##### Custom Matching Parameters
69
70Parameters can have a custom regexp, which overrides the default match (`[^/]+`). For example, you can match digits or names in a path:
71
72```js
73const regexpNumbers = pathToRegexp("/icon-:foo(\\d+).png");
74// keys = [{ name: 'foo', ... }]
75
76regexpNumbers.exec("/icon-123.png");
77//=> ['/icon-123.png', '123']
78
79regexpNumbers.exec("/icon-abc.png");
80//=> null
81
82const regexpWord = pathToRegexp("/(user|u)");
83// keys = [{ name: 0, ... }]
84
85regexpWord.exec("/u");
86//=> ['/u', 'u']
87
88regexpWord.exec("/users");
89//=> null
90```
91
92**Tip:** Backslashes need to be escaped with another backslash in JavaScript strings.
93
94##### Custom Prefix and Suffix
95
96Parameters can be wrapped in `{}` to create custom prefixes or suffixes for your segment:
97
98```js
99const regexp = pathToRegexp("/:attr1?{-:attr2}?{-:attr3}?");
100
101regexp.exec("/test");
102// => ['/test', 'test', undefined, undefined]
103
104regexp.exec("/test-test");
105// => ['/test', 'test', 'test', undefined]
106```
107
108#### Unnamed Parameters
109
110It is possible to write an unnamed parameter that only consists of a regexp. It works the same the named parameter, except it will be numerically indexed:
111
112```js
113const regexp = pathToRegexp("/:foo/(.*)");
114// keys = [{ name: 'foo', ... }, { name: 0, ... }]
115
116regexp.exec("/test/route");
117//=> [ '/test/route', 'test', 'route', index: 0, input: '/test/route', groups: undefined ]
118```
119
120#### Modifiers
121
122Modifiers must be placed after the parameter (e.g. `/:foo?`, `/(test)?`, `/:foo(test)?`, or `{-:foo(test)}?`).
123
124##### Optional
125
126Parameters can be suffixed with a question mark (`?`) to make the parameter optional.
127
128```js
129const regexp = pathToRegexp("/:foo/:bar?");
130// keys = [{ name: 'foo', ... }, { name: 'bar', prefix: '/', modifier: '?' }]
131
132regexp.exec("/test");
133//=> [ '/test', 'test', undefined, index: 0, input: '/test', groups: undefined ]
134
135regexp.exec("/test/route");
136//=> [ '/test/route', 'test', 'route', index: 0, input: '/test/route', groups: undefined ]
137```
138
139**Tip:** The prefix is also optional, escape the prefix `\/` to make it required.
140
141When dealing with query strings, escape the question mark (`?`) so it doesn't mark the parameter as optional. Handling unordered data is outside the scope of this library.
142
143```js
144const regexp = pathToRegexp("/search/:tableName\\?useIndex=true&term=amazing");
145
146regexp.exec("/search/people?useIndex=true&term=amazing");
147//=> [ '/search/people?useIndex=true&term=amazing', 'people', index: 0, input: '/search/people?useIndex=true&term=amazing', groups: undefined ]
148
149// This library does not handle query strings in different orders
150regexp.exec("/search/people?term=amazing&useIndex=true");
151//=> null
152```
153
154##### Zero or more
155
156Parameters can be suffixed with an asterisk (`*`) to denote a zero or more parameter matches.
157
158```js
159const regexp = pathToRegexp("/:foo*");
160// keys = [{ name: 'foo', prefix: '/', modifier: '*' }]
161
162regexp.exec("/");
163//=> [ '/', undefined, index: 0, input: '/', groups: undefined ]
164
165regexp.exec("/bar/baz");
166//=> [ '/bar/baz', 'bar/baz', index: 0, input: '/bar/baz', groups: undefined ]
167```
168
169##### One or more
170
171Parameters can be suffixed with a plus sign (`+`) to denote a one or more parameter matches.
172
173```js
174const regexp = pathToRegexp("/:foo+");
175// keys = [{ name: 'foo', prefix: '/', modifier: '+' }]
176
177regexp.exec("/");
178//=> null
179
180regexp.exec("/bar/baz");
181//=> [ '/bar/baz','bar/baz', index: 0, input: '/bar/baz', groups: undefined ]
182```
183
184### Match
185
186The `match` function will return a function for transforming paths into parameters:
187
188```js
189// Make sure you consistently `decode` segments.
190const match = match("/user/:id", { decode: decodeURIComponent });
191
192match("/user/123"); //=> { path: '/user/123', index: 0, params: { id: '123' } }
193match("/invalid"); //=> false
194match("/user/caf%C3%A9"); //=> { path: '/user/caf%C3%A9', index: 0, params: { id: 'café' } }
195```
196
197#### Process Pathname
198
199You should make sure variations of the same path match the expected `path`. Here's one possible solution using `encode`:
200
201```js
202const match = match("/café", { encode: encodeURI, decode: decodeURIComponent });
203
204match("/user/caf%C3%A9"); //=> { path: '/user/caf%C3%A9', index: 0, params: { id: 'café' } }
205```
206
207**Note:** [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) automatically encodes pathnames for you.
208
209##### Alternative Using Normalize
210
211Sometimes you won't have an already normalized pathname. You can normalize it yourself before processing:
212
213```js
214/**
215 * Normalize a pathname for matching, replaces multiple slashes with a single
216 * slash and normalizes unicode characters to "NFC". When using this method,
217 * `decode` should be an identity function so you don't decode strings twice.
218 */
219function normalizePathname(pathname: string) {
220 return (
221 decodeURI(pathname)
222 // Replaces repeated slashes in the URL.
223 .replace(/\/+/g, "/")
224 // Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize
225 // Note: Missing native IE support, may want to skip this step.
226 .normalize()
227 );
228}
229
230// Two possible ways of writing `/café`:
231const re = pathToRegexp("/caf\u00E9");
232const input = encodeURI("/cafe\u0301");
233
234re.test(input); //=> false
235re.test(normalizePathname(input)); //=> true
236```
237
238### Parse
239
240The `parse` function will return a list of strings and keys from a path string:
241
242```js
243const tokens = parse("/route/:foo/(.*)");
244
245console.log(tokens[0]);
246//=> "/route"
247
248console.log(tokens[1]);
249//=> { name: 'foo', prefix: '/', suffix: '', pattern: '[^\\/#\\?]+?', modifier: '' }
250
251console.log(tokens[2]);
252//=> { name: 0, prefix: '/', suffix: '', pattern: '.*', modifier: '' }
253```
254
255**Note:** This method only works with strings.
256
257### Compile ("Reverse" Path-To-RegExp)
258
259The `compile` function will return a function for transforming parameters into a valid path:
260
261```js
262// Make sure you encode your path segments consistently.
263const toPath = compile("/user/:id", { encode: encodeURIComponent });
264
265toPath({ id: 123 }); //=> "/user/123"
266toPath({ id: "café" }); //=> "/user/caf%C3%A9"
267toPath({ id: "/" }); //=> "/user/%2F"
268
269toPath({ id: ":/" }); //=> "/user/%3A%2F"
270
271// Without `encode`, you need to make sure inputs are encoded correctly.
272const toPathRaw = compile("/user/:id");
273
274toPathRaw({ id: "%3A%2F" }); //=> "/user/%3A%2F"
275toPathRaw({ id: ":/" }, { validate: false }); //=> "/user/:/"
276
277const toPathRepeated = compile("/:segment+");
278
279toPathRepeated({ segment: "foo" }); //=> "/foo"
280toPathRepeated({ segment: ["a", "b", "c"] }); //=> "/a/b/c"
281
282const toPathRegexp = compile("/user/:id(\\d+)");
283
284toPathRegexp({ id: 123 }); //=> "/user/123"
285toPathRegexp({ id: "123" }); //=> "/user/123"
286toPathRegexp({ id: "abc" }); //=> Throws `TypeError`.
287toPathRegexp({ id: "abc" }, { validate: false }); //=> "/user/abc"
288```
289
290**Note:** The generated function will throw on invalid input.
291
292### Working with Tokens
293
294Path-To-RegExp exposes the two functions used internally that accept an array of tokens:
295
296- `tokensToRegexp(tokens, keys?, options?)` Transform an array of tokens into a matching regular expression.
297- `tokensToFunction(tokens)` Transform an array of tokens into a path generator function.
298
299#### Token Information
300
301- `name` The name of the token (`string` for named or `number` for unnamed index)
302- `prefix` The prefix string for the segment (e.g. `"/"`)
303- `suffix` The suffix string for the segment (e.g. `""`)
304- `pattern` The RegExp used to match this token (`string`)
305- `modifier` The modifier character used for the segment (e.g. `?`)
306
307## Compatibility with Express <= 4.x
308
309Path-To-RegExp breaks compatibility with Express <= `4.x`:
310
311- RegExp special characters can only be used in a parameter
312 - Express.js 4.x supported `RegExp` special characters regardless of position - this is considered a bug
313- Parameters have suffixes that augment meaning - `*`, `+` and `?`. E.g. `/:user*`
314- No wildcard asterisk (`*`) - use parameters instead (`(.*)` or `:splat*`)
315
316## Live Demo
317
318You can see a live demo of this library in use at [express-route-tester](http://forbeslindesay.github.com/express-route-tester/).
319
320## License
321
322MIT
323
324[npm-image]: https://img.shields.io/npm/v/path-to-regexp.svg?style=flat
325[npm-url]: https://npmjs.org/package/path-to-regexp
326[travis-image]: https://img.shields.io/travis/pillarjs/path-to-regexp.svg?style=flat
327[travis-url]: https://travis-ci.org/pillarjs/path-to-regexp
328[coveralls-image]: https://img.shields.io/coveralls/pillarjs/path-to-regexp.svg?style=flat
329[coveralls-url]: https://coveralls.io/r/pillarjs/path-to-regexp?branch=master
330[david-image]: http://img.shields.io/david/pillarjs/path-to-regexp.svg?style=flat
331[david-url]: https://david-dm.org/pillarjs/path-to-regexp
332[license-image]: http://img.shields.io/npm/l/path-to-regexp.svg?style=flat
333[license-url]: LICENSE.md
334[downloads-image]: http://img.shields.io/npm/dm/path-to-regexp.svg?style=flat
335[downloads-url]: https://npmjs.org/package/path-to-regexp
336
\No newline at end of file