path-to-regexp icon indicating copy to clipboard operation
path-to-regexp copied to clipboard

how to get named keys with a negative look ahead?

Open daniellizik opened this issue 3 years ago • 11 comments

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 }

daniellizik avatar Apr 21 '21 07:04 daniellizik

Unfortunately, I was never able to make it works as you want. I also have a situation where this would be needed.

DavidHenri008 avatar Aug 03 '21 14:08 DavidHenri008

After some investigation, I found out that this seems to work: /:animal((?!foo)[a-zA-Z0-9]+)/:id([0-9]+) See CodeSandbox

DavidHenri008 avatar Aug 03 '21 15:08 DavidHenri008

@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.

jonchurch avatar Aug 06 '21 19:08 jonchurch

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 avatar Aug 06 '21 19:08 jonchurch

@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 avatar Aug 08 '21 02:08 blakeembrey

@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.

jonchurch avatar Aug 09 '21 13:08 jonchurch

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

aseem-upadhyay avatar Feb 28 '22 11:02 aseem-upadhyay

Bump this. I'm trying to write a regex that excludes a path starting with .well-known.

nvmnghia avatar Sep 30 '22 02:09 nvmnghia

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

luwes avatar May 18 '23 20:05 luwes

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 avatar Dec 26 '23 16:12 royeden

@royeden You can’t put named keys inside the regex, regardless of it being a negative lookahead.

blakeembrey avatar Dec 29 '23 19:12 blakeembrey