diff --git a/dist/commonjs/path-parser.js b/dist/commonjs/path-parser.js index 1c5fb69..eeba932 100644 --- a/dist/commonjs/path-parser.js +++ b/dist/commonjs/path-parser.js @@ -19,6 +19,12 @@ var rules = [{ name: 'url-parameter-splat', pattern: /^\*([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})/, regex: /([^\?]*)/ +}, { + name: 'url-parameter-matrix', + pattern: /^\;([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})/, + regex: function regex(match) { + return new RegExp(';' + match[1] + '=([a-zA-Z0-9-_.~]+)'); + } }, { // Query parameter: ?param1¶m2 // ?:param1&:param2 @@ -34,7 +40,7 @@ var rules = [{ }, { // Sub delimiters name: 'sub-delimiter', - pattern: /^(\!|\&|\-|_|\.)/, + pattern: /^(\!|\&|\-|_|\.|;)/, regex: function regex(match) { return new RegExp(match[0]); } @@ -85,7 +91,10 @@ var Path = (function () { return /^url-parameter/.test(t.type); }).length > 0; this.hasSpatParam = this.tokens.filter(function (t) { - return /splat/.test(t.type); + return /splat$/.test(t.type); + }).length > 0; + this.hasMatrixParams = this.tokens.filter(function (t) { + return /matrix$/.test(t.type); }).length > 0; this.hasQueryParams = this.tokens.filter(function (t) { return t.type === 'query-parameter'; @@ -182,6 +191,7 @@ var Path = (function () { var base = this.tokens.filter(function (t) { return t.type !== 'query-parameter'; }).map(function (t) { + if (t.type === 'url-parameter-matrix') return ';' + t.val[0] + '=' + params[t.val[0]]; return /^url-parameter/.test(t.type) ? params[t.val[0]] : t.match; }).join(''); diff --git a/dist/umd/path-parser.js b/dist/umd/path-parser.js index e89c9e9..f8fb834 100644 --- a/dist/umd/path-parser.js +++ b/dist/umd/path-parser.js @@ -28,6 +28,12 @@ name: 'url-parameter-splat', pattern: /^\*([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})/, regex: /([^\?]*)/ + }, { + name: 'url-parameter-matrix', + pattern: /^\;([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})/, + regex: function regex(match) { + return new RegExp(';' + match[1] + '=([a-zA-Z0-9-_.~]+)'); + } }, { // Query parameter: ?param1¶m2 // ?:param1&:param2 @@ -43,7 +49,7 @@ }, { // Sub delimiters name: 'sub-delimiter', - pattern: /^(\!|\&|\-|_|\.)/, + pattern: /^(\!|\&|\-|_|\.|;)/, regex: function regex(match) { return new RegExp(match[0]); } @@ -94,7 +100,10 @@ return /^url-parameter/.test(t.type); }).length > 0; this.hasSpatParam = this.tokens.filter(function (t) { - return /splat/.test(t.type); + return /splat$/.test(t.type); + }).length > 0; + this.hasMatrixParams = this.tokens.filter(function (t) { + return /matrix$/.test(t.type); }).length > 0; this.hasQueryParams = this.tokens.filter(function (t) { return t.type === 'query-parameter'; @@ -191,6 +200,7 @@ var base = this.tokens.filter(function (t) { return t.type !== 'query-parameter'; }).map(function (t) { + if (t.type === 'url-parameter-matrix') return ';' + t.val[0] + '=' + params[t.val[0]]; return /^url-parameter/.test(t.type) ? params[t.val[0]] : t.match; }).join(''); diff --git a/modules/Path.js b/modules/Path.js index 74a062b..6c15c1e 100644 --- a/modules/Path.js +++ b/modules/Path.js @@ -12,6 +12,11 @@ const rules = [ pattern: /^\*([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})/, regex: /([^\?]*)/ }, + { + name: 'url-parameter-matrix', + pattern: /^\;([a-zA-Z0-9-_]*[a-zA-Z0-9]{1})/, + regex: match => new RegExp(';' + match[1] + '=([a-zA-Z0-9-_.~]+)') + }, { // Query parameter: ?param1¶m2 // ?:param1&:param2 @@ -28,7 +33,7 @@ const rules = [ { // Sub delimiters name: 'sub-delimiter', - pattern: /^(\!|\&|\-|_|\.)/, + pattern: /^(\!|\&|\-|_|\.|;)/, regex: match => new RegExp(match[0]) }, { @@ -71,7 +76,8 @@ export default class Path { this.tokens = tokenise(path) this.hasUrlParams = this.tokens.filter(t => /^url-parameter/.test(t.type)).length > 0 - this.hasSpatParam = this.tokens.filter(t => /splat/.test(t.type)).length > 0 + this.hasSpatParam = this.tokens.filter(t => /splat$/.test(t.type)).length > 0 + this.hasMatrixParams = this.tokens.filter(t => /matrix$/.test(t.type)).length > 0 this.hasQueryParams = this.tokens.filter(t => t.type === 'query-parameter').length > 0 // Extract named parameters from tokens this.urlParams = !this.hasUrlParams ? [] : this.tokens @@ -142,7 +148,10 @@ export default class Path { let base = this.tokens .filter(t => t.type !== 'query-parameter') - .map(t => /^url-parameter/.test(t.type) ? params[t.val[0]] : t.match) + .map(t => { + if (t.type === 'url-parameter-matrix') return `;${t.val[0]}=${params[t.val[0]]}` + return /^url-parameter/.test(t.type) ? params[t.val[0]] : t.match + }) .join('') let searchPart = this.queryParams diff --git a/test/main.js b/test/main.js index c034fb3..63f638e 100644 --- a/test/main.js +++ b/test/main.js @@ -67,7 +67,7 @@ describe('Path', function () { path.build({ id: '123', id2: '456', id3: '789' }).should.equal('/users/profile/123-456?id3=789') }); - it('should match build paths with splat parameters', function () { + it('should match and build paths with splat parameters', function () { var path = new Path('/users/*splat'); path.hasSpatParam.should.be.true; // Successful match @@ -77,7 +77,7 @@ describe('Path', function () { path.build({ splat: 'profile/123'}).should.equal('/users/profile/123'); }); - it('should match build paths with splat and url parameters', function () { + it('should match and build paths with splat and url parameters', function () { var path = new Path('/users/*splat/view/:id'); path.hasSpatParam.should.be.true; // Successful match @@ -85,11 +85,20 @@ describe('Path', function () { path.match('/users/admin/manage/view/123').should.eql({ splat: 'admin/manage', id: '123' }); }); - it('should match build paths with url, splat and query parameters', function () { + it('should match and build paths with url, splat and query parameters', function () { var path = new Path('/:section/*splat?id'); path.hasSpatParam.should.be.true; // Successful match path.match('/users/profile/view?id=123').should.eql({ section: 'users', splat: 'profile/view', id: '123' }); path.build({section: 'users', splat: 'profile/view', id: '123'}).should.equal('/users/profile/view?id=123'); }) + + it('should match and build paths with matrix parameters', function () { + var path = new Path('/users/;section'); + path.hasMatrixParams.should.be.true; + // Build path + path.build({ section: 'profile'}).should.equal('/users/;section=profile'); + // Successful match + path.match('/users/;section=profile').should.eql({ section: 'profile' }); + }); });