nodulator
Version:
Complete NodeJS Framework for Restfull APIs
173 lines (149 loc) • 4.84 kB
JavaScript
/*
* Copyright 2015 the original author or authors
* @license MIT, see LICENSE.txt for details
*
* @author Scott Andrews
*/
(function (define) {
'use strict';
var undef;
define(function (require) {
var uriEncoder, operations, prefixRE;
uriEncoder = require('./uriEncoder');
prefixRE = /^([^:]*):([0-9]+)$/;
operations = {
'': { first: '', separator: ',', named: false, empty: '', encoder: uriEncoder.encode },
'+': { first: '', separator: ',', named: false, empty: '', encoder: uriEncoder.encodeURL },
'#': { first: '#', separator: ',', named: false, empty: '', encoder: uriEncoder.encodeURL },
'.': { first: '.', separator: '.', named: false, empty: '', encoder: uriEncoder.encode },
'/': { first: '/', separator: '/', named: false, empty: '', encoder: uriEncoder.encode },
';': { first: ';', separator: ';', named: true, empty: '', encoder: uriEncoder.encode },
'?': { first: '?', separator: '&', named: true, empty: '=', encoder: uriEncoder.encode },
'&': { first: '&', separator: '&', named: true, empty: '=', encoder: uriEncoder.encode },
'=': { reserved: true },
',': { reserved: true },
'!': { reserved: true },
'@': { reserved: true },
'|': { reserved: true }
};
function apply(operation, expression, params) {
/*jshint maxcomplexity:11 */
return expression.split(',').reduce(function (result, variable) {
var opts, value;
opts = {};
if (variable.slice(-1) === '*') {
variable = variable.slice(0, -1);
opts.explode = true;
}
if (prefixRE.test(variable)) {
var prefix = prefixRE.exec(variable);
variable = prefix[1];
opts.maxLength = parseInt(prefix[2]);
}
variable = uriEncoder.decode(variable);
value = params[variable];
if (value === undef || value === null) {
return result;
}
if (Array.isArray(value)) {
result += value.reduce(function (result, value) {
if (result.length) {
result += opts.explode ? operation.separator : ',';
if (operation.named && opts.explode) {
result += operation.encoder(variable);
result += value.length ? '=' : operation.empty;
}
}
else {
result += operation.first;
if (operation.named) {
result += operation.encoder(variable);
result += value.length ? '=' : operation.empty;
}
}
result += operation.encoder(value);
return result;
}, '');
}
else if (typeof value === 'object') {
result += Object.keys(value).reduce(function (result, name) {
if (result.length) {
result += opts.explode ? operation.separator : ',';
}
else {
result += operation.first;
if (operation.named && !opts.explode) {
result += operation.encoder(variable);
result += value[name].length ? '=' : operation.empty;
}
}
result += operation.encoder(name);
result += opts.explode ? '=' : ',';
result += operation.encoder(value[name]);
return result;
}, '');
}
else {
value = String(value);
if (opts.maxLength) {
value = value.slice(0, opts.maxLength);
}
result += result.length ? operation.separator : operation.first;
if (operation.named) {
result += operation.encoder(variable);
result += value.length ? '=' : operation.empty;
}
result += operation.encoder(value);
}
return result;
}, '');
}
function expandExpression(expression, params) {
var operation;
operation = operations[expression.slice(0,1)];
if (operation) {
expression = expression.slice(1);
}
else {
operation = operations[''];
}
if (operation.reserved) {
throw new Error('Reserved expression operations are not supported');
}
return apply(operation, expression, params);
}
function expandTemplate(template, params) {
var start, end, uri;
uri = '';
end = 0;
while (true) {
start = template.indexOf('{', end);
if (start === -1) {
// no more expressions
uri += template.slice(end);
break;
}
uri += template.slice(end, start);
end = template.indexOf('}', start) + 1;
uri += expandExpression(template.slice(start + 1, end - 1), params);
}
return uri;
}
return {
/**
* Expand a URI Template with parameters to form a URI.
*
* Full implementation (level 4) of rfc6570.
* @see https://tools.ietf.org/html/rfc6570
*
* @param {string} template URI template
* @param {Object} [params] params to apply to the template durring expantion
* @returns {string} expanded URI
*/
expand: expandTemplate
};
});
}(
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }
// Boilerplate for AMD and Node
));