diff --git a/src/index.spec.ts b/src/index.spec.ts index 7973d9e..d18e7fe 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -1043,35 +1043,6 @@ const MATCH_TESTS: MatchTestSet[] = [ ], }, - /** - * Arrays of simple paths. - */ - { - path: ["/one", "/two"], - tests: [ - { - input: "/one", - matches: ["/one"], - expected: { path: "/one", index: 0, params: {} }, - }, - { - input: "/two", - matches: ["/two"], - expected: { path: "/two", index: 0, params: {} }, - }, - { - input: "/three", - matches: null, - expected: false, - }, - { - input: "/one/two", - matches: null, - expected: false, - }, - ], - }, - /** * Optional. */ @@ -1961,132 +1932,6 @@ const MATCH_TESTS: MatchTestSet[] = [ ], }, - /** - * Regexps. - */ - { - path: /.*/, - tests: [ - { - input: "/match/anything", - matches: ["/match/anything"], - expected: { path: "/match/anything", index: 0, params: {} }, - }, - ], - }, - { - path: /(.*)/, - tests: [ - { - input: "/match/anything", - matches: ["/match/anything", "/match/anything"], - expected: { - path: "/match/anything", - index: 0, - params: { "0": "/match/anything" }, - }, - }, - ], - }, - { - path: /\/(\d+)/, - tests: [ - { - input: "/abc", - matches: null, - expected: false, - }, - { - input: "/123", - matches: ["/123", "123"], - expected: { path: "/123", index: 0, params: { "0": "123" } }, - }, - ], - }, - - /** - * Mixed inputs. - */ - { - path: ["/one", /\/two/], - tests: [ - { - input: "/one", - matches: ["/one"], - expected: { path: "/one", index: 0, params: {} }, - }, - { - input: "/two", - matches: ["/two"], - expected: { path: "/two", index: 0, params: {} }, - }, - { - input: "/three", - matches: null, - expected: false, - }, - ], - }, - { - path: ["/:test(\\d+)", /(.*)/], - tests: [ - { - input: "/123", - matches: ["/123", "123", undefined], - expected: { path: "/123", index: 0, params: { test: "123" } }, - }, - { - input: "/abc", - matches: ["/abc", undefined, "/abc"], - expected: { path: "/abc", index: 0, params: { "0": "/abc" } }, - }, - ], - }, - - /** - * Correct names and indexes. - */ - { - path: ["/:test", "/route/:test2"], - tests: [ - { - input: "/test", - matches: ["/test", "test", undefined], - expected: { path: "/test", index: 0, params: { test: "test" } }, - }, - { - input: "/route/test", - matches: ["/route/test", undefined, "test"], - expected: { path: "/route/test", index: 0, params: { test2: "test" } }, - }, - ], - }, - { - path: [/^\/([^/]+)$/, /^\/route\/([^/]+)$/], - tests: [ - { - input: "/test", - matches: ["/test", "test", undefined], - expected: { path: "/test", index: 0, params: { 0: "test" } }, - }, - { - input: "/route/test", - matches: ["/route/test", undefined, "test"], - expected: { path: "/route/test", index: 0, params: { 0: "test" } }, - }, - ], - }, - { - path: /(?:.*)/, - tests: [ - { - input: "/anything/you/want", - matches: ["/anything/you/want"], - expected: { path: "/anything/you/want", index: 0, params: {} }, - }, - ], - }, - /** * Escaped characters. */ @@ -2775,82 +2620,6 @@ const MATCH_TESTS: MatchTestSet[] = [ ], }, - /** - * Named capturing groups. - */ - { - path: /\/(?.+)/, - tests: [ - { - input: "/foo", - matches: ["/foo", "foo"], - expected: { path: "/foo", index: 0, params: { groupname: "foo" } }, - }, - ], - }, - { - path: /\/(?.*).(?html|json)/, - tests: [ - { - input: "/route", - matches: null, - expected: false, - }, - { - input: "/route.txt", - matches: null, - expected: false, - }, - { - input: "/route.html", - matches: ["/route.html", "route", "html"], - expected: { - path: "/route.html", - index: 0, - params: { test: "route", format: "html" }, - }, - }, - { - input: "/route.json", - matches: ["/route.json", "route", "json"], - expected: { - path: "/route.json", - index: 0, - params: { test: "route", format: "json" }, - }, - }, - ], - }, - { - path: /\/(.+)\/(?.+)\/(.+)/, - tests: [ - { - input: "/test", - matches: null, - expected: false, - }, - { - input: "/test/testData", - matches: null, - expected: false, - }, - { - input: "/test/testData/extraStuff", - matches: [ - "/test/testData/extraStuff", - "test", - "testData", - "extraStuff", - ], - expected: { - path: "/test/testData/extraStuff", - index: 0, - params: { 0: "test", 1: "extraStuff", groupname: "testData" }, - }, - }, - ], - }, - /** * https://github.com/pillarjs/path-to-regexp/pull/270 */ @@ -2952,23 +2721,8 @@ const MATCH_TESTS: MatchTestSet[] = [ */ describe("path-to-regexp", () => { describe("arguments", () => { - it("should work without different call combinations", () => { - pathToRegexp.pathToRegexp("/test"); - pathToRegexp.pathToRegexp("/test", []); - pathToRegexp.pathToRegexp("/test", undefined, {}); - - pathToRegexp.pathToRegexp(/^\/test/); - pathToRegexp.pathToRegexp(/^\/test/, []); - pathToRegexp.pathToRegexp(/^\/test/, undefined, {}); - - pathToRegexp.pathToRegexp(["/a", "/b"]); - pathToRegexp.pathToRegexp(["/a", "/b"], []); - pathToRegexp.pathToRegexp(["/a", "/b"], undefined, {}); - }); - it("should accept an array of keys as the second argument", () => { - const keys: pathToRegexp.Key[] = []; - const re = pathToRegexp.pathToRegexp("/user/:id", keys, { end: false }); + const re = pathToRegexp.pathToRegexp("/user/:id", { end: false }); const expectedKeys = [ { @@ -2980,7 +2734,7 @@ describe("path-to-regexp", () => { }, ]; - expect(keys).toEqual(expectedKeys); + expect(re.keys).toEqual(expectedKeys); expect(exec(re, "/user/123/show")).toEqual(["/user/123", "123"]); }); @@ -3063,8 +2817,7 @@ describe("path-to-regexp", () => { "should match $input", testOptions, ({ input, matches, expected }) => { - const keys: pathToRegexp.Key[] = []; - const re = pathToRegexp.pathToRegexp(path, keys, options); + const re = pathToRegexp.pathToRegexp(path, options); const match = pathToRegexp.match(path, options); expect(exec(re, input)).toEqual(matches); diff --git a/src/index.ts b/src/index.ts index 757bcce..f4d33d9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -122,23 +122,23 @@ function lexer(str: string) { let i = 0; while (i < chars.length) { - const char = chars[i]; - const type = SIMPLE_TOKENS[char]; + const value = chars[i]; + const type = SIMPLE_TOKENS[value]; if (type) { - tokens.push({ type, index: i++, value: char }); + tokens.push({ type, index: i++, value }); continue; } - if (char === "\\") { + if (value === "\\") { tokens.push({ type: "ESCAPED", index: i++, value: chars[i++] }); continue; } - if (char === ":") { + if (value === ":") { let name = chars[++i]; - if (!ID_START.test(chars[i])) { + if (!ID_START.test(name)) { throw new TypeError(`Missing parameter name at ${i}`); } @@ -150,7 +150,7 @@ function lexer(str: string) { continue; } - if (char === "(") { + if (value === "(") { const pos = i++; let count = 1; let pattern = ""; @@ -353,7 +353,7 @@ function toKey( * Compile a string to a template function for the path. */ export function compile

( - value: string | TokenData, + value: Path, options: CompileOptions = {}, ) { const data = value instanceof TokenData ? value : parse(value, options); @@ -500,23 +500,21 @@ export function match

( str: Path, options: MatchOptions = {}, ): MatchFunction

{ - const keys: Key[] = []; - const re = pathToRegexp(str, keys, options); - return matchRegexp

(re, keys, options); + const re = pathToRegexp(str, options); + return matchRegexp

(re, options); } /** * Create a path match function from `path-to-regexp` output. */ function matchRegexp

( - re: RegExp, - keys: Key[], + re: PathRegExp, options: MatchOptions, ): MatchFunction

{ const { decode = NOOP_VALUE, loose = DEFAULT_DELIMITER } = options; const stringify = toStringify(loose); - const decoders = keys.map((key) => { + const decoders = re.keys.map((key) => { if (key.separator) { const re = new RegExp( `(${key.pattern})(?:${stringify(key.separator)}|$)`, @@ -543,7 +541,7 @@ function matchRegexp

( for (let i = 1; i < m.length; i++) { if (m[i] === undefined) continue; - const key = keys[i - 1]; + const key = re.keys[i - 1]; const decoder = decoders[i - 1]; params[key.name] = decoder(m[i]); } @@ -600,50 +598,6 @@ export interface Key { */ export type Token = string | Key; -/** - * Pull out keys from a regexp. - */ -function regexpToRegexp(path: RegExp, keys: Key[]): RegExp { - if (!keys) return path; - - let index = 0; - for (const execResult of path.source.matchAll(GROUPS_RE)) { - keys.push({ - // Use parenthesized substring match if available, index otherwise. - name: execResult[1] || String(index++), - prefix: "", - suffix: "", - modifier: "", - pattern: "", - }); - } - - return path; -} - -/** - * Transform an array into a regexp. - */ -function arrayToRegexp( - paths: PathItem[], - keys: Key[], - options: PathToRegexpOptions, -): RegExp { - const parts = paths.map((path) => pathToRegexp(path, keys, options).source); - return new RegExp(`(?:${parts.join("|")})`, flags(options)); -} - -/** - * Create a path regexp from string input. - */ -function stringToRegexp( - path: string, - keys: Key[], - options: PathToRegexpOptions, -) { - return tokensToRegexp(parse(path, options), keys, options); -} - /** * Expose a function for taking tokens and returning a RegExp. */ @@ -699,15 +653,12 @@ function keyToRegexp(key: Key, stringify: Encode): string { } } -/** - * Simple input types. - */ -export type PathItem = string | RegExp | TokenData; - /** * Repeated and simple input types. */ -export type Path = PathItem | PathItem[]; +export type Path = string | TokenData; + +export type PathRegExp = RegExp & { keys: Key[] }; /** * Normalize the given path string, returning a regular expression. @@ -716,13 +667,9 @@ export type Path = PathItem | PathItem[]; * placeholder key descriptions. For example, using `/user/:id`, `keys` will * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`. */ -export function pathToRegexp( - path: Path, - keys: Key[] = [], - options: PathToRegexpOptions = {}, -) { - if (path instanceof TokenData) return tokensToRegexp(path, keys, options); - if (path instanceof RegExp) return regexpToRegexp(path, keys); - if (Array.isArray(path)) return arrayToRegexp(path, keys, options); - return stringToRegexp(path, keys, options); +export function pathToRegexp(path: Path, options: PathToRegexpOptions = {}) { + const data = path instanceof TokenData ? path : parse(path, options); + const keys: Key[] = []; + const regexp = tokensToRegexp(data, keys, options); + return Object.assign(regexp, { keys }); }