The Wayback Machine - https://web.archive.org/web/20201207163209/https://github.com/pillarjs/path-to-regexp/pull/225
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add named capturing groups to regexpToRegexp method #225

Merged
merged 6 commits into from Aug 10, 2020

Conversation

@DamianKu
Copy link
Contributor

@DamianKu DamianKu commented Jun 28, 2020

I was looking into fixing issues raised on express repository #4277.

I modified regular expression in regexpToRegexp to match not only ( but also (?<*> probably regexp could be better :).

No change with normal regexp matching, router.get(/\/regex\/(.+)/) -> localhost/regex/testData will result in {"0":"testData"}.

With named capturing groups, router.get(/\/regex2\/(?<groupname>.+)/) -> localhost/regex2/testData will result in {"groupname":"testData"}.
Mixed matched with named capturing groups, router.get(/\/(.+)\/(?<groupname>.+)\/(.+)/) -> localhost/testRegex/testData/extraStuff" will result in {"0":"testRegex","2":"extraStuff","groupname":"testData"}.

All tests are passing but I didn't add new tests to cover this functionality yet.
Would be great to get some feedback from you guys if I'm even looking in good place or is it worth working on it.

@blakeembrey
Copy link
Member

@blakeembrey blakeembrey commented Jul 7, 2020

This looks really great to me, thanks! From my understanding this will work in all current projects because the named group doesn't remove it from the array of RegExp results (e.g. this code depends on the position of keys in the result:

const key = keys[i - 1];
). If you want to add a couple of tests around it we should be good to merge this.

For getting this feature into the current version of Express, you'll probably need to make this PR against an older branch here: https://github.com/pillarjs/path-to-regexp/blob/0.1.x/index.js

However, I believe this it can land in the next Express.js release with the current implementation.

@@ -453,13 +453,17 @@ export type Token = string | Key;
function regexpToRegexp(path: RegExp, keys?: Key[]): RegExp {
if (!keys) return path;

// Use a negative lookahead to match only capturing groups.
const groups = path.source.match(/\((?!\?)/g);
const groups = path.source.match(/\((\?<.*?>)?(?!\?)/g);

This comment has been minimized.

@blakeembrey

blakeembrey Jul 7, 2020
Member
Suggested change
const groups = path.source.match(/\((\?<.*?>)?(?!\?)/g);
const groups = path.source.match(/\((?:\?<(.*?)>)?(?!\?)/g);

Something like this will resolve the comment you have below.

This comment has been minimized.

@DamianKu

DamianKu Jul 7, 2020
Author Contributor

Yeah, non-capturing groups, I tried that. Had no luck so I'm guessing, I made some mistake :)

Will try this :)

This comment has been minimized.

@DamianKu

DamianKu Jul 8, 2020
Author Contributor

Something like this will resolve the comment you have below.

That didn't work

$ curl http://localhost:1337/testRegex/testData/extraStuff -w "\n"
{"0":"testRegex","2":"extraStuff","(?<groupname>":"testData"}

This comment has been minimized.

@blakeembrey

blakeembrey Jul 8, 2020
Member

Oh yeah, that makes sense. It's happening with .match which is only getting the matches and not the groups. We probably need to use regexp.exec in a loop instead.

There's also https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/matchAll but it's not supported on earlier node.js versions or browsers.

This comment has been minimized.

@DamianKu

DamianKu Jul 11, 2020
Author Contributor

Using exec worked :)

Looping through exec results doesn't look nice tho.
Any idea how to make it nicer?

@DamianKu
Copy link
Contributor Author

@DamianKu DamianKu commented Jul 8, 2020

Test is failing on node v8 as Named capture groups are behind '--harmony' runtime flag.

image

@blakeembrey
Copy link
Member

@blakeembrey blakeembrey commented Jul 8, 2020

@DamianKu You'll probably need to put the tests behind a version flag by checking the node.js version in the test suite.

Use exec instead of match.
@DamianKu
Copy link
Contributor Author

@DamianKu DamianKu commented Jul 11, 2020

@DamianKu You'll probably need to put the tests behind a version flag by checking the node.js version in the test suite.

@blakeembrey
How I would go about doing that?
Do you have any example in other your projects that I could investigate? :)

@blakeembrey
Copy link
Member

@blakeembrey blakeembrey commented Jul 14, 2020

How I would go about doing that?

You can read the node.js version here: https://nodejs.org/api/process.html#process_process_version. And use something like https://www.npmjs.com/package/semver to compare whether you want to run it. Put it within an if condition to define the test.

Here's an example (albeit using TypeScript): https://github.com/TypeStrong/ts-node/blob/866bce6a175ec124fe62f269b22e91c92b40f875/src/index.spec.ts#L137

@DamianKu
Copy link
Contributor Author

@DamianKu DamianKu commented Jul 14, 2020

@DamianKu
Copy link
Contributor Author

@DamianKu DamianKu commented Jul 18, 2020

I added the semver check after the initialization of TEST variable.

If you prefer I can do ternary in TEST like so:

const TESTS: Test[] = [
    ...,

    ...(gte(process.version, "10.0.0")
    ? [
        [...test...],
        [...test...]
      ]
    : ([] as any)),
    
    ...,
];
@mastermatt mastermatt mentioned this pull request Jul 18, 2020
modifier: "",
pattern: ""
});
index++;

This comment has been minimized.

@blakeembrey

blakeembrey Jul 20, 2020
Member

It would probably be good to stay consistent with the behavior in string tokens. In that method, we're only incrementing the counter each non-named group:

name: name || key++,
.

That would mean you probably want execResult[1] || index++. We should add a mixed test of named and unnamed groups to make sure it doesn't break.

This comment has been minimized.

@DamianKu

DamianKu Jul 25, 2020
Author Contributor

OK will do that.

Does it mean that this /\/(.+)\/(?<groupname>.+)\/(.+)/ called with /testRegex/testData/extraStuff should result in {"0":"testRegex","1":"extraStuff","groupname":"testData"} ?

…ith non named regexp matching
@blakeembrey blakeembrey merged commit feddb3d into pillarjs:master Aug 10, 2020
2 checks passed
2 checks passed
continuous-integration/travis-ci/pr The Travis CI build passed
Details
coverage/coveralls First build on master at 100.0%
Details
@blakeembrey
Copy link
Member

@blakeembrey blakeembrey commented Aug 10, 2020

Thanks @DamianKu! This looks great.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

2 participants
You can’t perform that action at this time.