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", diff --git a/src/index.spec.ts b/src/index.spec.ts index 512fe1d..b0a65b5 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, @@ -2594,6 +2595,95 @@ 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"]] + ], + [] + ], + [ + /\/(.+)\/(?.+)\/(.+)/, + 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"] + ] + ], + [] + ] + ); +} + /** * Dynamically generate the entire test suite. */ diff --git a/src/index.ts b/src/index.ts index 95c2c7a..56b7d53 100644 --- a/src/index.ts +++ b/src/index.ts @@ -453,19 +453,20 @@ 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); - - if (groups) { - for (let i = 0; i < groups.length; i++) { - keys.push({ - name: i, - 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: "" + }); + execResult = groupsRegex.exec(path.source); } return path;