UNPKG

rfc6570

Version:

RFC 6570 compliant uri template parser, builder and router

353 lines (281 loc) 11 kB
!function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.rfc6570=e():"undefined"!=typeof global?global.rfc6570=e():"undefined"!=typeof self&&(self.rfc6570=e())}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ /* jshint node:true */ var UriTemplate = require('./UriTemplate'); function Router() { var routes = []; this.add = function (template, handler) { routes.push({ template: new UriTemplate(template), handler: handler }); // }; //add this.handle = function (url) { return routes.some(function (route) { var data = route.template.parse(url); return data && route.handler(data) !== false; }); }; //exec } //Router module.exports = Router; },{"./UriTemplate":2}],2:[function(require,module,exports){ /* jshint node:true */ module.exports = UriTemplate; var operatorOptions = { "": { "prefix": "", "seperator": ",", "assignment": false, "assignEmpty": false, "encode": percentEncode }, "+": { "prefix": "", "seperator": ",", "assignment": false, "assignEmpty": false, "encode": encodeURI }, "#": { "prefix": "#", "seperator": ",", "assignment": false, "assignEmpty": false, "encode": encodeURI }, ".": { "prefix": ".", "seperator": ".", "assignment": false, "assignEmpty": false, "encode": percentEncode }, "/": { "prefix": "/", "seperator": "/", "assignment": false, "encode": encodeURIComponent }, ";": { "prefix": ";", "seperator": ";", "assignment": true, "assignEmpty": false, "encode": encodeURIComponent }, "?": { "prefix": "?", "seperator": "&", "assignment": true, "assignEmpty": true, "encode": encodeURIComponent }, "&": { "prefix": "&", "seperator": "&", "assignment": true, "assignEmpty": true, "encode": encodeURIComponent } }; //operatorOptions function percentEncode(value) { /* http://tools.ietf.org/html/rfc3986#section-2.3 */ var unreserved = "-._~"; if (isUndefined(value)) return ''; value = value.toString(); return Array.prototype.map.call(value, function (ch) { var charCode = ch.charCodeAt(0); if (charCode >= 0x30 && charCode <= 0x39) return ch; if (charCode >= 0x41 && charCode <= 0x5a) return ch; if (charCode >= 0x61 && charCode <= 0x7a) return ch; if (~unreserved.indexOf(ch)) return ch; return '%' + charCode.toString(16).toUpperCase(); }).join(''); } //percentEncode function isDefined(value) { return !isUndefined(value); } //isDefined function isUndefined(value) { /* http://tools.ietf.org/html/rfc6570#section-2.3 */ if (value === null) return true; if (value === undefined) return true; if (Array.isArray(value)) { if (value.length === 0) return true; } return false; } //isUndefined function UriTemplate(template) { /* http://tools.ietf.org/html/rfc6570#section-2.2 expression = "{" [ operator ] variable-list "}" operator = op-level2 / op-level3 / op-reserve op-level2 = "+" / "#" op-level3 = "." / "/" / ";" / "?" / "&" op-reserve = "=" / "," / "!" / "@" / "|" */ var reTemplate = /\{([\+#\.\/;\?&=\,!@\|]?)([A-Za-z0-9_\,\.\:\*]+?)\}/g; var reVariable = /^([\$_a-z][\$_a-z0-9]*)((?:\:[1-9][0-9]?[0-9]?[0-9]?)?)(\*?)$/i; var match; var pieces = []; var glues = []; var offset = 0; var pieceCount = 0; while ( !! (match = reTemplate.exec(template))) { glues.push(template.substring(offset, match.index)); /* The operator characters equals ("="), comma (","), exclamation ("!"), at sign ("@"), and pipe ("|") are reserved for future extensions. */ if (match[1] && ~'=,!@|'.indexOf(match[1])) { throw "operator '" + match[1] + "' is reserved for future extensions"; } offset = match.index; pieces.push({ operator: match[1], variables: match[2].split(',').map(variableMapper) }); offset += match[0].length; pieceCount++; } function variableMapper(variable) { var match = reVariable.exec(variable); return { name: match[1], maxLength: match[2] && parseInt(match[2].substring(1), 10), composite: !! match[3] }; } glues.push(template.substring(offset)); this.parse = function (str) { var data = {}; var offset = 0; var offsets = []; if (!glues.every(function (glue, glueIndex) { var index; if (glueIndex > 0 && glue === '') index = str.length; else index = str.indexOf(glue, offset); offset = index; offsets.push(offset); offset += glue.length; return~ index; })) return false; if (!pieces.every(function (piece, pieceIndex) { var options = operatorOptions[piece.operator]; var value, values; var offsetBegin = offsets[pieceIndex] + glues[pieceIndex].length; var offsetEnd = offsets[pieceIndex + 1]; value = str.substring(offsetBegin, offsetEnd); if (value.length === 0) return true; if (value.substring(0, options.prefix.length) !== options.prefix) return false; value = value.substring(options.prefix.length); values = value.split(options.seperator); if (!piece.variables.every(function (variable, variableIndex) { var value = values[variableIndex]; var name; if (value === undefined) return true; name = variable.name; if (options.assignment) { if (value.substring(0, name.length) !== name) return false; value = value.substring(name.length); if (value.length === 0 && options.assignEmpty) return false; if (value.length > 0) { if (value[0] !== '=') return false; value = value.substring(1); } } value = decodeURIComponent(value); data[name] = value; return true; })) return false; return true; })) return false; return data; }; //parse this.stringify = function (data) { var str = ''; data = data || {}; str += glues[0]; if (!pieces.every(function (piece, pieceIndex) { var options = operatorOptions[piece.operator]; var parts; parts = piece.variables.map(function (variable) { var value = data[variable.name]; if (!Array.isArray(value)) value = [value]; value = value.filter(isDefined); if (isUndefined(value)) return null; if (variable.composite) { value = value.map(function (value) { if (typeof value === 'object') { value = Object.keys(value).map(function (key) { var keyValue = value[key]; if (variable.maxLength) keyValue = keyValue.substring(0, variable.maxLength); keyValue = options.encode(keyValue); if (keyValue) keyValue = key + '=' + keyValue; else { keyValue = key; if (options.assignEmpty) keyValue += '='; } return keyValue; }).join(options.seperator); } else { if (variable.maxLength) value = value.substring(0, variable.maxLength); value = options.encode(value); if (options.assignment) { if (value) value = variable.name + '=' + value; else { value = variable.name; if (options.assignEmpty) value += '='; } } } return value; }); value = value.join(options.seperator); } else { value = value.map(function (value) { if (typeof value === 'object') { return Object.keys(value).map(function (key) { var keyValue = value[key]; if (variable.maxLength) keyValue = keyValue.substring(0, variable.maxLength); return key + ',' + options.encode(keyValue); }).join(','); } else { if (variable.maxLength) value = value.substring(0, variable.maxLength); return options.encode(value); } }); value = value.join(','); if (options.assignment) { if (value) value = variable.name + '=' + value; else { value = variable.name; if (options.assignEmpty) value += '='; } } } return value; }); parts = parts.filter(isDefined); if (isDefined(parts)) { str += options.prefix; str += parts.join(options.seperator); } str += glues[pieceIndex + 1]; return true; })) return false; return str; }; //stringify } //UriTemplate },{}],3:[function(require,module,exports){ /* jshint node:true */ module.exports = { Router: require('./Router'), UriTemplate: require('./UriTemplate') }; },{"./Router":1,"./UriTemplate":2}]},{},[3]) (3) }); ;