uritemplate
Version:
An UriTemplate implementation of rfc 6570
218 lines (203 loc) • 7.59 kB
JavaScript
/*jshint unused:false */
/*global pctEncoder, rfcCharHelper, isDefined, objectHelper, encodingHelper*/
var VariableExpression = (function () {
"use strict";
// helper function if JSON is not available
function prettyPrint (value) {
return (JSON && JSON.stringify) ? JSON.stringify(value) : value;
}
function isEmpty (value) {
if (!isDefined(value)) {
return true;
}
if (objectHelper.isString(value)) {
return value === '';
}
if (objectHelper.isNumber(value) || objectHelper.isBoolean(value)) {
return false;
}
if (objectHelper.isArray(value)) {
return value.length === 0;
}
for (var propertyName in value) {
if (value.hasOwnProperty(propertyName)) {
return false;
}
}
return true;
}
function propertyArray (object) {
var
result = [],
propertyName;
for (propertyName in object) {
if (object.hasOwnProperty(propertyName)) {
result.push({name: propertyName, value: object[propertyName]});
}
}
return result;
}
function VariableExpression (templateText, operator, varspecs) {
this.templateText = templateText;
this.operator = operator;
this.varspecs = varspecs;
}
VariableExpression.prototype.toString = function () {
return this.templateText;
};
function expandSimpleValue(varspec, operator, value) {
var result = '';
value = value.toString();
if (operator.named) {
result += encodingHelper.encodeLiteral(varspec.varname);
if (value === '') {
result += operator.ifEmpty;
return result;
}
result += '=';
}
if (varspec.maxLength !== null) {
value = value.substr(0, varspec.maxLength);
}
result += operator.encode(value);
return result;
}
function valueDefined (nameValue) {
return isDefined(nameValue.value);
}
function expandNotExploded(varspec, operator, value) {
var
arr = [],
result = '';
if (operator.named) {
result += encodingHelper.encodeLiteral(varspec.varname);
if (isEmpty(value)) {
result += operator.ifEmpty;
return result;
}
result += '=';
}
if (objectHelper.isArray(value)) {
arr = value;
arr = objectHelper.filter(arr, isDefined);
arr = objectHelper.map(arr, operator.encode);
result += objectHelper.join(arr, ',');
}
else {
arr = propertyArray(value);
arr = objectHelper.filter(arr, valueDefined);
arr = objectHelper.map(arr, function (nameValue) {
return operator.encode(nameValue.name) + ',' + operator.encode(nameValue.value);
});
result += objectHelper.join(arr, ',');
}
return result;
}
function expandExplodedNamed (varspec, operator, value) {
var
isArray = objectHelper.isArray(value),
arr = [];
if (isArray) {
arr = value;
arr = objectHelper.filter(arr, isDefined);
arr = objectHelper.map(arr, function (listElement) {
var tmp = encodingHelper.encodeLiteral(varspec.varname);
if (isEmpty(listElement)) {
tmp += operator.ifEmpty;
}
else {
tmp += '=' + operator.encode(listElement);
}
return tmp;
});
}
else {
arr = propertyArray(value);
arr = objectHelper.filter(arr, valueDefined);
arr = objectHelper.map(arr, function (nameValue) {
var tmp = encodingHelper.encodeLiteral(nameValue.name);
if (isEmpty(nameValue.value)) {
tmp += operator.ifEmpty;
}
else {
tmp += '=' + operator.encode(nameValue.value);
}
return tmp;
});
}
return objectHelper.join(arr, operator.separator);
}
function expandExplodedUnnamed (operator, value) {
var
arr = [],
result = '';
if (objectHelper.isArray(value)) {
arr = value;
arr = objectHelper.filter(arr, isDefined);
arr = objectHelper.map(arr, operator.encode);
result += objectHelper.join(arr, operator.separator);
}
else {
arr = propertyArray(value);
arr = objectHelper.filter(arr, function (nameValue) {
return isDefined(nameValue.value);
});
arr = objectHelper.map(arr, function (nameValue) {
return operator.encode(nameValue.name) + '=' + operator.encode(nameValue.value);
});
result += objectHelper.join(arr, operator.separator);
}
return result;
}
VariableExpression.prototype.expand = function (variables) {
var
expanded = [],
index,
varspec,
value,
valueIsArr,
oneExploded = false,
operator = this.operator;
// expand each varspec and join with operator's separator
for (index = 0; index < this.varspecs.length; index += 1) {
varspec = this.varspecs[index];
value = variables[varspec.varname];
// if (!isDefined(value)) {
// if (variables.hasOwnProperty(varspec.name)) {
if (value === null || value === undefined) {
continue;
}
if (varspec.exploded) {
oneExploded = true;
}
valueIsArr = objectHelper.isArray(value);
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
expanded.push(expandSimpleValue(varspec, operator, value));
}
else if (varspec.maxLength && isDefined(value)) {
// 2.4.1 of the spec says: "Prefix modifiers are not applicable to variables that have composite values."
throw new Error('Prefix modifiers are not applicable to variables that have composite values. You tried to expand ' + this + " with " + prettyPrint(value));
}
else if (!varspec.exploded) {
if (operator.named || !isEmpty(value)) {
expanded.push(expandNotExploded(varspec, operator, value));
}
}
else if (isDefined(value)) {
if (operator.named) {
expanded.push(expandExplodedNamed(varspec, operator, value));
}
else {
expanded.push(expandExplodedUnnamed(operator, value));
}
}
}
if (expanded.length === 0) {
return "";
}
else {
return operator.first + objectHelper.join(expanded, operator.separator);
}
};
return VariableExpression;
}());