extract-params
Advanced tools
Comparing version 2.1.1 to 3.0.0
@@ -0,1 +1,7 @@ | ||
var assign = require('lodash.assign'); | ||
var isPlainObject = require('lodash.isplainobject'); | ||
var isString = require('lodash.isstring'); | ||
var isFunction = require('lodash.isfunction'); | ||
var isUndefined = require('lodash.isundefined'); | ||
var paramRegex = /:[a-zA-Z]+/g; | ||
@@ -12,23 +18,45 @@ | ||
module.exports = function extractParams(str, pattern, transform) { | ||
if (typeof str !== 'string') { | ||
throw new Error('\'str\' must be a string'); | ||
function normalisePattern(pattern) { | ||
if (isString(pattern)) { | ||
return { pattern: pattern, caseSensitive: true, transform: identity }; | ||
} | ||
if (isPlainObject(pattern)) { | ||
if (isUndefined(pattern.transform)) { | ||
return assign({ caseSensitive: true, transform: identity }, pattern); | ||
} | ||
if (isFunction(pattern.transform)) { | ||
return assign({ caseSensitive: true }, pattern); | ||
} | ||
throw new Error('\'transform\' must be a function'); | ||
return null; | ||
} | ||
if (typeof pattern !== 'string') { | ||
throw new Error('\'pattern\' must be a string'); | ||
throw new Error('\'pattern\' must be a string or an object'); | ||
return null; | ||
} | ||
module.exports = function extractParams(str, pattern) { | ||
var patternObj = normalisePattern(pattern); | ||
if (patternObj === null) { | ||
return null; | ||
} | ||
if (typeof transform === 'undefined') { | ||
transform = identity; | ||
} else if (typeof transform !== 'function') { | ||
throw new Error('\'transform\' must be a function'); | ||
if (!isString(str)) { | ||
throw new Error('\'str\' must be a string'); | ||
return null; | ||
} | ||
var valuesRegex = new RegExp('^' + pattern.split(paramRegex).map(function(patternPart) { | ||
if (!(isString(patternObj.pattern))) { | ||
throw new Error('\'pattern\' value must be a string'); | ||
return null; | ||
} | ||
var regexFlags = patternObj.caseSensitive ? '' : 'i'; | ||
var valuesRegex = new RegExp('^' + patternObj.pattern.split(paramRegex).map(function(patternPart) { | ||
return escapeRegexCharacters(patternPart); | ||
}).join('(.+)') + '$'); | ||
}).join('(.+)') + '$', regexFlags); | ||
@@ -41,6 +69,6 @@ var valuesMatch = str.match(valuesRegex); | ||
var paramsMatch = pattern.match(paramRegex); | ||
var paramsMatch = patternObj.pattern.match(paramRegex); | ||
if (paramsMatch === null) { | ||
return transform({}); | ||
return patternObj.transform({}); | ||
} | ||
@@ -52,3 +80,3 @@ | ||
return transform(valuesMatch.slice(1).reduce(function(result, value, index) { | ||
return patternObj.transform(valuesMatch.slice(1).reduce(function(result, value, index) { | ||
result[params[index]] = value; | ||
@@ -55,0 +83,0 @@ return result; |
@@ -0,5 +1,7 @@ | ||
var isString = require('lodash.isstring'); | ||
var isArray = require('lodash.isarray'); | ||
var extractParams = require('./extractParams'); | ||
module.exports = function extractParamsInFirstMatch(str, patterns) { | ||
if (typeof str !== 'string') { | ||
if (!(isString(str))) { | ||
throw new Error('\'str\' must be a string'); | ||
@@ -9,3 +11,3 @@ return null; | ||
if (typeof patterns !== 'object' || typeof patterns.length === 'undefined') { | ||
if (!(isArray(patterns))) { | ||
throw new Error('\'patterns\' must be an array'); | ||
@@ -18,3 +20,3 @@ return null; | ||
for (var i = 0; i < patternsCount; i++) { | ||
var params = extractParams(str, patterns[i].pattern, patterns[i].transform); | ||
var params = extractParams(str, patterns[i]); | ||
@@ -21,0 +23,0 @@ if (params !== null) { |
{ | ||
"name": "extract-params", | ||
"version": "2.1.1", | ||
"version": "3.0.0", | ||
"description": "Extract parameters from a string based on a pattern", | ||
@@ -10,3 +10,4 @@ "main": "index.js", | ||
"test-dev": "mocha test --watch --reporter min", | ||
"build": "npm run lint && npm test" | ||
"build": "npm run lint && npm test", | ||
"postversion": "git push && git push --tags" | ||
}, | ||
@@ -29,2 +30,10 @@ "repository": { | ||
], | ||
"dependencies": { | ||
"lodash.assign": "^3.2.0", | ||
"lodash.isarray": "^3.0.4", | ||
"lodash.isfunction": "^3.0.6", | ||
"lodash.isplainobject": "^3.2.0", | ||
"lodash.isstring": "^3.0.1", | ||
"lodash.isundefined": "^3.0.1" | ||
}, | ||
"devDependencies": { | ||
@@ -31,0 +40,0 @@ "chai": "^3.4.1", |
135
README.md
<a href="https://codeship.com/projects/119982" target="_blank"> | ||
<img src="https://img.shields.io/codeship/ff47ba10-7c98-0133-b9e7-2e6bcf2dba9a/master.svg" | ||
<img src="https://img.shields.io/codeship/ff47ba10-7c98-0133-b9e7-2e6bcf2dba9a/master.svg?style=flat-square" | ||
alt="Build Status" /> | ||
</a> | ||
<a href="https://npmjs.org/package/extract-params" target="_blank"> | ||
<img src="https://img.shields.io/npm/v/extract-params.svg" | ||
alt="NPM Version" /> | ||
<a href="http://issuestats.com/github/moroshko/extract-params" target="_blank"> | ||
<img src="http://issuestats.com/github/moroshko/extract-params/badge/pr?style=flat-square" | ||
alt="Pull Requests stats" /> | ||
</a> | ||
<a href="https://npmjs.org/package/extract-params" target="_blank"> | ||
<img src="https://img.shields.io/npm/dm/extract-params.svg" | ||
<img src="https://img.shields.io/npm/dm/extract-params.svg?style=flat-square" | ||
alt="NPM Downloads" /> | ||
</a> | ||
<a href="https://npmjs.org/package/extract-params" target="_blank"> | ||
<img src="https://img.shields.io/npm/v/extract-params.svg?style=flat-square" | ||
alt="NPM Version" /> | ||
</a> | ||
@@ -32,18 +36,12 @@ # Extract Params | ||
* [`extractParams(str, pattern, [transform])`](#extractParams) | ||
* [`extractParams(str, pattern)`](#extractParams) | ||
* [`extractParamsInFirstMatch(str, patterns)`](#extractParamsInFirstMatch) | ||
<a name="extractParams"></a> | ||
### extractParams(str, pattern, [transform]) | ||
### extractParams(str, pattern) | ||
Tests whether `str` matches the given parameterized `pattern`. If match is successful, it returns a hash of parameters and their values. | ||
Tests whether `str` matches the given parameterized [pattern](#patterns). If match is successful, it returns a hash of parameters and their values. Otherwise, `extractParams` returns `null`. | ||
Otherwise, `extractParams` returns `null`. | ||
An optional `transform` function can be passed to manipulate the extracted params. If `transform` returns `null`, the match fails. `transform` can be used, for example, to lowercase the values in `params`, or to validate them (return `null` if validation fails). | ||
The match is considered successful only if `str` matches the `pattern` at the start and at the end (see examples 2 and 3 below). | ||
`pattern` parameters must have letters only. | ||
#### Example 1 | ||
@@ -102,8 +100,23 @@ | ||
var params = extractParams( | ||
'/users/1234/friends/456/photo', | ||
'/users/:userId/friends/:friendId/photo', | ||
function(params) { | ||
var userId = parseInt(params.userId, 10); | ||
'/USERS/123/Friends/456/photo', | ||
'/users/:userId/friends/:friendId/photo' | ||
); | ||
/* | ||
Returns: | ||
null | ||
return userId >= 1 && userId <= 999 ? params : null; | ||
because the pattern is case sensitive by default | ||
*/ | ||
``` | ||
<a name="case-insensitive-example"></a> | ||
#### Example 5 | ||
```js | ||
var params = extractParams( | ||
'/USERS/123/Friends/456/photo', | ||
{ | ||
pattern: '/users/:userId/friends/:friendId/photo', | ||
caseSensitive: false | ||
} | ||
@@ -114,5 +127,62 @@ ); | ||
Returns: | ||
{ | ||
userId: '123', | ||
friendId: '456' | ||
} | ||
*/ | ||
``` | ||
<a name="lowercase-keys-example"></a> | ||
#### Example 6 | ||
```js | ||
function lowercaseValues(params) { | ||
return Object.keys(params).reduce(function(result, param) { | ||
result[param] = params[param].toLowerCase(); | ||
return result; | ||
}, {}); | ||
} | ||
var params = extractParams( | ||
'/users/Misha/friends/MARK/photo', | ||
{ | ||
pattern: '/users/:user/friends/:friend/photo', | ||
transform: lowercaseValues | ||
} | ||
); | ||
/* | ||
Returns: | ||
{ | ||
user: 'misha', | ||
friend: 'mark' | ||
} | ||
*/ | ||
``` | ||
<a name="regex-validation-example"></a> | ||
#### Example 7 | ||
```js | ||
var companyRegex = /[a-zA-Z]+/; | ||
var employeeRegex = /[a-z\-]+/; | ||
function validator(params) { | ||
return typeof params.company === 'string' && companyRegex.test(params.company) && | ||
typeof params.employee === 'string' && employeeRegex.test(params.employee); | ||
} | ||
var params = extractParams( | ||
'/companies/Yahoo7/employees/david-brown', | ||
{ | ||
pattern: '/companies/:company/employees/:employee', | ||
transform: validator | ||
} | ||
); | ||
/* | ||
Returns: | ||
null | ||
because userId > 999 | ||
because 'Yahoo7' contains a number | ||
*/ | ||
@@ -124,3 +194,3 @@ ``` | ||
Tests whether `str` matches one of the parameterized `patterns`. Every pattern can have an optional `transform` function. If none of the `patterns` match, `extractParamsInFirstMatch` returns `null`. Otherwise, it returns the matching pattern index and its parameters. | ||
Tests whether `str` matches one of the parameterized [patterns](#patterns). If none of the `patterns` match, `extractParamsInFirstMatch` returns `null`. Otherwise, it returns the matching pattern index and its parameters. | ||
@@ -211,2 +281,23 @@ #### Example 1 | ||
<a name="patterns"></a> | ||
## Patterns | ||
The functions in this library operate on a `pattern` type. | ||
### Basic patterns | ||
In its simplest form, pattern is just a string, e.g. `/users`. | ||
Patterns can have parameters, e.g. `/users/:userId/friends/:friendId/photo`. | ||
Parameters must start with a `:`, and can contain letters only. Therefore, `:username`, `:userName`, and `:USERNAME` are valid parameters, but `:user-name`, `:user_name` and `:iphone6` are not. | ||
### Advanced patterns | ||
For more advanced patterns, an object with the following keys can be provided: | ||
* `pattern` - (required) The pattern string. | ||
* `caseSensitive` - (optional) Boolean indicating whether the pattern is considered case sensitive or not. [Example](#case-insensitive-example)<br />Defaults to `true`. | ||
* `transform` - (optional) Function that takes the extracted params, and returns a manipulated version of them. [Example](#lowercase-keys-example)<br />If it returns `null`, the match fails. [Example](#regex-validation-example)<br />Defaults to the identity function. | ||
## Running Tests | ||
@@ -220,2 +311,2 @@ | ||
[MIT](http://moroshko.mit-license.org) | ||
<a href="http://moroshko.mit-license.org" target="_blank">MIT</a> |
@@ -20,4 +20,6 @@ var expect = require('chai').expect; | ||
str: '/elm', | ||
pattern: '/:language', | ||
transform: {}, | ||
pattern: { | ||
pattern: '/:language', | ||
transform: {} | ||
}, | ||
throw: '\'transform\' must be a function' | ||
@@ -50,15 +52,17 @@ }, | ||
{ | ||
should: 'return use the transform function if there is match but the pattern has no parameters', | ||
should: 'use the transform function if there is match but the pattern has no parameters', | ||
str: 'react-is-awesome', | ||
pattern: 'react-is-awesome', | ||
transform: function(params) { | ||
var newParams = { | ||
mood: 'awesome' | ||
}; | ||
pattern: { | ||
pattern: 'react-is-awesome', | ||
transform: function(params) { | ||
var newParams = { | ||
mood: 'awesome' | ||
}; | ||
for (var param in params) { | ||
newParams[param] = params[param]; | ||
for (var param in params) { | ||
newParams[param] = params[param]; | ||
} | ||
return newParams; | ||
} | ||
return newParams; | ||
}, | ||
@@ -96,13 +100,23 @@ result: { | ||
{ | ||
should: 'handle case insensitive patterns', | ||
str: 'My-Name-Is-Misha', | ||
pattern: { pattern: 'my-name-is-:name', caseSensitive: false }, | ||
result: { | ||
name: 'Misha' | ||
} | ||
}, | ||
{ | ||
should: 'transform the extracted params using the transform function', | ||
str: '/users/123/friends/456/photo', | ||
pattern: '/users/:userId/friends/:friendId/photo', | ||
transform: function(params) { | ||
var newParams = {}; | ||
pattern: { | ||
pattern: '/users/:userId/friends/:friendId/photo', | ||
transform: function(params) { | ||
var newParams = {}; | ||
for (var param in params) { | ||
newParams[param] = '**' + params[param] + '**'; | ||
for (var param in params) { | ||
newParams[param] = '**' + params[param] + '**'; | ||
} | ||
return newParams; | ||
} | ||
return newParams; | ||
}, | ||
@@ -117,7 +131,9 @@ result: { | ||
str: '/users/1234/friends/456/photo', | ||
pattern: '/users/:userId/friends/:friendId/photo', | ||
transform: function(params) { | ||
var userId = parseInt(params.userId, 10); | ||
pattern: { | ||
pattern: '/users/:userId/friends/:friendId/photo', | ||
transform: function(params) { | ||
var userId = parseInt(params.userId, 10); | ||
return userId >= 1 && userId <= 999 ? params : null; | ||
return userId >= 1 && userId <= 999 ? params : null; | ||
} | ||
}, | ||
@@ -131,3 +147,3 @@ result: null | ||
it(testCase.should, function() { | ||
var fn = extractParams.bind(null, testCase.str, testCase.pattern, testCase.transform); | ||
var fn = extractParams.bind(null, testCase.str, testCase.pattern); | ||
@@ -134,0 +150,0 @@ if (testCase.throw) { |
@@ -67,2 +67,31 @@ var expect = require('chai').expect; | ||
{ | ||
should: 'return the first match if the string has mixed case when patterns are not case sensitive', | ||
str: '/UsErS/123', | ||
patterns: [ | ||
{ pattern: '/users/:userId/friends/:friendId/photo', caseSensitive: false }, | ||
{ pattern: '/users/:userId/friends/:friendId', caseSensitive: false }, | ||
{ pattern: '/users/:userId/friends', caseSensitive: false }, | ||
{ pattern: '/users/:userId', caseSensitive: false }, | ||
{ pattern: '/users', caseSensitive: false } | ||
], | ||
result: { | ||
patternIndex: 3, | ||
params: { | ||
userId: '123' | ||
} | ||
} | ||
}, | ||
{ | ||
should: 'return null if the string has mixed case given patterns are case sensitive by default', | ||
str: '/UsErS/123', | ||
patterns: [ | ||
{ pattern: '/users/:userId/friends/:friendId/photo' }, | ||
{ pattern: '/users/:userId/friends/:friendId' }, | ||
{ pattern: '/users/:userId/friends' }, | ||
{ pattern: '/users/:userId' }, | ||
{ pattern: '/users' } | ||
], | ||
result: null | ||
}, | ||
{ | ||
should: 'use the transform function to return the first match', | ||
@@ -69,0 +98,0 @@ str: '/users/1234/friends/456', |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
20416
10
351
307
6
+ Addedlodash.assign@^3.2.0
+ Addedlodash.isarray@^3.0.4
+ Addedlodash.isfunction@^3.0.6
+ Addedlodash.isplainobject@^3.2.0
+ Addedlodash.isstring@^3.0.1
+ Addedlodash.isundefined@^3.0.1
+ Addedlodash._baseassign@3.2.0(transitive)
+ Addedlodash._basecopy@3.0.1(transitive)
+ Addedlodash._basefor@3.0.3(transitive)
+ Addedlodash._bindcallback@3.0.1(transitive)
+ Addedlodash._createassigner@3.1.1(transitive)
+ Addedlodash._getnative@3.9.1(transitive)
+ Addedlodash._isiterateecall@3.0.9(transitive)
+ Addedlodash.assign@3.2.0(transitive)
+ Addedlodash.isarguments@3.1.0(transitive)
+ Addedlodash.isarray@3.0.4(transitive)
+ Addedlodash.isfunction@3.0.9(transitive)
+ Addedlodash.isplainobject@3.2.0(transitive)
+ Addedlodash.isstring@3.0.1(transitive)
+ Addedlodash.isundefined@3.0.1(transitive)
+ Addedlodash.keys@3.1.2(transitive)
+ Addedlodash.keysin@3.0.8(transitive)
+ Addedlodash.restparam@3.6.1(transitive)