From 87daaa754ac2743fee6550e932277fafad21dcd4 Mon Sep 17 00:00:00 2001 From: Damian Kuriata Date: Sun, 28 Jun 2020 17:10:13 +0100 Subject: [PATCH 1/6] Add named capturing groups to regexpToRegexp method --- src/index.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/index.ts b/src/index.ts index 95c2c7a..cbb10a9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -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); if (groups) { for (let i = 0; i < groups.length; i++) { + const name = + groups[i] === "(" + ? i // Use index as name for non named match + : groups[i].slice(3, -1); // Remove '(?<' & '>' from named match. TODO improve regex to match without these characters + keys.push({ - name: i, + name, prefix: "", suffix: "", modifier: "", From ba13aa26f6de35f0d5600b45d2c11db3a3c9f20c Mon Sep 17 00:00:00 2001 From: Damian Kuriata Date: Wed, 8 Jul 2020 20:01:56 +0100 Subject: [PATCH 2/6] Add tests for named capturing groups --- src/index.spec.ts | 49 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/index.spec.ts b/src/index.spec.ts index 512fe1d..a794ea9 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -1833,6 +1833,55 @@ const TESTS: Test[] = [ [] ], + /** + * Named capturing groups + */ + [ + /\/(?.+)/, + undefined, + [ + { + name: "groupname", + prefix: "", + suffix: "", + modifier: "", + pattern: "" + } + ], + [ + ["/", null], + ["/foo", ["/foo", "foo"]] + ], + [] + ], + [ + /\/(?.*).(?html|json)/, + undefined, + [ + { + name: "test", + prefix: "", + suffix: "", + modifier: "", + pattern: "" + }, + { + name: "format", + prefix: "", + suffix: "", + modifier: "", + pattern: "" + } + ], + [ + ["/route", null], + ["/route.txt", null], + ["/route.html", ["/route.html", "route", "html"]], + ["/route.json", ["/route.json", "route", "json"]] + ], + [] + ], + /** * Ignore non-matching groups in regexps. */ From d8d20f9f672d8897d1ed753f4d99d191de96ac0d Mon Sep 17 00:00:00 2001 From: Damian Kuriata Date: Sat, 11 Jul 2020 20:09:18 +0100 Subject: [PATCH 3/6] Update groups regex to match captured group name. Use exec instead of match. --- src/index.ts | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/index.ts b/src/index.ts index cbb10a9..f8e2a5f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -453,23 +453,21 @@ export type Token = string | Key; function regexpToRegexp(path: RegExp, keys?: Key[]): RegExp { if (!keys) return path; - const groups = path.source.match(/\((\?<.*?>)?(?!\?)/g); - - if (groups) { - for (let i = 0; i < groups.length; i++) { - const name = - groups[i] === "(" - ? i // Use index as name for non named match - : groups[i].slice(3, -1); // Remove '(?<' & '>' from named match. TODO improve regex to match without these characters - - keys.push({ - name, - prefix: "", - suffix: "", - modifier: "", - pattern: "" - }); - } + const groupsRegex = /\((?:\?<(.*?)>)?(?!\?)/g; + + let index = 0; + let execResult = groupsRegex.exec(path.source); + while (execResult) { + keys.push({ + // Use parenthesized substring match if available, index otherwise + name: execResult[1] || index, + prefix: "", + suffix: "", + modifier: "", + pattern: "" + }); + index++; + execResult = groupsRegex.exec(path.source); } return path; From c16691446ac32c6967883366935466d78bfe30b6 Mon Sep 17 00:00:00 2001 From: Damian Kuriata Date: Sat, 18 Jul 2020 15:22:47 +0100 Subject: [PATCH 4/6] Add semver & @types/semver to devDependencies. --- package-lock.json | 61 ++++++++++++++++++++++++++++++++++++++++++++--- package.json | 2 ++ 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4ff6f12..5c0567f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -154,6 +154,12 @@ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -1068,6 +1074,15 @@ "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==", "dev": true }, + "@types/semver": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.1.tgz", + "integrity": "sha512-ooD/FJ8EuwlDKOI6D9HWxgIgJjMg2cuziXm/42npDC8y4NjxplBUn9loewZiBNCt44450lHAU0OSb51/UqXeag==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/stack-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", @@ -2807,6 +2822,14 @@ "semver": "^5.5.0", "shebang-command": "^1.2.0", "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } } }, "crypto-browserify": { @@ -6827,6 +6850,12 @@ "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true } } }, @@ -7202,6 +7231,14 @@ "semver": "^5.5.0", "shellwords": "^0.1.1", "which": "^1.3.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } } }, "node-releases": { @@ -7241,6 +7278,12 @@ "requires": { "path-parse": "^1.0.6" } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true } } }, @@ -8969,9 +9012,9 @@ } }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", "dev": true }, "semver-compare": { @@ -10020,6 +10063,12 @@ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, "yargs-parser": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", @@ -10063,6 +10112,12 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true } } }, diff --git a/package.json b/package.json index c537613..56278b8 100644 --- a/package.json +++ b/package.json @@ -72,11 +72,13 @@ "@size-limit/preset-small-lib": "^2.1.6", "@types/jest": "^24.0.22", "@types/node": "^12.12.7", + "@types/semver": "^7.3.1", "husky": "^3.0.9", "jest": "^24.9.0", "lint-staged": "^9.4.2", "prettier": "^1.19.1", "rimraf": "^3.0.0", + "semver": "^7.3.2", "ts-jest": "^24.1.0", "tslint": "^5.20.1", "tslint-config-prettier": "^1.18.0", From 9caa26dafce0d8ccbc6143b782185012f7fc92bb Mon Sep 17 00:00:00 2001 From: Damian Kuriata Date: Sat, 18 Jul 2020 15:27:39 +0100 Subject: [PATCH 5/6] Push named capturing groups tests to test suite only if valid version --- src/index.spec.ts | 103 ++++++++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 49 deletions(-) diff --git a/src/index.spec.ts b/src/index.spec.ts index a794ea9..10d03e5 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -1,5 +1,6 @@ import * as util from "util"; import * as pathToRegexp from "./index"; +import { gte } from "semver"; type Test = [ pathToRegexp.Path, @@ -1833,55 +1834,6 @@ const TESTS: Test[] = [ [] ], - /** - * Named capturing groups - */ - [ - /\/(?.+)/, - undefined, - [ - { - name: "groupname", - prefix: "", - suffix: "", - modifier: "", - pattern: "" - } - ], - [ - ["/", null], - ["/foo", ["/foo", "foo"]] - ], - [] - ], - [ - /\/(?.*).(?html|json)/, - undefined, - [ - { - name: "test", - prefix: "", - suffix: "", - modifier: "", - pattern: "" - }, - { - name: "format", - prefix: "", - suffix: "", - modifier: "", - pattern: "" - } - ], - [ - ["/route", null], - ["/route.txt", null], - ["/route.html", ["/route.html", "route", "html"]], - ["/route.json", ["/route.json", "route", "json"]] - ], - [] - ], - /** * Ignore non-matching groups in regexps. */ @@ -2643,6 +2595,59 @@ const TESTS: Test[] = [ ] ]; +/** + * Named capturing groups (available from Node version 10) + */ +if (gte(process.version, "10.0.0")) { + TESTS.push( + [ + /\/(?.+)/, + undefined, + [ + { + name: "groupname", + prefix: "", + suffix: "", + modifier: "", + pattern: "" + } + ], + [ + ["/", null], + ["/foo", ["/foo", "foo"]] + ], + [] + ], + [ + /\/(?.*).(?html|json)/, + undefined, + [ + { + name: "test", + prefix: "", + suffix: "", + modifier: "", + pattern: "" + }, + { + name: "format", + prefix: "", + suffix: "", + modifier: "", + pattern: "" + } + ], + [ + ["/route", null], + ["/route.txt", null], + ["/route.html", ["/route.html", "route", "html"]], + ["/route.json", ["/route.json", "route", "json"]] + ], + [] + ] + ); +} + /** * Dynamically generate the entire test suite. */ From 5534a3309a777bcf7bca0e6bb2c0a29086a06660 Mon Sep 17 00:00:00 2001 From: Damian Kuriata Date: Sat, 25 Jul 2020 18:18:09 +0100 Subject: [PATCH 6/6] Do not increment index on non capturing groups. Add tests for named with non named regexp matching --- src/index.spec.ts | 36 ++++++++++++++++++++++++++++++++++++ src/index.ts | 3 +-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/index.spec.ts b/src/index.spec.ts index 10d03e5..b0a65b5 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -2644,6 +2644,42 @@ if (gte(process.version, "10.0.0")) { ["/route.json", ["/route.json", "route", "json"]] ], [] + ], + [ + /\/(.+)\/(?.+)\/(.+)/, + undefined, + [ + { + name: 0, + prefix: "", + suffix: "", + modifier: "", + pattern: "" + }, + { + name: "groupname", + prefix: "", + suffix: "", + modifier: "", + pattern: "" + }, + { + name: 1, + prefix: "", + suffix: "", + modifier: "", + pattern: "" + } + ], + [ + ["/test", null], + ["/test/testData", null], + [ + "/test/testData/extraStuff", + ["/test/testData/extraStuff", "test", "testData", "extraStuff"] + ] + ], + [] ] ); } diff --git a/src/index.ts b/src/index.ts index f8e2a5f..56b7d53 100644 --- a/src/index.ts +++ b/src/index.ts @@ -460,13 +460,12 @@ function regexpToRegexp(path: RegExp, keys?: Key[]): RegExp { while (execResult) { keys.push({ // Use parenthesized substring match if available, index otherwise - name: execResult[1] || index, + name: execResult[1] || index++, prefix: "", suffix: "", modifier: "", pattern: "" }); - index++; execResult = groupsRegex.exec(path.source); }