diff --git a/Readme.md b/Readme.md index f47d95f..fa5e182 100644 --- a/Readme.md +++ b/Readme.md @@ -163,6 +163,13 @@ console.log(result) **Note:** The generated function will throw on any invalid input. It will execute all necessary checks to ensure the generated path is valid. This method only works with strings. +### Working with Tokens + +Path-To-RegExp exposes the two functions used internally that accept an array of tokens. + +* `pathToRegexp.tokensToRegExp(tokens, options)` Transform an array of tokens into a matching regular expression. +* `pathToRegexp.tokensToFunction(tokens)` Transform an array of tokens into a path generator function. + ## Compatibility with Express <= 4.x Path-To-RegExp breaks compatibility with Express <= 4.x in a few ways: diff --git a/index.js b/index.js index 89148b4..ab7546d 100644 --- a/index.js +++ b/index.js @@ -6,6 +6,8 @@ var isarray = require('isarray') module.exports = pathToRegexp module.exports.parse = parse module.exports.compile = compile +module.exports.tokensToFunction = tokensToFunction +module.exports.tokensToRegExp = tokensToRegExp /** * The main path matching regexp utility. @@ -96,12 +98,20 @@ function parse (str) { * @return {Function} */ function compile (str) { - var keys = parse(str) + return tokensToFunction(parse(str)) +} + +/** + * Expose a method for transforming tokens into the path function. + */ +function tokensToFunction (tokens) { + // Compile all the tokens into regexps. + var matches = new Array(tokens.length) // Compile all the patterns before compilation. - for (var i = 0; i < keys.length; i++) { - if (typeof keys[i] === 'object') { - keys[i].regexp = new RegExp('^' + keys[i].pattern + '$') + for (var i = 0; i < tokens.length; i++) { + if (typeof tokens[i] === 'object') { + matches[i] = new RegExp('^' + tokens[i].pattern + '$') } } @@ -110,8 +120,8 @@ function compile (str) { obj = obj || {} - for (var i = 0; i < keys.length; i++) { - var key = keys[i] + for (var i = 0; i < tokens.length; i++) { + var key = tokens[i] if (typeof key === 'string') { path += key @@ -143,7 +153,7 @@ function compile (str) { } for (var j = 0; j < value.length; j++) { - if (!key.regexp.test(value[j])) { + if (!matches[i].test(value[j])) { throw new TypeError('Expected all "' + key.name + '" to match "' + key.pattern + '"') } @@ -153,7 +163,7 @@ function compile (str) { continue } - if (!key.regexp.test(value)) { + if (!matches[i].test(value)) { throw new TypeError('Expected "' + key.name + '" to match "' + key.pattern + '"') } @@ -262,11 +272,35 @@ function arrayToRegexp (path, keys, options) { * @return {RegExp} */ function stringToRegexp (path, keys, options) { + var tokens = parse(path) + var re = tokensToRegExp(tokens, options) + + // Attach keys back to the regexp. + for (var i = 0; i < tokens.length; i++) { + if (typeof tokens[i] !== 'string') { + keys.push(tokens[i]) + } + } + + return attachKeys(re, keys) +} + +/** + * Expose a function for taking tokens and returning a RegExp. + * + * @param {Array} tokens + * @param {Array} keys + * @param {Object} options + * @return {RegExp} + */ +function tokensToRegExp (tokens, options) { + options = options || {} + var strict = options.strict var end = options.end !== false var route = '' - var endsWithSlash = path.charAt(path.length - 1) === '/' - var tokens = parse(path) + var lastToken = tokens[tokens.length - 1] + var endsWithSlash = typeof lastToken === 'string' && /\/$/.test(lastToken) // Iterate over the tokens and create our regexp string. for (var i = 0; i < tokens.length; i++) { @@ -278,9 +312,6 @@ function stringToRegexp (path, keys, options) { var prefix = escapeString(token.prefix) var capture = token.pattern - // Push non-string tokens into the keys array. - keys.push(token) - if (token.repeat) { capture += '(?:' + prefix + capture + ')*' } @@ -315,7 +346,7 @@ function stringToRegexp (path, keys, options) { route += strict && endsWithSlash ? '' : '(?=\\/|$)' } - return attachKeys(new RegExp('^' + route, flags(options)), keys) + return new RegExp('^' + route, flags(options)) } /** diff --git a/test.js b/test.js index ef5b23e..691f8a6 100644 --- a/test.js +++ b/test.js @@ -1647,6 +1647,22 @@ describe('path-to-regexp', function () { }) }) + describe('tokens', function () { + var tokens = pathToRegexp.parse(TEST_PATH) + + it('should expose method to compile tokens to regexp', function () { + var re = pathToRegexp.tokensToRegExp(tokens) + + expect(exec(re, '/user/123')).to.deep.equal(['/user/123', '123']) + }) + + it('should expose method to compile tokens to a path function', function () { + var fn = pathToRegexp.tokensToFunction(tokens) + + expect(fn({ id: 123 })).to.equal('/user/123') + }) + }) + describe('rules', function () { TESTS.forEach(function (test) { var path = test[0]