path-to-regexp
path-to-regexp copied to clipboard
how to get named keys with a negative look ahead?
say i have a request with a url
/foo/123
how can I match anything except "foo" while having the first parameter be a named key?
// in js
/(?!foo).+/[0-9]+
// also need the first param, but this is invalid
/(?!foo):animal/:num
/dog/123 => match { animal: 'dog', num: 123 }
/cat/7893434 => match { animal: 'cat', num: 7893434 }
/foo/123 => no match { animal: null }
Unfortunately, I was never able to make it works as you want. I also have a situation where this would be needed.
After some investigation, I found out that this seems to work:
/:animal((?!foo)[a-zA-Z0-9]+)/:id([0-9]+)
See CodeSandbox
@DavidHenri008 has the right idea. This falls under "Custom Matching Parameters" in the docs.
Essentially, you can put a regex in parenthesis after a named parameter in order to define a custom regex.
Actually I'll reopen this, I realize now the real issue was you couldn't start a regex with ?
. I think this isn't a bug, and luckily it gives a specific error message. Perhaps that error message should be updated to say that you need to enclose a lookahead/behind group in it's own parens? I think that is the real issue here, misunderstanding that these capture groups still need to be enclosed, as I believe they do with JS regex anyways.
The logic was I believe added in https://github.com/pillarjs/path-to-regexp/pull/207 and the code itself throwing is https://github.com/pillarjs/path-to-regexp/blob/master/src/index.ts#L85
@jonchurch thoughts on what should be changed if this is an open issue? From the implementation POV it’s not a valid regex to start with the ?
directly after an opening parenthesis. Need to consider that the parenthesis is an implementation detail of path-to-regexp
syntax and not an actual part of the regex.
@blakeembrey The best way to prevent someone running into this mistake is likely adding an example to the docs. Thinking about it, a change to the error message is overkill here.
Specifically, adding an example for lookahead/behinds.
Hey @blakeembrey @jonchurch . What's the resolution here. I ran into a similar use case to negate out urls based on a specific keyword occurrence.
something like /:page(!test)
meaning this url should be dropped if test occurs
Bump this. I'm trying to write a regex that excludes a path starting with .well-known
.
I ran into this (bug?) today with this vercel.json. Any idea what the fix is here?
"source": "/examples/:path((?!vanilla/).*)", "destination": "/examples/vanilla/:path*"
/Users/wes/.npm/_npx/aab42732f01924e5/node_modules/path-to-regexp/index.js:346
return new RegExp('^' + route, flags(options))
^
SyntaxError: Invalid regular expression: /^\/examples\/([^\/]+?)\((?\!vanilla\/)\.(.*)\)(?:\/)?$/: Invalid group
at new RegExp (<anonymous>)
at tokensToRegExp (/Users/wes/.npm/_npx/aab42732f01924e5/node_modules/path-to-regexp/index.js:346:10)
at stringToRegexp (/Users/wes/.npm/_npx/aab42732f01924e5/node_modules/path-to-regexp/index.js:288:10)
at pathToRegexp (/Users/wes/.npm/_npx/aab42732f01924e5/node_modules/path-to-regexp/index.js:370:10)
at sourceMatches (/Users/wes/.npm/_npx/aab42732f01924e5/node_modules/serve-handler/src/index.js:47:22)
at toTarget (/Users/wes/.npm/_npx/aab42732f01924e5/node_modules/serve-handler/src/index.js:70:18)
at shouldRedirect (/Users/wes/.npm/_npx/aab42732f01924e5/node_modules/serve-handler/src/index.js:174:18)
at module.exports (/Users/wes/.npm/_npx/aab42732f01924e5/node_modules/serve-handler/src/index.js:583:19)
at run (file:///Users/wes/.npm/_npx/aab42732f01924e5/node_modules/serve/build/main.js:177:13)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
Node.js v18.12.1
I think I've probably ran into the same issue while trying to use negative lookaheads combined with path params, the way vercel recommends doing this in the nextjs docs:
export const config = {
matcher: [
/*
* Match all request paths except for the ones starting with:
* - api (API routes)
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico (favicon file)
*/
'/((?!api|_next/static|_next/image|favicon.ico).*)',
],
}
My issue is trying the example with path params and expecting it to work:
'/((?!foo/:bar))'
turns into
/^(?:\/((?!foo\/:bar)))[\/#\?]?$/i
instead of the expected
/^(?:\/((?!foo(?:\/([^\/#\?]+?)))))[\/#\?]?$/i
@royeden You can’t put named keys inside the regex, regardless of it being a negative lookahead.