path-parser
Advanced tools
Comparing version 0.4.4 to 0.5.0
@@ -0,1 +1,11 @@ | ||
<a name="0.5.0"></a> | ||
# 0.5.0 (2015-12-08) | ||
### Features | ||
* add support for query parameters with brackets ([658d491](https://github.com/troch/path-parser/commit/658d491)) | ||
<a name="0.4.4"></a> | ||
@@ -2,0 +12,0 @@ ## 0.4.4 (2015-11-24) |
@@ -34,2 +34,8 @@ define(['exports', 'module'], function (exports, module) { | ||
// ?:param1&:param2 | ||
name: 'query-parameter-bracket', | ||
pattern: /^(?:\?|&)(?:\:)?([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})(?:\[\])/ | ||
}, // regex: match => new RegExp('(?=(\?|.*&)' + match[0] + '(?=(\=|&|$)))') | ||
{ | ||
// Query parameter: ?param1¶m2 | ||
// ?:param1&:param2 | ||
name: 'query-parameter', | ||
@@ -55,3 +61,3 @@ pattern: /^(?:\?|&)(?:\:)?([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})/ | ||
name: 'fragment', | ||
pattern: /^([0-9a-zA-Z]+?)/, | ||
pattern: /^([0-9a-zA-Z]+)/, | ||
regex: function regex(match) { | ||
@@ -81,2 +87,3 @@ return new RegExp(match[0]); | ||
}); | ||
// If no rules matched, throw an error (possible malformed path) | ||
@@ -95,5 +102,13 @@ if (!matched) { | ||
var withoutBrackets = function withoutBrackets(param) { | ||
return param.replace(/\[\]$/, ''); | ||
}; | ||
var appendQueryParam = function appendQueryParam(params, param) { | ||
var val = arguments.length <= 2 || arguments[2] === undefined ? '' : arguments[2]; | ||
if (/\[\]$/.test(param)) { | ||
param = withoutBrackets(param); | ||
val = [val]; | ||
} | ||
var existingVal = params[param]; | ||
@@ -109,2 +124,3 @@ | ||
if (!searchPart) return {}; | ||
return searchPart.split('&').map(function (_) { | ||
@@ -160,3 +176,4 @@ return _.split('='); | ||
this.hasQueryParams = this.tokens.filter(function (t) { | ||
return t.type === 'query-parameter'; | ||
return (/^query-parameter/.test(t.type) | ||
); | ||
}).length > 0; | ||
@@ -179,8 +196,16 @@ // Extract named parameters from tokens | ||
return t.val; | ||
}) | ||
// Flatten | ||
.reduce(function (r, v) { | ||
}).reduce(function (r, v) { | ||
return r.concat(v); | ||
}); | ||
this.params = this.urlParams.concat(this.queryParams); | ||
}, []); | ||
this.queryParamsBr = !this.hasQueryParams ? [] : this.tokens.filter(function (t) { | ||
return (/-bracket$/.test(t.type) | ||
); | ||
}).map(function (t) { | ||
return t.val; | ||
}).reduce(function (r, v) { | ||
return r.concat(v); | ||
}, []); | ||
this.params = this.urlParams.concat(this.queryParams).concat(this.queryParamsBr); | ||
// Check if hasQueryParams | ||
@@ -219,2 +244,3 @@ // Regular expressions for url part only (full and partial match) | ||
var match = this._urlMatch(path, new RegExp('^' + source + (this.hasQueryParams ? '\\?.*$' : '$'))); | ||
// If no match, or no query params, no need to go further | ||
@@ -225,3 +251,3 @@ if (!match || !this.hasQueryParams) return match; | ||
var unexpectedQueryParams = Object.keys(queryParams).filter(function (p) { | ||
return _this2.queryParams.indexOf(p) === -1; | ||
return _this2.queryParams.concat(_this2.queryParamsBr).indexOf(p) === -1; | ||
}); | ||
@@ -259,3 +285,3 @@ | ||
Object.keys(queryParams).filter(function (p) { | ||
return _this3.queryParams.indexOf(p) >= 0; | ||
return _this3.queryParams.concat(_this3.queryParamsBr).indexOf(p) >= 0; | ||
}).forEach(function (p) { | ||
@@ -291,5 +317,6 @@ return appendQueryParam(match, p, queryParams[p]); | ||
var base = this.tokens.filter(function (t) { | ||
return t.type !== 'query-parameter'; | ||
return (/^query-parameter/.test(t.type) === false | ||
); | ||
}).map(function (t) { | ||
if (t.type === 'url-parameter-matrix') return ';' + t.val[0] + '=' + params[t.val[0]]; | ||
if (t.type === 'url-parameter-matrix') return ';' + t.val + '=' + params[t.val[0]]; | ||
return (/^url-parameter/.test(t.type) ? params[t.val[0]] : t.match | ||
@@ -301,6 +328,10 @@ ); | ||
var searchPart = this.queryParams.filter(function (p) { | ||
return Object.keys(params).indexOf(p) !== -1; | ||
var queryParams = this.queryParams.concat(this.queryParamsBr.map(function (p) { | ||
return p + '[]'; | ||
})); | ||
var searchPart = queryParams.filter(function (p) { | ||
return Object.keys(params).indexOf(withoutBrackets(p)) !== -1; | ||
}).map(function (p) { | ||
return _serialise(p, params[p]); | ||
return _serialise(p, params[withoutBrackets(p)]); | ||
}).join('&'); | ||
@@ -307,0 +338,0 @@ |
@@ -37,2 +37,8 @@ 'use strict'; | ||
// ?:param1&:param2 | ||
name: 'query-parameter-bracket', | ||
pattern: /^(?:\?|&)(?:\:)?([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})(?:\[\])/ | ||
}, // regex: match => new RegExp('(?=(\?|.*&)' + match[0] + '(?=(\=|&|$)))') | ||
{ | ||
// Query parameter: ?param1¶m2 | ||
// ?:param1&:param2 | ||
name: 'query-parameter', | ||
@@ -58,3 +64,3 @@ pattern: /^(?:\?|&)(?:\:)?([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})/ | ||
name: 'fragment', | ||
pattern: /^([0-9a-zA-Z]+?)/, | ||
pattern: /^([0-9a-zA-Z]+)/, | ||
regex: function regex(match) { | ||
@@ -84,2 +90,3 @@ return new RegExp(match[0]); | ||
}); | ||
// If no rules matched, throw an error (possible malformed path) | ||
@@ -98,5 +105,13 @@ if (!matched) { | ||
var withoutBrackets = function withoutBrackets(param) { | ||
return param.replace(/\[\]$/, ''); | ||
}; | ||
var appendQueryParam = function appendQueryParam(params, param) { | ||
var val = arguments.length <= 2 || arguments[2] === undefined ? '' : arguments[2]; | ||
if (/\[\]$/.test(param)) { | ||
param = withoutBrackets(param); | ||
val = [val]; | ||
} | ||
var existingVal = params[param]; | ||
@@ -112,2 +127,3 @@ | ||
if (!searchPart) return {}; | ||
return searchPart.split('&').map(function (_) { | ||
@@ -163,3 +179,4 @@ return _.split('='); | ||
this.hasQueryParams = this.tokens.filter(function (t) { | ||
return t.type === 'query-parameter'; | ||
return (/^query-parameter/.test(t.type) | ||
); | ||
}).length > 0; | ||
@@ -182,8 +199,16 @@ // Extract named parameters from tokens | ||
return t.val; | ||
}) | ||
// Flatten | ||
.reduce(function (r, v) { | ||
}).reduce(function (r, v) { | ||
return r.concat(v); | ||
}); | ||
this.params = this.urlParams.concat(this.queryParams); | ||
}, []); | ||
this.queryParamsBr = !this.hasQueryParams ? [] : this.tokens.filter(function (t) { | ||
return (/-bracket$/.test(t.type) | ||
); | ||
}).map(function (t) { | ||
return t.val; | ||
}).reduce(function (r, v) { | ||
return r.concat(v); | ||
}, []); | ||
this.params = this.urlParams.concat(this.queryParams).concat(this.queryParamsBr); | ||
// Check if hasQueryParams | ||
@@ -222,2 +247,3 @@ // Regular expressions for url part only (full and partial match) | ||
var match = this._urlMatch(path, new RegExp('^' + source + (this.hasQueryParams ? '\\?.*$' : '$'))); | ||
// If no match, or no query params, no need to go further | ||
@@ -228,3 +254,3 @@ if (!match || !this.hasQueryParams) return match; | ||
var unexpectedQueryParams = Object.keys(queryParams).filter(function (p) { | ||
return _this2.queryParams.indexOf(p) === -1; | ||
return _this2.queryParams.concat(_this2.queryParamsBr).indexOf(p) === -1; | ||
}); | ||
@@ -262,3 +288,3 @@ | ||
Object.keys(queryParams).filter(function (p) { | ||
return _this3.queryParams.indexOf(p) >= 0; | ||
return _this3.queryParams.concat(_this3.queryParamsBr).indexOf(p) >= 0; | ||
}).forEach(function (p) { | ||
@@ -294,5 +320,6 @@ return appendQueryParam(match, p, queryParams[p]); | ||
var base = this.tokens.filter(function (t) { | ||
return t.type !== 'query-parameter'; | ||
return (/^query-parameter/.test(t.type) === false | ||
); | ||
}).map(function (t) { | ||
if (t.type === 'url-parameter-matrix') return ';' + t.val[0] + '=' + params[t.val[0]]; | ||
if (t.type === 'url-parameter-matrix') return ';' + t.val + '=' + params[t.val[0]]; | ||
return (/^url-parameter/.test(t.type) ? params[t.val[0]] : t.match | ||
@@ -304,6 +331,10 @@ ); | ||
var searchPart = this.queryParams.filter(function (p) { | ||
return Object.keys(params).indexOf(p) !== -1; | ||
var queryParams = this.queryParams.concat(this.queryParamsBr.map(function (p) { | ||
return p + '[]'; | ||
})); | ||
var searchPart = queryParams.filter(function (p) { | ||
return Object.keys(params).indexOf(withoutBrackets(p)) !== -1; | ||
}).map(function (p) { | ||
return _serialise(p, params[p]); | ||
return _serialise(p, params[withoutBrackets(p)]); | ||
}).join('&'); | ||
@@ -310,0 +341,0 @@ |
@@ -46,2 +46,8 @@ (function (global, factory) { | ||
// ?:param1&:param2 | ||
name: 'query-parameter-bracket', | ||
pattern: /^(?:\?|&)(?:\:)?([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})(?:\[\])/ | ||
}, // regex: match => new RegExp('(?=(\?|.*&)' + match[0] + '(?=(\=|&|$)))') | ||
{ | ||
// Query parameter: ?param1¶m2 | ||
// ?:param1&:param2 | ||
name: 'query-parameter', | ||
@@ -67,3 +73,3 @@ pattern: /^(?:\?|&)(?:\:)?([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})/ | ||
name: 'fragment', | ||
pattern: /^([0-9a-zA-Z]+?)/, | ||
pattern: /^([0-9a-zA-Z]+)/, | ||
regex: function regex(match) { | ||
@@ -93,2 +99,3 @@ return new RegExp(match[0]); | ||
}); | ||
// If no rules matched, throw an error (possible malformed path) | ||
@@ -107,5 +114,13 @@ if (!matched) { | ||
var withoutBrackets = function withoutBrackets(param) { | ||
return param.replace(/\[\]$/, ''); | ||
}; | ||
var appendQueryParam = function appendQueryParam(params, param) { | ||
var val = arguments.length <= 2 || arguments[2] === undefined ? '' : arguments[2]; | ||
if (/\[\]$/.test(param)) { | ||
param = withoutBrackets(param); | ||
val = [val]; | ||
} | ||
var existingVal = params[param]; | ||
@@ -121,2 +136,3 @@ | ||
if (!searchPart) return {}; | ||
return searchPart.split('&').map(function (_) { | ||
@@ -172,3 +188,4 @@ return _.split('='); | ||
this.hasQueryParams = this.tokens.filter(function (t) { | ||
return t.type === 'query-parameter'; | ||
return (/^query-parameter/.test(t.type) | ||
); | ||
}).length > 0; | ||
@@ -191,8 +208,16 @@ // Extract named parameters from tokens | ||
return t.val; | ||
}) | ||
// Flatten | ||
.reduce(function (r, v) { | ||
}).reduce(function (r, v) { | ||
return r.concat(v); | ||
}); | ||
this.params = this.urlParams.concat(this.queryParams); | ||
}, []); | ||
this.queryParamsBr = !this.hasQueryParams ? [] : this.tokens.filter(function (t) { | ||
return (/-bracket$/.test(t.type) | ||
); | ||
}).map(function (t) { | ||
return t.val; | ||
}).reduce(function (r, v) { | ||
return r.concat(v); | ||
}, []); | ||
this.params = this.urlParams.concat(this.queryParams).concat(this.queryParamsBr); | ||
// Check if hasQueryParams | ||
@@ -231,2 +256,3 @@ // Regular expressions for url part only (full and partial match) | ||
var match = this._urlMatch(path, new RegExp('^' + source + (this.hasQueryParams ? '\\?.*$' : '$'))); | ||
// If no match, or no query params, no need to go further | ||
@@ -237,3 +263,3 @@ if (!match || !this.hasQueryParams) return match; | ||
var unexpectedQueryParams = Object.keys(queryParams).filter(function (p) { | ||
return _this2.queryParams.indexOf(p) === -1; | ||
return _this2.queryParams.concat(_this2.queryParamsBr).indexOf(p) === -1; | ||
}); | ||
@@ -271,3 +297,3 @@ | ||
Object.keys(queryParams).filter(function (p) { | ||
return _this3.queryParams.indexOf(p) >= 0; | ||
return _this3.queryParams.concat(_this3.queryParamsBr).indexOf(p) >= 0; | ||
}).forEach(function (p) { | ||
@@ -303,5 +329,6 @@ return appendQueryParam(match, p, queryParams[p]); | ||
var base = this.tokens.filter(function (t) { | ||
return t.type !== 'query-parameter'; | ||
return (/^query-parameter/.test(t.type) === false | ||
); | ||
}).map(function (t) { | ||
if (t.type === 'url-parameter-matrix') return ';' + t.val[0] + '=' + params[t.val[0]]; | ||
if (t.type === 'url-parameter-matrix') return ';' + t.val + '=' + params[t.val[0]]; | ||
return (/^url-parameter/.test(t.type) ? params[t.val[0]] : t.match | ||
@@ -313,6 +340,10 @@ ); | ||
var searchPart = this.queryParams.filter(function (p) { | ||
return Object.keys(params).indexOf(p) !== -1; | ||
var queryParams = this.queryParams.concat(this.queryParamsBr.map(function (p) { | ||
return p + '[]'; | ||
})); | ||
var searchPart = queryParams.filter(function (p) { | ||
return Object.keys(params).indexOf(withoutBrackets(p)) !== -1; | ||
}).map(function (p) { | ||
return _serialise(p, params[p]); | ||
return _serialise(p, params[withoutBrackets(p)]); | ||
}).join('&'); | ||
@@ -319,0 +350,0 @@ |
@@ -27,2 +27,9 @@ let defaultOrConstrained = (match) => { | ||
// ?:param1&:param2 | ||
name: 'query-parameter-bracket', | ||
pattern: /^(?:\?|&)(?:\:)?([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})(?:\[\])/, | ||
// regex: match => new RegExp('(?=(\?|.*&)' + match[0] + '(?=(\=|&|$)))') | ||
}, | ||
{ | ||
// Query parameter: ?param1¶m2 | ||
// ?:param1&:param2 | ||
name: 'query-parameter', | ||
@@ -47,3 +54,3 @@ pattern: /^(?:\?|&)(?:\:)?([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})/, | ||
name: 'fragment', | ||
pattern: /^([0-9a-zA-Z]+?)/, | ||
pattern: /^([0-9a-zA-Z]+)/, | ||
regex: match => new RegExp(match[0]) | ||
@@ -53,3 +60,3 @@ } | ||
let tokenise = (str, tokens = []) => { | ||
const tokenise = (str, tokens = []) => { | ||
// Look for a matching rule | ||
@@ -72,2 +79,3 @@ let matched = | ||
}) | ||
// If no rules matched, throw an error (possible malformed path) | ||
@@ -79,29 +87,36 @@ if (!matched) { | ||
return tokens | ||
} | ||
}; | ||
let optTrailingSlash = (source, trailingSlash) => { | ||
const optTrailingSlash = (source, trailingSlash) => { | ||
if (!trailingSlash) return source | ||
return source.replace(/\\\/$/, '') + '(?:\\/)?' | ||
} | ||
}; | ||
let appendQueryParam = (params, param, val = '') => { | ||
let existingVal = params[param] | ||
const withoutBrackets = param => param.replace(/\[\]$/, ''); | ||
if (existingVal === undefined) params[param] = val | ||
else params[param] = Array.isArray(existingVal) ? existingVal.concat(val) : [ existingVal, val ] | ||
const appendQueryParam = (params, param, val = '') => { | ||
if (/\[\]$/.test(param)) { | ||
param = withoutBrackets(param); | ||
val = [ val ]; | ||
} | ||
const existingVal = params[param]; | ||
return params | ||
} | ||
if (existingVal === undefined) params[param] = val; | ||
else params[param] = Array.isArray(existingVal) ? existingVal.concat(val) : [ existingVal, val ]; | ||
let parseQueryParams = path => { | ||
return params; | ||
}; | ||
const parseQueryParams = path => { | ||
let searchPart = path.split('?')[1] | ||
if (!searchPart) return {} | ||
return searchPart.split('&') | ||
.map(_ => _.split('=')) | ||
.reduce((obj, m) => appendQueryParam(obj, m[0], m[1] ? decodeURIComponent(m[1]) : m[1]), {}) | ||
} | ||
}; | ||
let toSerialisable = val => val !== undefined && val !== null && val !== '' ? '=' + encodeURIComponent(val) : '' | ||
const toSerialisable = val => val !== undefined && val !== null && val !== '' ? '=' + encodeURIComponent(val) : ''; | ||
let serialise = (key, val) => Array.isArray(val) ? val.map(v => serialise(key, v)).join('&') : key + toSerialisable(val) | ||
const serialise = (key, val) => Array.isArray(val) ? val.map(v => serialise(key, v)).join('&') : key + toSerialisable(val); | ||
@@ -125,3 +140,3 @@ export default class Path { | ||
this.hasMatrixParams = this.tokens.filter(t => /matrix$/.test(t.type)).length > 0 | ||
this.hasQueryParams = this.tokens.filter(t => t.type === 'query-parameter').length > 0 | ||
this.hasQueryParams = this.tokens.filter(t => /^query-parameter/.test(t.type)).length > 0 | ||
// Extract named parameters from tokens | ||
@@ -137,5 +152,10 @@ this.urlParams = !this.hasUrlParams ? [] : this.tokens | ||
.map(t => t.val) | ||
// Flatten | ||
.reduce((r, v) => r.concat(v)) | ||
this.params = this.urlParams.concat(this.queryParams) | ||
.reduce((r, v) => r.concat(v), []); | ||
this.queryParamsBr = !this.hasQueryParams ? [] : this.tokens | ||
.filter(t => /-bracket$/.test(t.type)) | ||
.map(t => t.val) | ||
.reduce((r, v) => r.concat(v), []); | ||
this.params = this.urlParams.concat(this.queryParams).concat(this.queryParamsBr); | ||
// Check if hasQueryParams | ||
@@ -166,2 +186,3 @@ // Regular expressions for url part only (full and partial match) | ||
let match = this._urlMatch(path, new RegExp('^' + source + (this.hasQueryParams ? '\\?.*$' : '$'))) | ||
// If no match, or no query params, no need to go further | ||
@@ -172,3 +193,3 @@ if (!match || !this.hasQueryParams) return match | ||
let unexpectedQueryParams = Object.keys(queryParams) | ||
.filter(p => this.queryParams.indexOf(p) === -1) | ||
.filter(p => this.queryParams.concat(this.queryParamsBr).indexOf(p) === -1 ) | ||
@@ -199,3 +220,3 @@ if (unexpectedQueryParams.length === 0) { | ||
Object.keys(queryParams) | ||
.filter(p => this.queryParams.indexOf(p) >= 0) | ||
.filter(p => this.queryParams.concat(this.queryParamsBr).indexOf(p) >= 0) | ||
.forEach(p => appendQueryParam(match, p, queryParams[p])) | ||
@@ -220,5 +241,5 @@ | ||
let base = this.tokens | ||
.filter(t => t.type !== 'query-parameter') | ||
.filter(t => /^query-parameter/.test(t.type) === false) | ||
.map(t => { | ||
if (t.type === 'url-parameter-matrix') return `;${t.val[0]}=${params[t.val[0]]}` | ||
if (t.type === 'url-parameter-matrix') return `;${t.val}=${params[t.val[0]]}` | ||
return /^url-parameter/.test(t.type) ? params[t.val[0]] : t.match | ||
@@ -230,5 +251,7 @@ }) | ||
let searchPart = this.queryParams | ||
.filter(p => Object.keys(params).indexOf(p) !== -1) | ||
.map(p => serialise(p, params[p])) | ||
const queryParams = this.queryParams.concat(this.queryParamsBr.map(p => p + '[]')); | ||
let searchPart = queryParams | ||
.filter(p => Object.keys(params).indexOf(withoutBrackets(p)) !== -1) | ||
.map(p => serialise(p, params[withoutBrackets(p)])) | ||
.join('&') | ||
@@ -235,0 +258,0 @@ |
{ | ||
"name": "path-parser", | ||
"version": "0.4.4", | ||
"version": "0.5.0", | ||
"description": "A small utility to parse, match and generate paths", | ||
@@ -5,0 +5,0 @@ "main": "dist/commonjs/path-parser.js", |
@@ -44,2 +44,3 @@ [![npm version](https://badge.fury.io/js/path-parser.svg)](http://badge.fury.io/js/path-parser) | ||
- `?param1=a¶m1=b` will result in `{param1: ['a', 'b']}` | ||
- `?param1[]=a` and `?param1[]=a¶m1[]=b` will result respectively in `{param1: ['a']}` and `{param1: ['a', 'b']}` | ||
@@ -46,0 +47,0 @@ ## Parameter constraints |
@@ -56,2 +56,3 @@ 'use strict'; | ||
path.match('/users?limit=15').should.eql({ limit: '15' }); | ||
path.match('/users?limit=15').should.eql({ limit: '15' }); | ||
path.partialMatch('/users?offset&limits=1').should.eql({ offset: '' }); | ||
@@ -74,2 +75,11 @@ path.partialMatch('/users?offset=1&offset=2%202&limits=1').should.eql({ offset: ['1', '2 2'] }); | ||
it('should match and build paths of query parameters with square brackets', function () { | ||
var path = new Path('/users?offset&limit[]'); | ||
path.build({ offset: 31, limit: ['15'] }).should.equal('/users?offset=31&limit[]=15'); | ||
path.build({ offset: 31, limit: ['15', '16'] }).should.equal('/users?offset=31&limit[]=15&limit[]=16'); | ||
path.match('/users?offset=31&limit[]=15').should.eql({ offset: '31', limit: ['15'] }); | ||
path.match('/users?offset=31&limit[]=15&limit[]=16').should.eql({ offset: '31', limit: ['15', '16'] }); | ||
}); | ||
it('should match and build paths with url and query parameters', function () { | ||
@@ -76,0 +86,0 @@ var path = new Path('/users/profile/:id-:id2?:id3'); |
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
73305
1280
79