path-parser
Advanced tools
Comparing version 0.0.7 to 0.1.0
@@ -11,2 +11,6 @@ 'use strict'; | ||
var defaultOrConstrained = function defaultOrConstrained(match) { | ||
return '(' + (match ? match.replace(/(^<|>$)/g, '') : '[a-zA-Z0-9-_.~]+') + ')'; | ||
}; | ||
var rules = [{ | ||
@@ -16,4 +20,6 @@ // An URL can contain a parameter :paramName | ||
name: 'url-parameter', | ||
pattern: /^:([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})/, | ||
regex: /([a-zA-Z0-9-_.~]+)/ | ||
pattern: /^:([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})(<(.+?)>)?/, | ||
regex: function regex(match) { | ||
return new RegExp(defaultOrConstrained(match[2])); | ||
} | ||
}, { | ||
@@ -26,5 +32,5 @@ // Url parameter (splat) | ||
name: 'url-parameter-matrix', | ||
pattern: /^\;([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})/, | ||
pattern: /^\;([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})(<(.+?)>)?/, | ||
regex: function regex(match) { | ||
return new RegExp(';' + match[1] + '=([a-zA-Z0-9-_.~]+)'); | ||
return new RegExp(';' + match[1] + '=' + defaultOrConstrained(match[2])); | ||
} | ||
@@ -70,3 +76,4 @@ }, { | ||
match: match[0], | ||
val: match.length > 1 ? match.slice(1) : null, | ||
val: match.slice(1, 2), | ||
otherVal: match.slice(2), | ||
regex: rule.regex instanceof Function ? rule.regex(match) : rule.regex | ||
@@ -110,3 +117,3 @@ }); | ||
}).map(function (t) { | ||
return t.val; | ||
return t.val.slice(0, 1); | ||
}) | ||
@@ -190,2 +197,3 @@ // Flatten | ||
var params = arguments[0] === undefined ? {} : arguments[0]; | ||
var ignoreConstraints = arguments[1] === undefined ? false : arguments[1]; | ||
@@ -197,2 +205,13 @@ // Check all params are provided (not search parameters which are optional) | ||
// Check constraints | ||
if (!ignoreConstraints) { | ||
var constraintsPassed = this.tokens.filter(function (t) { | ||
return /^url-parameter/.test(t.type) && !/-splat$/.test(t.type); | ||
}).every(function (t) { | ||
return new RegExp('^' + defaultOrConstrained(t.otherVal[0]) + '$').test(params[t.val]); | ||
}); | ||
if (!constraintsPassed) throw new Error('Some parameters are of invalid format'); | ||
} | ||
var base = this.tokens.filter(function (t) { | ||
@@ -199,0 +218,0 @@ return t.type !== 'query-parameter'; |
@@ -20,2 +20,6 @@ (function (global, factory) { | ||
var defaultOrConstrained = function defaultOrConstrained(match) { | ||
return '(' + (match ? match.replace(/(^<|>$)/g, '') : '[a-zA-Z0-9-_.~]+') + ')'; | ||
}; | ||
var rules = [{ | ||
@@ -25,4 +29,6 @@ // An URL can contain a parameter :paramName | ||
name: 'url-parameter', | ||
pattern: /^:([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})/, | ||
regex: /([a-zA-Z0-9-_.~]+)/ | ||
pattern: /^:([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})(<(.+?)>)?/, | ||
regex: function regex(match) { | ||
return new RegExp(defaultOrConstrained(match[2])); | ||
} | ||
}, { | ||
@@ -35,5 +41,5 @@ // Url parameter (splat) | ||
name: 'url-parameter-matrix', | ||
pattern: /^\;([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})/, | ||
pattern: /^\;([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})(<(.+?)>)?/, | ||
regex: function regex(match) { | ||
return new RegExp(';' + match[1] + '=([a-zA-Z0-9-_.~]+)'); | ||
return new RegExp(';' + match[1] + '=' + defaultOrConstrained(match[2])); | ||
} | ||
@@ -79,3 +85,4 @@ }, { | ||
match: match[0], | ||
val: match.length > 1 ? match.slice(1) : null, | ||
val: match.slice(1, 2), | ||
otherVal: match.slice(2), | ||
regex: rule.regex instanceof Function ? rule.regex(match) : rule.regex | ||
@@ -119,3 +126,3 @@ }); | ||
}).map(function (t) { | ||
return t.val; | ||
return t.val.slice(0, 1); | ||
}) | ||
@@ -199,2 +206,3 @@ // Flatten | ||
var params = arguments[0] === undefined ? {} : arguments[0]; | ||
var ignoreConstraints = arguments[1] === undefined ? false : arguments[1]; | ||
@@ -206,2 +214,13 @@ // Check all params are provided (not search parameters which are optional) | ||
// Check constraints | ||
if (!ignoreConstraints) { | ||
var constraintsPassed = this.tokens.filter(function (t) { | ||
return /^url-parameter/.test(t.type) && !/-splat$/.test(t.type); | ||
}).every(function (t) { | ||
return new RegExp('^' + defaultOrConstrained(t.otherVal[0]) + '$').test(params[t.val]); | ||
}); | ||
if (!constraintsPassed) throw new Error('Some parameters are of invalid format'); | ||
} | ||
var base = this.tokens.filter(function (t) { | ||
@@ -208,0 +227,0 @@ return t.type !== 'query-parameter'; |
@@ -0,1 +1,5 @@ | ||
let defaultOrConstrained = (match) => { | ||
return '(' + (match ? match.replace(/(^<|>$)/g, '') : '[a-zA-Z0-9-_.~]+') + ')' | ||
} | ||
const rules = [ | ||
@@ -6,4 +10,4 @@ { | ||
name: 'url-parameter', | ||
pattern: /^:([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})/, | ||
regex: /([a-zA-Z0-9-_.~]+)/ | ||
pattern: /^:([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})(<(.+?)>)?/, | ||
regex: match => new RegExp(defaultOrConstrained(match[2])) | ||
}, | ||
@@ -18,4 +22,4 @@ { | ||
name: 'url-parameter-matrix', | ||
pattern: /^\;([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})/, | ||
regex: match => new RegExp(';' + match[1] + '=([a-zA-Z0-9-_.~]+)') | ||
pattern: /^\;([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})(<(.+?)>)?/, | ||
regex: match => new RegExp(';' + match[1] + '=' + defaultOrConstrained(match[2])) | ||
}, | ||
@@ -57,6 +61,7 @@ { | ||
tokens.push({ | ||
type: rule.name, | ||
match: match[0], | ||
val: match.length > 1 ? match.slice(1) : null, | ||
regex: rule.regex instanceof Function ? rule.regex(match) : rule.regex | ||
type: rule.name, | ||
match: match[0], | ||
val: match.slice(1, 2), | ||
otherVal: match.slice(2), | ||
regex: rule.regex instanceof Function ? rule.regex(match) : rule.regex | ||
}) | ||
@@ -88,3 +93,3 @@ | ||
.filter(t => /^url-parameter/.test(t.type)) | ||
.map(t => t.val) | ||
.map(t => t.val.slice(0, 1)) | ||
// Flatten | ||
@@ -149,6 +154,15 @@ .reduce((r, v) => r.concat(v)) | ||
build(params = {}) { | ||
build(params = {}, ignoreConstraints = false) { | ||
// Check all params are provided (not search parameters which are optional) | ||
if (!this.params.every(p => params[p] !== undefined)) throw new Error('Missing parameters') | ||
// Check constraints | ||
if (!ignoreConstraints) { | ||
let constraintsPassed = this.tokens | ||
.filter(t => /^url-parameter/.test(t.type) && !/-splat$/.test(t.type)) | ||
.every(t => new RegExp('^' + defaultOrConstrained(t.otherVal[0]) + '$').test(params[t.val])) | ||
if (!constraintsPassed) throw new Error('Some parameters are of invalid format'); | ||
} | ||
let base = this.tokens | ||
@@ -155,0 +169,0 @@ .filter(t => t.type !== 'query-parameter') |
{ | ||
"name": "path-parser", | ||
"version": "0.0.7", | ||
"description": "A small utility to parse paths", | ||
"version": "0.1.0", | ||
"description": "A small utility to parse, match and generate paths", | ||
"main": "dist/commonjs/path-parser.js", | ||
@@ -6,0 +6,0 @@ "scripts": { |
@@ -32,5 +32,24 @@ [![npm version](https://badge.fury.io/js/path-parser.svg)](http://badge.fury.io/js/path-parser) | ||
- `:param`: for URL parameters | ||
- `;param`: for matrix parameters | ||
- `*splat`: for parameters spanning over multiple segments. Handle with care | ||
- `?param1¶m2` or `?:param1&:param2`: for query parameters. Colons `:` are optional | ||
## Parameter constraints | ||
For URL parameters and matrix parameters, you can add a constraint in the form of a regular expression. | ||
Note that back slashes have to be escaped. | ||
- `:param<\\d+>` will match numbers only for parameter `param` | ||
- `;id<[a-fA-F0-9]{8}` will match 8 characters hexadecimal strings for parameter `id` | ||
Constraints are also applied when building paths, unless specified otherwise (set second argument of `build` to true). | ||
```javascript | ||
// Path.build(params, ignore) | ||
var Path = new Path('/users/profile/:id<\d+>'); | ||
path.build({id: 'not-a-number'}); // => Will throw an error | ||
path.build({id: 'not-a-number'}, true); // => '/users/profile/not-a-number' | ||
``` | ||
## Related modules | ||
@@ -37,0 +56,0 @@ |
@@ -22,3 +22,4 @@ var babel = require('babel'); | ||
], function (err) { | ||
if (err) console.log(err); | ||
process.exit(err ? 1 : 0); | ||
}) |
@@ -104,2 +104,26 @@ 'use strict'; | ||
}); | ||
it('should match and build paths with constrained parameters', function () { | ||
var path = new Path('/users/:id<\\d+>'); | ||
// Build path | ||
path.build({id: 99}).should.equal('/users/99'); | ||
// Match path | ||
path.match('/users/11').should.eql({id: '11'}); | ||
should.not.exist(path.match('/users/thomas')); | ||
path = new Path('/users/;id<[A-F0-9]{6}>'); | ||
// Build path | ||
path.build({id: 'A76FE4'}).should.equal('/users/;id=A76FE4'); | ||
// Error because of incorrect parameter format | ||
(function () { | ||
path.build({id: 'incorrect-param'}); | ||
}).should.throw(); | ||
// Force | ||
path.build({id: 'fake'}, true).should.equal('/users/;id=fake'); | ||
// Match path | ||
path.match('/users/;id=A76FE4').should.eql({id: 'A76FE4'}); | ||
should.not.exist(path.match('/users;id=Z12345')); | ||
}); | ||
}); |
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
35308
716
58