Comparing version 1.3.2 to 2.0.0
{ | ||
"name": "rest", | ||
"version": "1.3.2", | ||
"version": "2.0.0", | ||
"main": "./browser.js", | ||
"moduleType": ["amd", "node"], | ||
"dependencies": { | ||
"when": "~3" | ||
}, | ||
"moduleType": ["node"], | ||
"dependencies": {}, | ||
"ignore": [ | ||
@@ -10,0 +8,0 @@ "docs", |
/* | ||
* Copyright 2014 the original author or authors | ||
* Copyright 2014-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,19 +8,9 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var rest = require('./client/default'), | ||
browser = require('./client/xhr'); | ||
var rest = require('./client/default'), | ||
browser = require('./client/xhr'); | ||
rest.setPlatformDefaultClient(browser); | ||
rest.setPlatformDefaultClient(browser); | ||
return rest; | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
module.exports = rest; |
/* | ||
* Copyright 2014 the original author or authors | ||
* Copyright 2014-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,58 +8,48 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (/* require */) { | ||
/** | ||
* Add common helper methods to a client impl | ||
* | ||
* @param {function} impl the client implementation | ||
* @param {Client} [target] target of this client, used when wrapping other clients | ||
* @returns {Client} the client impl with additional methods | ||
*/ | ||
module.exports = function client(impl, target) { | ||
if (target) { | ||
/** | ||
* Add common helper methods to a client impl | ||
* | ||
* @param {function} impl the client implementation | ||
* @param {Client} [target] target of this client, used when wrapping other clients | ||
* @returns {Client} the client impl with additional methods | ||
* @returns {Client} the target client | ||
*/ | ||
return function client(impl, target) { | ||
impl.skip = function skip() { | ||
return target; | ||
}; | ||
if (target) { | ||
} | ||
/** | ||
* @returns {Client} the target client | ||
*/ | ||
impl.skip = function skip() { | ||
return target; | ||
}; | ||
/** | ||
* Allow a client to easily be wrapped by an interceptor | ||
* | ||
* @param {Interceptor} interceptor the interceptor to wrap this client with | ||
* @param [config] configuration for the interceptor | ||
* @returns {Client} the newly wrapped client | ||
*/ | ||
impl.wrap = function wrap(interceptor, config) { | ||
return interceptor(impl, config); | ||
}; | ||
} | ||
/** | ||
* @deprecated | ||
*/ | ||
impl.chain = function chain() { | ||
if (typeof console !== 'undefined') { | ||
console.log('rest.js: client.chain() is deprecated, use client.wrap() instead'); | ||
} | ||
/** | ||
* Allow a client to easily be wrapped by an interceptor | ||
* | ||
* @param {Interceptor} interceptor the interceptor to wrap this client with | ||
* @param [config] configuration for the interceptor | ||
* @returns {Client} the newly wrapped client | ||
*/ | ||
impl.wrap = function wrap(interceptor, config) { | ||
return interceptor(impl, config); | ||
}; | ||
return impl.wrap.apply(this, arguments); | ||
}; | ||
/** | ||
* @deprecated | ||
*/ | ||
impl.chain = function chain() { | ||
if (typeof console !== 'undefined') { | ||
console.log('rest.js: client.chain() is deprecated, use client.wrap() instead'); | ||
} | ||
return impl; | ||
return impl.wrap.apply(this, arguments); | ||
}; | ||
return impl; | ||
}; | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
}; |
/* | ||
* Copyright 2014 the original author or authors | ||
* Copyright 2014-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,118 +8,110 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
var undef; | ||
/** | ||
* Plain JS Object containing properties that represent an HTTP request. | ||
* | ||
* Depending on the capabilities of the underlying client, a request | ||
* may be cancelable. If a request may be canceled, the client will add | ||
* a canceled flag and cancel function to the request object. Canceling | ||
* the request will put the response into an error state. | ||
* | ||
* @field {string} [method='GET'] HTTP method, commonly GET, POST, PUT, DELETE or HEAD | ||
* @field {string|UrlBuilder} [path=''] path template with optional path variables | ||
* @field {Object} [params] parameters for the path template and query string | ||
* @field {Object} [headers] custom HTTP headers to send, in addition to the clients default headers | ||
* @field [entity] the HTTP entity, common for POST or PUT requests | ||
* @field {boolean} [canceled] true if the request has been canceled, set by the client | ||
* @field {Function} [cancel] cancels the request if invoked, provided by the client | ||
* @field {Client} [originator] the client that first handled this request, provided by the interceptor | ||
* | ||
* @class Request | ||
*/ | ||
define(function (require) { | ||
/** | ||
* Plain JS Object containing properties that represent an HTTP response | ||
* | ||
* @field {Object} [request] the request object as received by the root client | ||
* @field {Object} [raw] the underlying request object, like XmlHttpRequest in a browser | ||
* @field {number} [status.code] status code of the response (i.e. 200, 404) | ||
* @field {string} [status.text] status phrase of the response | ||
* @field {Object] [headers] response headers hash of normalized name, value pairs | ||
* @field [entity] the response body | ||
* | ||
* @class Response | ||
*/ | ||
/** | ||
* Plain JS Object containing properties that represent an HTTP request. | ||
* | ||
* Depending on the capabilities of the underlying client, a request | ||
* may be cancelable. If a request may be canceled, the client will add | ||
* a canceled flag and cancel function to the request object. Canceling | ||
* the request will put the response into an error state. | ||
* | ||
* @field {string} [method='GET'] HTTP method, commonly GET, POST, PUT, DELETE or HEAD | ||
* @field {string|UrlBuilder} [path=''] path template with optional path variables | ||
* @field {Object} [params] parameters for the path template and query string | ||
* @field {Object} [headers] custom HTTP headers to send, in addition to the clients default headers | ||
* @field [entity] the HTTP entity, common for POST or PUT requests | ||
* @field {boolean} [canceled] true if the request has been canceled, set by the client | ||
* @field {Function} [cancel] cancels the request if invoked, provided by the client | ||
* @field {Client} [originator] the client that first handled this request, provided by the interceptor | ||
* | ||
* @class Request | ||
*/ | ||
/** | ||
* HTTP client particularly suited for RESTful operations. | ||
* | ||
* @field {function} wrap wraps this client with a new interceptor returning the wrapped client | ||
* | ||
* @param {Request} the HTTP request | ||
* @returns {ResponsePromise<Response>} a promise the resolves to the HTTP response | ||
* | ||
* @class Client | ||
*/ | ||
/** | ||
* Plain JS Object containing properties that represent an HTTP response | ||
* | ||
* @field {Object} [request] the request object as received by the root client | ||
* @field {Object} [raw] the underlying request object, like XmlHttpRequest in a browser | ||
* @field {number} [status.code] status code of the response (i.e. 200, 404) | ||
* @field {string} [status.text] status phrase of the response | ||
* @field {Object] [headers] response headers hash of normalized name, value pairs | ||
* @field [entity] the response body | ||
* | ||
* @class Response | ||
*/ | ||
/** | ||
* Extended when.js Promises/A+ promise with HTTP specific helpers | ||
*q | ||
* @method entity promise for the HTTP entity | ||
* @method status promise for the HTTP status code | ||
* @method headers promise for the HTTP response headers | ||
* @method header promise for a specific HTTP response header | ||
* | ||
* @class ResponsePromise | ||
* @extends Promise | ||
*/ | ||
/** | ||
* HTTP client particularly suited for RESTful operations. | ||
* | ||
* @field {function} wrap wraps this client with a new interceptor returning the wrapped client | ||
* | ||
* @param {Request} the HTTP request | ||
* @returns {ResponsePromise<Response>} a promise the resolves to the HTTP response | ||
* | ||
* @class Client | ||
*/ | ||
var client, target, platformDefault; | ||
/** | ||
* Extended when.js Promises/A+ promise with HTTP specific helpers | ||
*q | ||
* @method entity promise for the HTTP entity | ||
* @method status promise for the HTTP status code | ||
* @method headers promise for the HTTP response headers | ||
* @method header promise for a specific HTTP response header | ||
* | ||
* @class ResponsePromise | ||
* @extends Promise | ||
*/ | ||
client = require('../client'); | ||
var client, target, platformDefault; | ||
if (typeof Promise !== 'function' && console && console.log) { | ||
console.log('An ES6 Promise implementation is required to use rest.js. See https://github.com/cujojs/when/blob/master/docs/es6-promise-shim.md for using when.js as a Promise polyfill.'); | ||
} | ||
client = require('../client'); | ||
/** | ||
* Make a request with the default client | ||
* @param {Request} the HTTP request | ||
* @returns {Promise<Response>} a promise the resolves to the HTTP response | ||
*/ | ||
function defaultClient() { | ||
return target.apply(void 0, arguments); | ||
} | ||
/** | ||
* Make a request with the default client | ||
* @param {Request} the HTTP request | ||
* @returns {Promise<Response>} a promise the resolves to the HTTP response | ||
*/ | ||
function defaultClient() { | ||
return target.apply(undef, arguments); | ||
} | ||
/** | ||
* Change the default client | ||
* @param {Client} client the new default client | ||
*/ | ||
defaultClient.setDefaultClient = function setDefaultClient(client) { | ||
target = client; | ||
}; | ||
/** | ||
* Change the default client | ||
* @param {Client} client the new default client | ||
*/ | ||
defaultClient.setDefaultClient = function setDefaultClient(client) { | ||
target = client; | ||
}; | ||
/** | ||
* Obtain a direct reference to the current default client | ||
* @returns {Client} the default client | ||
*/ | ||
defaultClient.getDefaultClient = function getDefaultClient() { | ||
return target; | ||
}; | ||
/** | ||
* Obtain a direct reference to the current default client | ||
* @returns {Client} the default client | ||
*/ | ||
defaultClient.getDefaultClient = function getDefaultClient() { | ||
return target; | ||
}; | ||
/** | ||
* Reset the default client to the platform default | ||
*/ | ||
defaultClient.resetDefaultClient = function resetDefaultClient() { | ||
target = platformDefault; | ||
}; | ||
/** | ||
* Reset the default client to the platform default | ||
*/ | ||
defaultClient.resetDefaultClient = function resetDefaultClient() { | ||
target = platformDefault; | ||
}; | ||
/** | ||
* @private | ||
*/ | ||
defaultClient.setPlatformDefaultClient = function setPlatformDefaultClient(client) { | ||
if (platformDefault) { | ||
throw new Error('Unable to redefine platformDefaultClient'); | ||
} | ||
target = platformDefault = client; | ||
}; | ||
/** | ||
* @private | ||
*/ | ||
defaultClient.setPlatformDefaultClient = function setPlatformDefaultClient(client) { | ||
if (platformDefault) { | ||
throw new Error('Unable to redefine platformDefaultClient'); | ||
} | ||
target = platformDefault = client; | ||
}; | ||
return client(defaultClient); | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
module.exports = client(defaultClient); |
/* | ||
* Copyright 2012-2014 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,139 +8,124 @@ * | ||
(function (define, global, document) { | ||
'use strict'; | ||
'use strict'; | ||
var undef; | ||
var UrlBuilder, responsePromise, client; | ||
define(function (require) { | ||
UrlBuilder = require('../UrlBuilder'); | ||
responsePromise = require('../util/responsePromise'); | ||
client = require('../client'); | ||
var when, UrlBuilder, responsePromise, client; | ||
// consider abstracting this into a util module | ||
function clearProperty(scope, propertyName) { | ||
try { | ||
delete scope[propertyName]; | ||
} | ||
catch (e) { | ||
// IE doesn't like to delete properties on the window object | ||
if (propertyName in scope) { | ||
scope[propertyName] = void 0; | ||
} | ||
} | ||
} | ||
when = require('when'); | ||
UrlBuilder = require('../UrlBuilder'); | ||
responsePromise = require('../util/responsePromise'); | ||
client = require('../client'); | ||
// consider abstracting this into a util module | ||
function clearProperty(scope, propertyName) { | ||
try { | ||
delete scope[propertyName]; | ||
} | ||
catch (e) { | ||
// IE doesn't like to delete properties on the window object | ||
if (propertyName in scope) { | ||
scope[propertyName] = undef; | ||
} | ||
} | ||
function cleanupScriptNode(response) { | ||
try { | ||
if (response.raw && response.raw.parentNode) { | ||
response.raw.parentNode.removeChild(response.raw); | ||
} | ||
} catch (e) { | ||
// ignore | ||
} | ||
} | ||
function cleanupScriptNode(response) { | ||
try { | ||
if (response.raw && response.raw.parentNode) { | ||
response.raw.parentNode.removeChild(response.raw); | ||
} | ||
} catch (e) { | ||
// ignore | ||
} | ||
function registerCallback(prefix, resolve, response, name) { | ||
if (!name) { | ||
do { | ||
name = prefix + Math.floor(new Date().getTime() * Math.random()); | ||
} | ||
while (name in window); | ||
} | ||
function registerCallback(prefix, resolve, response, name) { | ||
if (!name) { | ||
do { | ||
name = prefix + Math.floor(new Date().getTime() * Math.random()); | ||
} | ||
while (name in global); | ||
} | ||
global[name] = function jsonpCallback(data) { | ||
response.entity = data; | ||
clearProperty(global, name); | ||
cleanupScriptNode(response); | ||
if (!response.request.canceled) { | ||
resolve(response); | ||
} | ||
}; | ||
return name; | ||
window[name] = function jsonpCallback(data) { | ||
response.entity = data; | ||
clearProperty(window, name); | ||
cleanupScriptNode(response); | ||
if (!response.request.canceled) { | ||
resolve(response); | ||
} | ||
}; | ||
/** | ||
* Executes the request as JSONP. | ||
* | ||
* @param {string} request.path the URL to load | ||
* @param {Object} [request.params] parameters to bind to the path | ||
* @param {string} [request.callback.param='callback'] the parameter name for | ||
* which the callback function name is the value | ||
* @param {string} [request.callback.prefix='jsonp'] prefix for the callback | ||
* function, as the callback is attached to the window object, a unique, | ||
* unobtrusive prefix is desired | ||
* @param {string} [request.callback.name=<generated>] pins the name of the | ||
* callback function, useful for cases where the server doesn't allow | ||
* custom callback names. Generally not recommended. | ||
* | ||
* @returns {Promise<Response>} | ||
*/ | ||
return client(function jsonp(request) { | ||
return responsePromise.promise(function (resolve, reject) { | ||
return name; | ||
} | ||
var callbackName, callbackParams, script, firstScript, response; | ||
/** | ||
* Executes the request as JSONP. | ||
* | ||
* @param {string} request.path the URL to load | ||
* @param {Object} [request.params] parameters to bind to the path | ||
* @param {string} [request.callback.param='callback'] the parameter name for | ||
* which the callback function name is the value | ||
* @param {string} [request.callback.prefix='jsonp'] prefix for the callback | ||
* function, as the callback is attached to the window object, a unique, | ||
* unobtrusive prefix is desired | ||
* @param {string} [request.callback.name=<generated>] pins the name of the | ||
* callback function, useful for cases where the server doesn't allow | ||
* custom callback names. Generally not recommended. | ||
* | ||
* @returns {Promise<Response>} | ||
*/ | ||
module.exports = client(function jsonp(request) { | ||
return responsePromise.promise(function (resolve, reject) { | ||
request = typeof request === 'string' ? { path: request } : request || {}; | ||
response = { request: request }; | ||
var callbackName, callbackParams, script, firstScript, response; | ||
if (request.canceled) { | ||
response.error = 'precanceled'; | ||
reject(response); | ||
return; | ||
} | ||
request = typeof request === 'string' ? { path: request } : request || {}; | ||
response = { request: request }; | ||
request.callback = request.callback || {}; | ||
callbackName = registerCallback(request.callback.prefix || 'jsonp', resolve, response, request.callback.name); | ||
callbackParams = {}; | ||
callbackParams[request.callback.param || 'callback'] = callbackName; | ||
if (request.canceled) { | ||
response.error = 'precanceled'; | ||
reject(response); | ||
return; | ||
} | ||
request.canceled = false; | ||
request.cancel = function cancel() { | ||
request.canceled = true; | ||
cleanupScriptNode(response); | ||
reject(response); | ||
}; | ||
request.callback = request.callback || {}; | ||
callbackName = registerCallback(request.callback.prefix || 'jsonp', resolve, response, request.callback.name); | ||
callbackParams = {}; | ||
callbackParams[request.callback.param || 'callback'] = callbackName; | ||
script = document.createElement('script'); | ||
script.type = 'text/javascript'; | ||
script.async = true; | ||
script.src = response.url = new UrlBuilder(request.path, request.params).build(callbackParams); | ||
request.canceled = false; | ||
request.cancel = function cancel() { | ||
request.canceled = true; | ||
cleanupScriptNode(response); | ||
reject(response); | ||
}; | ||
function handlePossibleError() { | ||
if (typeof global[callbackName] === 'function') { | ||
response.error = 'loaderror'; | ||
clearProperty(global, callbackName); | ||
cleanupScriptNode(response); | ||
reject(response); | ||
} | ||
} | ||
script.onerror = function () { | ||
handlePossibleError(); | ||
}; | ||
script.onload = script.onreadystatechange = function (e) { | ||
// script tag load callbacks are completely non-standard | ||
// handle case where onreadystatechange is fired for an error instead of onerror | ||
if ((e && (e.type === 'load' || e.type === 'error')) || script.readyState === 'loaded') { | ||
handlePossibleError(); | ||
} | ||
}; | ||
script = document.createElement('script'); | ||
script.type = 'text/javascript'; | ||
script.async = true; | ||
script.src = response.url = new UrlBuilder(request.path, callbackParams).build(); | ||
response.raw = script; | ||
firstScript = document.getElementsByTagName('script')[0]; | ||
firstScript.parentNode.insertBefore(script, firstScript); | ||
function handlePossibleError() { | ||
if (typeof window[callbackName] === 'function') { | ||
response.error = 'loaderror'; | ||
clearProperty(window, callbackName); | ||
cleanupScriptNode(response); | ||
reject(response); | ||
} | ||
} | ||
script.onerror = function () { | ||
handlePossibleError(); | ||
}; | ||
script.onload = script.onreadystatechange = function (e) { | ||
// script tag load callbacks are completely non-standard | ||
// handle case where onreadystatechange is fired for an error instead of onerror | ||
if ((e && (e.type === 'load' || e.type === 'error')) || script.readyState === 'loaded') { | ||
handlePossibleError(); | ||
} | ||
}; | ||
}); | ||
}); | ||
response.raw = script; | ||
firstScript = document.getElementsByTagName('script')[0]; | ||
firstScript.parentNode.insertBefore(script, firstScript); | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }, | ||
typeof window !== 'undefined' ? window : void 0, | ||
typeof document !== 'undefined' ? document : void 0 | ||
// Boilerplate for AMD and Node | ||
)); | ||
}); |
/* | ||
* Copyright 2012-2014 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -9,140 +9,127 @@ * | ||
(function (define, envRequire) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var parser, http, https, mixin, normalizeHeaderName, responsePromise, client, httpsExp; | ||
var parser, http, https, when, UrlBuilder, mixin, normalizeHeaderName, responsePromise, client, httpsExp; | ||
parser = require('url'); | ||
http = require('http'); | ||
https = require('https'); | ||
mixin = require('../util/mixin'); | ||
normalizeHeaderName = require('../util/normalizeHeaderName'); | ||
responsePromise = require('../util/responsePromise'); | ||
client = require('../client'); | ||
parser = envRequire('url'); | ||
http = envRequire('http'); | ||
https = envRequire('https'); | ||
when = require('when'); | ||
UrlBuilder = require('../UrlBuilder'); | ||
mixin = require('../util/mixin'); | ||
normalizeHeaderName = require('../util/normalizeHeaderName'); | ||
responsePromise = require('../util/responsePromise'); | ||
client = require('../client'); | ||
httpsExp = /^https/i; | ||
httpsExp = /^https/i; | ||
// TODO remove once Node 0.6 is no longer supported | ||
Buffer.concat = Buffer.concat || function (list, length) { | ||
/*jshint plusplus:false, shadow:true */ | ||
// from https://github.com/joyent/node/blob/v0.8.21/lib/buffer.js | ||
if (!Array.isArray(list)) { | ||
throw new Error('Usage: Buffer.concat(list, [length])'); | ||
} | ||
// TODO remove once Node 0.6 is no longer supported | ||
Buffer.concat = Buffer.concat || function (list, length) { | ||
/*jshint plusplus:false, shadow:true */ | ||
// from https://github.com/joyent/node/blob/v0.8.21/lib/buffer.js | ||
if (!Array.isArray(list)) { | ||
throw new Error('Usage: Buffer.concat(list, [length])'); | ||
} | ||
if (list.length === 0) { | ||
return new Buffer(0); | ||
} else if (list.length === 1) { | ||
return list[0]; | ||
} | ||
if (list.length === 0) { | ||
return new Buffer(0); | ||
} else if (list.length === 1) { | ||
return list[0]; | ||
} | ||
if (typeof length !== 'number') { | ||
length = 0; | ||
for (var i = 0; i < list.length; i++) { | ||
var buf = list[i]; | ||
length += buf.length; | ||
} | ||
} | ||
if (typeof length !== 'number') { | ||
length = 0; | ||
for (var i = 0; i < list.length; i++) { | ||
var buf = list[i]; | ||
length += buf.length; | ||
} | ||
} | ||
var buffer = new Buffer(length); | ||
var pos = 0; | ||
for (var i = 0; i < list.length; i++) { | ||
var buf = list[i]; | ||
buf.copy(buffer, pos); | ||
pos += buf.length; | ||
} | ||
return buffer; | ||
}; | ||
var buffer = new Buffer(length); | ||
var pos = 0; | ||
for (var i = 0; i < list.length; i++) { | ||
var buf = list[i]; | ||
buf.copy(buffer, pos); | ||
pos += buf.length; | ||
} | ||
return buffer; | ||
}; | ||
module.exports = client(function node(request) { | ||
/*jshint maxcomplexity:20 */ | ||
return responsePromise.promise(function (resolve, reject) { | ||
return client(function node(request) { | ||
/*jshint maxcomplexity:20 */ | ||
return responsePromise.promise(function (resolve, reject) { | ||
var options, clientRequest, client, url, headers, entity, response; | ||
var options, clientRequest, client, url, headers, entity, response; | ||
request = typeof request === 'string' ? { path: request } : request || {}; | ||
response = { request: request }; | ||
request = typeof request === 'string' ? { path: request } : request || {}; | ||
response = { request: request }; | ||
if (request.canceled) { | ||
response.error = 'precanceled'; | ||
reject(response); | ||
return; | ||
} | ||
if (request.canceled) { | ||
response.error = 'precanceled'; | ||
reject(response); | ||
return; | ||
} | ||
url = response.url = request.path || ''; | ||
client = url.match(httpsExp) ? https : http; | ||
url = response.url = new UrlBuilder(request.path || '', request.params).build(); | ||
client = url.match(httpsExp) ? https : http; | ||
options = mixin({}, request.mixin, parser.parse(url)); | ||
options = mixin({}, request.mixin, parser.parse(url)); | ||
entity = request.entity; | ||
request.method = request.method || (entity ? 'POST' : 'GET'); | ||
options.method = request.method; | ||
headers = options.headers = {}; | ||
Object.keys(request.headers || {}).forEach(function (name) { | ||
headers[normalizeHeaderName(name)] = request.headers[name]; | ||
}); | ||
if (!headers['Content-Length']) { | ||
headers['Content-Length'] = entity ? Buffer.byteLength(entity, 'utf8') : 0; | ||
} | ||
entity = request.entity; | ||
request.method = request.method || (entity ? 'POST' : 'GET'); | ||
options.method = request.method; | ||
headers = options.headers = {}; | ||
Object.keys(request.headers || {}).forEach(function (name) { | ||
headers[normalizeHeaderName(name)] = request.headers[name]; | ||
}); | ||
if (!headers['Content-Length']) { | ||
headers['Content-Length'] = entity ? Buffer.byteLength(entity, 'utf8') : 0; | ||
} | ||
request.canceled = false; | ||
request.cancel = function cancel() { | ||
request.canceled = true; | ||
clientRequest.abort(); | ||
}; | ||
request.canceled = false; | ||
request.cancel = function cancel() { | ||
request.canceled = true; | ||
clientRequest.abort(); | ||
}; | ||
clientRequest = client.request(options, function (clientResponse) { | ||
// Array of Buffers to collect response chunks | ||
var buffers = []; | ||
clientRequest = client.request(options, function (clientResponse) { | ||
// Array of Buffers to collect response chunks | ||
var buffers = []; | ||
response.raw = { | ||
request: clientRequest, | ||
response: clientResponse | ||
}; | ||
response.status = { | ||
code: clientResponse.statusCode | ||
// node doesn't provide access to the status text | ||
}; | ||
response.headers = {}; | ||
Object.keys(clientResponse.headers).forEach(function (name) { | ||
response.headers[normalizeHeaderName(name)] = clientResponse.headers[name]; | ||
}); | ||
response.raw = { | ||
request: clientRequest, | ||
response: clientResponse | ||
}; | ||
response.status = { | ||
code: clientResponse.statusCode | ||
// node doesn't provide access to the status text | ||
}; | ||
response.headers = {}; | ||
Object.keys(clientResponse.headers).forEach(function (name) { | ||
response.headers[normalizeHeaderName(name)] = clientResponse.headers[name]; | ||
}); | ||
clientResponse.on('data', function (data) { | ||
// Collect the next Buffer chunk | ||
buffers.push(data); | ||
}); | ||
clientResponse.on('data', function (data) { | ||
// Collect the next Buffer chunk | ||
buffers.push(data); | ||
}); | ||
clientResponse.on('end', function () { | ||
// Create the final response entity | ||
response.entity = buffers.length > 0 ? Buffer.concat(buffers).toString() : ''; | ||
buffers = null; | ||
clientResponse.on('end', function () { | ||
// Create the final response entity | ||
response.entity = buffers.length > 0 ? Buffer.concat(buffers).toString() : ''; | ||
buffers = null; | ||
resolve(response); | ||
}); | ||
}); | ||
resolve(response); | ||
}); | ||
}); | ||
clientRequest.on('error', function (e) { | ||
response.error = e; | ||
reject(response); | ||
}); | ||
clientRequest.on('error', function (e) { | ||
response.error = e; | ||
reject(response); | ||
}); | ||
if (entity) { | ||
clientRequest.write(entity); | ||
} | ||
clientRequest.end(); | ||
if (entity) { | ||
clientRequest.write(entity); | ||
} | ||
clientRequest.end(); | ||
}); | ||
}); | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }, | ||
typeof require === 'function' && require | ||
// Boilerplate for AMD and Node | ||
)); | ||
}); |
/* | ||
* Copyright 2012-2014 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,168 +8,161 @@ * | ||
(function (define, global) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var normalizeHeaderName, responsePromise, client, headerSplitRE; | ||
var when, UrlBuilder, normalizeHeaderName, responsePromise, client, headerSplitRE; | ||
normalizeHeaderName = require('../util/normalizeHeaderName'); | ||
responsePromise = require('../util/responsePromise'); | ||
client = require('../client'); | ||
when = require('when'); | ||
UrlBuilder = require('../UrlBuilder'); | ||
normalizeHeaderName = require('../util/normalizeHeaderName'); | ||
responsePromise = require('../util/responsePromise'); | ||
client = require('../client'); | ||
// according to the spec, the line break is '\r\n', but doesn't hold true in practice | ||
headerSplitRE = /[\r|\n]+/; | ||
// according to the spec, the line break is '\r\n', but doesn't hold true in practice | ||
headerSplitRE = /[\r|\n]+/; | ||
function parseHeaders(raw) { | ||
// Note: Set-Cookie will be removed by the browser | ||
var headers = {}; | ||
function parseHeaders(raw) { | ||
// Note: Set-Cookie will be removed by the browser | ||
var headers = {}; | ||
if (!raw) { return headers; } | ||
if (!raw) { return headers; } | ||
raw.trim().split(headerSplitRE).forEach(function (header) { | ||
var boundary, name, value; | ||
boundary = header.indexOf(':'); | ||
name = normalizeHeaderName(header.substring(0, boundary).trim()); | ||
value = header.substring(boundary + 1).trim(); | ||
if (headers[name]) { | ||
if (Array.isArray(headers[name])) { | ||
// add to an existing array | ||
headers[name].push(value); | ||
} | ||
else { | ||
// convert single value to array | ||
headers[name] = [headers[name], value]; | ||
} | ||
} | ||
else { | ||
// new, single value | ||
headers[name] = value; | ||
} | ||
}); | ||
return headers; | ||
raw.trim().split(headerSplitRE).forEach(function (header) { | ||
var boundary, name, value; | ||
boundary = header.indexOf(':'); | ||
name = normalizeHeaderName(header.substring(0, boundary).trim()); | ||
value = header.substring(boundary + 1).trim(); | ||
if (headers[name]) { | ||
if (Array.isArray(headers[name])) { | ||
// add to an existing array | ||
headers[name].push(value); | ||
} | ||
else { | ||
// convert single value to array | ||
headers[name] = [headers[name], value]; | ||
} | ||
} | ||
else { | ||
// new, single value | ||
headers[name] = value; | ||
} | ||
}); | ||
function safeMixin(target, source) { | ||
Object.keys(source || {}).forEach(function (prop) { | ||
// make sure the property already exists as | ||
// IE 6 will blow up if we add a new prop | ||
if (source.hasOwnProperty(prop) && prop in target) { | ||
try { | ||
target[prop] = source[prop]; | ||
} | ||
catch (e) { | ||
// ignore, expected for some properties at some points in the request lifecycle | ||
} | ||
} | ||
}); | ||
return headers; | ||
} | ||
return target; | ||
function safeMixin(target, source) { | ||
Object.keys(source || {}).forEach(function (prop) { | ||
// make sure the property already exists as | ||
// IE 6 will blow up if we add a new prop | ||
if (source.hasOwnProperty(prop) && prop in target) { | ||
try { | ||
target[prop] = source[prop]; | ||
} | ||
catch (e) { | ||
// ignore, expected for some properties at some points in the request lifecycle | ||
} | ||
} | ||
}); | ||
return client(function xhr(request) { | ||
return responsePromise.promise(function (resolve, reject) { | ||
/*jshint maxcomplexity:20 */ | ||
return target; | ||
} | ||
var client, method, url, headers, entity, headerName, response, XMLHttpRequest; | ||
module.exports = client(function xhr(request) { | ||
return responsePromise.promise(function (resolve, reject) { | ||
/*jshint maxcomplexity:20 */ | ||
request = typeof request === 'string' ? { path: request } : request || {}; | ||
response = { request: request }; | ||
var client, method, url, headers, entity, headerName, response, XHR; | ||
if (request.canceled) { | ||
response.error = 'precanceled'; | ||
reject(response); | ||
return; | ||
} | ||
request = typeof request === 'string' ? { path: request } : request || {}; | ||
response = { request: request }; | ||
entity = request.entity; | ||
request.method = request.method || (entity ? 'POST' : 'GET'); | ||
method = request.method; | ||
url = response.url = new UrlBuilder(request.path || '', request.params).build(); | ||
if (request.canceled) { | ||
response.error = 'precanceled'; | ||
reject(response); | ||
return; | ||
} | ||
XMLHttpRequest = request.engine || global.XMLHttpRequest; | ||
if (!XMLHttpRequest) { | ||
reject({ request: request, url: url, error: 'xhr-not-available' }); | ||
return; | ||
} | ||
XHR = request.engine || XMLHttpRequest; | ||
if (!XHR) { | ||
reject({ request: request, error: 'xhr-not-available' }); | ||
return; | ||
} | ||
try { | ||
client = response.raw = new XMLHttpRequest(); | ||
entity = request.entity; | ||
request.method = request.method || (entity ? 'POST' : 'GET'); | ||
method = request.method; | ||
url = response.url = request.path || ''; | ||
// mixin extra request properties before and after opening the request as some properties require being set at different phases of the request | ||
safeMixin(client, request.mixin); | ||
client.open(method, url, true); | ||
safeMixin(client, request.mixin); | ||
try { | ||
client = response.raw = new XHR(); | ||
headers = request.headers; | ||
for (headerName in headers) { | ||
/*jshint forin:false */ | ||
if (headerName === 'Content-Type' && headers[headerName] === 'multipart/form-data') { | ||
// XMLHttpRequest generates its own Content-Type header with the | ||
// appropriate multipart boundary when sending multipart/form-data. | ||
continue; | ||
} | ||
// mixin extra request properties before and after opening the request as some properties require being set at different phases of the request | ||
safeMixin(client, request.mixin); | ||
client.open(method, url, true); | ||
safeMixin(client, request.mixin); | ||
client.setRequestHeader(headerName, headers[headerName]); | ||
} | ||
headers = request.headers; | ||
for (headerName in headers) { | ||
/*jshint forin:false */ | ||
if (headerName === 'Content-Type' && headers[headerName] === 'multipart/form-data') { | ||
// XMLHttpRequest generates its own Content-Type header with the | ||
// appropriate multipart boundary when sending multipart/form-data. | ||
continue; | ||
} | ||
request.canceled = false; | ||
request.cancel = function cancel() { | ||
request.canceled = true; | ||
client.abort(); | ||
reject(response); | ||
}; | ||
client.setRequestHeader(headerName, headers[headerName]); | ||
} | ||
client.onreadystatechange = function (/* e */) { | ||
if (request.canceled) { return; } | ||
if (client.readyState === (XMLHttpRequest.DONE || 4)) { | ||
response.status = { | ||
code: client.status, | ||
text: client.statusText | ||
}; | ||
response.headers = parseHeaders(client.getAllResponseHeaders()); | ||
response.entity = client.responseText; | ||
request.canceled = false; | ||
request.cancel = function cancel() { | ||
request.canceled = true; | ||
client.abort(); | ||
reject(response); | ||
}; | ||
if (response.status.code > 0) { | ||
// check status code as readystatechange fires before error event | ||
resolve(response); | ||
} | ||
else { | ||
// give the error callback a chance to fire before resolving | ||
// requests for file:// URLs do not have a status code | ||
setTimeout(function () { | ||
resolve(response); | ||
}, 0); | ||
} | ||
} | ||
client.onreadystatechange = function (/* e */) { | ||
if (request.canceled) { return; } | ||
if (client.readyState === (XHR.DONE || 4)) { | ||
response.status = { | ||
code: client.status, | ||
text: client.statusText | ||
}; | ||
response.headers = parseHeaders(client.getAllResponseHeaders()); | ||
response.entity = client.responseText; | ||
try { | ||
client.onerror = function (/* e */) { | ||
response.error = 'loaderror'; | ||
reject(response); | ||
}; | ||
// #125 -- Sometimes IE8-9 uses 1223 instead of 204 | ||
// http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request | ||
if (response.status.code === 1223) { | ||
response.status.code = 204; | ||
} | ||
catch (e) { | ||
// IE 6 will not support error handling | ||
if (response.status.code > 0) { | ||
// check status code as readystatechange fires before error event | ||
resolve(response); | ||
} | ||
else { | ||
// give the error callback a chance to fire before resolving | ||
// requests for file:// URLs do not have a status code | ||
setTimeout(function () { | ||
resolve(response); | ||
}, 0); | ||
} | ||
} | ||
}; | ||
client.send(entity); | ||
} | ||
catch (e) { | ||
try { | ||
client.onerror = function (/* e */) { | ||
response.error = 'loaderror'; | ||
reject(response); | ||
} | ||
}; | ||
} | ||
catch (e) { | ||
// IE 6 will not support error handling | ||
} | ||
}); | ||
}); | ||
client.send(entity); | ||
} | ||
catch (e) { | ||
response.error = 'loaderror'; | ||
reject(response); | ||
} | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }, | ||
typeof window !== 'undefined' ? window : void 0 | ||
// Boilerplate for AMD and Node | ||
)); | ||
}); |
@@ -8,3 +8,2 @@ # Clients | ||
- [JSONP Client](#module-rest/client/jsonp) | ||
- [IE XDomainRequest Client](#module-rest/client/xdr) | ||
@@ -48,3 +47,3 @@ | ||
The default client for browsers. The XHR client utilizes the XMLHttpRequest object provided by many browsers. Most every browser has direct support for XHR today. The `rest/interceptor/ie/xhr` interceptor can provided fall back support for older IE without native XHR. | ||
The default client for browsers. The XHR client utilizes the XMLHttpRequest object provided by many browsers. | ||
@@ -141,18 +140,1 @@ **Special Properties** | ||
</table> | ||
<a name="module-rest/client/xdr"></a> | ||
### IE XDomainRequest Client | ||
`rest/client/xdr` ([src](../client/xdr.js)) | ||
Cross-origin support available within IE, in particular IE 8 and 9. This client is typically employed via the `rest/interceptor/ie/xdomain` interceptor. Never used as the default client. | ||
**Know limitations** | ||
- only GET and POST methods are available | ||
- must use same scheme as origin http-to-http, https-to-https | ||
- no headers, request or response (the response Content-Type is available) | ||
- no response status code | ||
[Limitation details](http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx) |
@@ -12,2 +12,3 @@ # Interceptors | ||
- [Template Interceptor](#module-rest/interceptor/template) | ||
- [Params Interceptor](#module-rest/interceptor/params) | ||
- [Authentication Interceptors](#interceptor-provided-auth) | ||
@@ -23,4 +24,2 @@ - [Basic Auth Interceptor](#module-rest/interceptor/basicAuth) | ||
- [JSONP Interceptor](#module-rest/interceptor/jsonp) | ||
- [Cross Domain Request for IE Interceptor](#module-rest/interceptor/ie/xdomain) | ||
- [ActiveX XHR for IE Interceptor](#module-rest/interceptor/ie/xhr) | ||
- [Custom Interceptors](#interceptor-custom) | ||
@@ -38,3 +37,2 @@ - [Interceptor Best Practices](#interceptor-custom-practices) | ||
- [Async Request/Response](#interceptor-custom-concepts-async) | ||
- [Override Parent Client (ComplexRequest)](#interceptor-custom-concepts-parent) | ||
- [Abort Request (ComplexRequest)](#interceptor-custom-concepts-abort) | ||
@@ -437,4 +435,2 @@ | ||
Note: primitive templating is provided by `rest/UrlBuilder`, however, its behavior is non-standard and less powerful. | ||
**Phases** | ||
@@ -478,2 +474,45 @@ | ||
<a name="module-rest/interceptor/params"></a> | ||
#### Params Interceptor | ||
`rest/interceptor/template` ([src](../interceptor/params.js)) | ||
**Deprecated** | ||
The params interceptor expands token in the path defined by the param named wrapped in curly braces. Unbound params are appended to the end of the path as a query string. The params object is consumed by this interceptor. | ||
The [Template Interceptor](#module-rest/interceptor/template) is recommended instead of this interceptor. It is more powerful and flexible. | ||
**Phases** | ||
- request | ||
**Configuration** | ||
<table> | ||
<tr> | ||
<th>Property</th> | ||
<th>Required?</th> | ||
<th>Default</th> | ||
<th>Description</th> | ||
</tr> | ||
<tr> | ||
<td>params</td> | ||
<td>optional</td> | ||
<td><em>empty object</em></td> | ||
<td>default params to be combined with request.params</td> | ||
</tr> | ||
</table> | ||
**Example** | ||
```javascript | ||
client = rest.wrap(params, { params: { lang: 'en-us' } }); | ||
client({ path: '/dictionary/{term}', params: { term: 'hypermedia' } }).then(function (response) { | ||
assert.same('/dictionary/hypermedia?lang=en-us', response.request.path); | ||
assert.same(undefined, response.request.params); | ||
}); | ||
``` | ||
<a name="interceptor-provided-auth"></a> | ||
@@ -897,54 +936,2 @@ ### Authentication Interceptors | ||
<a name="module-rest/interceptor/ie/xdomain"></a> | ||
#### Cross Domain Request for IE Interceptor | ||
`rest/interceptor/ie/xdomain` ([src](../interceptor/ie/xdomain.js)) | ||
Utilizes IE's XDomainRequest support via the [XDomainRequest client](clients.md#module-rest/client/xdr) for making cross origin requests if needed, available and a CORS enabled XMLHttpRequest is not available. XDR request have a number of limitations, see the [XDR client](clients.md#module-rest/client/xdr) for limitation details. Will not interfere if installed in other environments. | ||
This interceptor should be installed as close to the root of the interceptor chain as possible. When a XDomainRequest client is needed, the normal parent client will not be invoked. | ||
**Phases** | ||
- request | ||
**Configuration** | ||
*none* | ||
**Example** | ||
```javascript | ||
client = rest.wrap(xdomain) | ||
.wrap(defaultRequest, { params: { api_key: '95f41bfa4faa0f43bf7c24795eabbed4', format: 'rest' } }); | ||
client({ params: { method: 'flickr.test.echo' } }).then(function (response) { | ||
// response from flickr | ||
}); | ||
``` | ||
<a name="module-rest/interceptor/ie/xhr"></a> | ||
#### ActiveX XHR for IE Interceptor | ||
`rest/interceptor/ie/xhr` ([src](../interceptor/ie/xhr.js)) | ||
Attempts to use an ActiveX XHR replacement if a native XMLHttpRequest object is not available. Useful for IE < 9, which does not natively support XMLHttpRequest. Will not interfere if installed in other environments. | ||
**Phases** | ||
- request | ||
**Configuration** | ||
*none* | ||
**Example** | ||
```javascript | ||
client = rest.wrap(xhr); | ||
client({}).then(function (response) { | ||
// normal XHR response, even in IE without XHR | ||
}); | ||
``` | ||
<a name="interceptor-custom"></a> | ||
@@ -1165,7 +1152,2 @@ ## Custom Interceptors | ||
<a name="interceptor-custom-concepts-parent"></a> | ||
**Override Parent Client (ComplexRequest)** | ||
- [rest/interceptor/ie/xdomain](#module-rest/interceptor/ie/xdomain) | ||
<a name="interceptor-custom-concepts-abort"></a> | ||
@@ -1172,0 +1154,0 @@ **Abort Request (ComplexRequest)** |
/* | ||
* Copyright 2012-2015 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,159 +8,139 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var defaultClient, mixin, responsePromise, client; | ||
var defaultClient, mixin, responsePromise, client, when; | ||
defaultClient = require('./client/default'); | ||
mixin = require('./util/mixin'); | ||
responsePromise = require('./util/responsePromise'); | ||
client = require('./client'); | ||
defaultClient = require('./client/default'); | ||
mixin = require('./util/mixin'); | ||
responsePromise = require('./util/responsePromise'); | ||
client = require('./client'); | ||
when = require('when'); | ||
/** | ||
* Interceptors have the ability to intercept the request and/org response | ||
* objects. They may augment, prune, transform or replace the | ||
* request/response as needed. Clients may be composed by wrapping | ||
* together multiple interceptors. | ||
* | ||
* Configured interceptors are functional in nature. Wrapping a client in | ||
* an interceptor will not affect the client, merely the data that flows in | ||
* and out of that client. A common configuration can be created once and | ||
* shared; specialization can be created by further wrapping that client | ||
* with custom interceptors. | ||
* | ||
* @param {Client} [target] client to wrap | ||
* @param {Object} [config] configuration for the interceptor, properties will be specific to the interceptor implementation | ||
* @returns {Client} A client wrapped with the interceptor | ||
* | ||
* @class Interceptor | ||
*/ | ||
/** | ||
* Interceptors have the ability to intercept the request and/org response | ||
* objects. They may augment, prune, transform or replace the | ||
* request/response as needed. Clients may be composed by wrapping | ||
* together multiple interceptors. | ||
* | ||
* Configured interceptors are functional in nature. Wrapping a client in | ||
* an interceptor will not affect the client, merely the data that flows in | ||
* and out of that client. A common configuration can be created once and | ||
* shared; specialization can be created by further wrapping that client | ||
* with custom interceptors. | ||
* | ||
* @param {Client} [target] client to wrap | ||
* @param {Object} [config] configuration for the interceptor, properties will be specific to the interceptor implementation | ||
* @returns {Client} A client wrapped with the interceptor | ||
* | ||
* @class Interceptor | ||
*/ | ||
function defaultInitHandler(config) { | ||
return config; | ||
} | ||
function defaultInitHandler(config) { | ||
return config; | ||
} | ||
function defaultRequestHandler(request /*, config, meta */) { | ||
return request; | ||
} | ||
function defaultRequestHandler(request /*, config, meta */) { | ||
return request; | ||
} | ||
function defaultResponseHandler(response /*, config, meta */) { | ||
return response; | ||
} | ||
function defaultResponseHandler(response /*, config, meta */) { | ||
return response; | ||
} | ||
/** | ||
* Alternate return type for the request handler that allows for more complex interactions. | ||
* | ||
* @param properties.request the traditional request return object | ||
* @param {Promise} [properties.abort] promise that resolves if/when the request is aborted | ||
* @param {Client} [properties.client] override the defined client with an alternate client | ||
* @param [properties.response] response for the request, short circuit the request | ||
*/ | ||
function ComplexRequest(properties) { | ||
if (!(this instanceof ComplexRequest)) { | ||
// in case users forget the 'new' don't mix into the interceptor | ||
return new ComplexRequest(properties); | ||
} | ||
mixin(this, properties); | ||
} | ||
function race(promisesOrValues) { | ||
// this function is different than when.any as the first to reject also wins | ||
return when.promise(function (resolve, reject) { | ||
promisesOrValues.forEach(function (promiseOrValue) { | ||
when(promiseOrValue, resolve, reject); | ||
}); | ||
}); | ||
} | ||
/** | ||
* Create a new interceptor for the provided handlers. | ||
* | ||
* @param {Function} [handlers.init] one time intialization, must return the config object | ||
* @param {Function} [handlers.request] request handler | ||
* @param {Function} [handlers.response] response handler regardless of error state | ||
* @param {Function} [handlers.success] response handler when the request is not in error | ||
* @param {Function} [handlers.error] response handler when the request is in error, may be used to 'unreject' an error state | ||
* @param {Function} [handlers.client] the client to use if otherwise not specified, defaults to platform default client | ||
* | ||
* @returns {Interceptor} | ||
*/ | ||
function interceptor(handlers) { | ||
/** | ||
* Alternate return type for the request handler that allows for more complex interactions. | ||
* | ||
* @param properties.request the traditional request return object | ||
* @param {Promise} [properties.abort] promise that resolves if/when the request is aborted | ||
* @param {Client} [properties.client] override the defined client with an alternate client | ||
* @param [properties.response] response for the request, short circuit the request | ||
*/ | ||
function ComplexRequest(properties) { | ||
if (!(this instanceof ComplexRequest)) { | ||
// in case users forget the 'new' don't mix into the interceptor | ||
return new ComplexRequest(properties); | ||
} | ||
mixin(this, properties); | ||
} | ||
var initHandler, requestHandler, successResponseHandler, errorResponseHandler; | ||
/** | ||
* Create a new interceptor for the provided handlers. | ||
* | ||
* @param {Function} [handlers.init] one time intialization, must return the config object | ||
* @param {Function} [handlers.request] request handler | ||
* @param {Function} [handlers.response] response handler regardless of error state | ||
* @param {Function} [handlers.success] response handler when the request is not in error | ||
* @param {Function} [handlers.error] response handler when the request is in error, may be used to 'unreject' an error state | ||
* @param {Function} [handlers.client] the client to use if otherwise not specified, defaults to platform default client | ||
* | ||
* @returns {Interceptor} | ||
*/ | ||
function interceptor(handlers) { | ||
handlers = handlers || {}; | ||
var initHandler, requestHandler, successResponseHandler, errorResponseHandler; | ||
initHandler = handlers.init || defaultInitHandler; | ||
requestHandler = handlers.request || defaultRequestHandler; | ||
successResponseHandler = handlers.success || handlers.response || defaultResponseHandler; | ||
errorResponseHandler = handlers.error || function () { | ||
// Propagate the rejection, with the result of the handler | ||
return Promise.resolve((handlers.response || defaultResponseHandler).apply(this, arguments)) | ||
.then(Promise.reject.bind(Promise)); | ||
}; | ||
handlers = handlers || {}; | ||
return function (target, config) { | ||
initHandler = handlers.init || defaultInitHandler; | ||
requestHandler = handlers.request || defaultRequestHandler; | ||
successResponseHandler = handlers.success || handlers.response || defaultResponseHandler; | ||
errorResponseHandler = handlers.error || function () { | ||
// Propagate the rejection, with the result of the handler | ||
return when((handlers.response || defaultResponseHandler).apply(this, arguments), when.reject, when.reject); | ||
}; | ||
if (typeof target === 'object') { | ||
config = target; | ||
} | ||
if (typeof target !== 'function') { | ||
target = handlers.client || defaultClient; | ||
} | ||
return function (target, config) { | ||
config = initHandler(config || {}); | ||
if (typeof target === 'object') { | ||
config = target; | ||
} | ||
if (typeof target !== 'function') { | ||
target = handlers.client || defaultClient; | ||
} | ||
config = initHandler(config || {}); | ||
function interceptedClient(request) { | ||
var context, meta; | ||
context = {}; | ||
meta = { 'arguments': Array.prototype.slice.call(arguments), client: interceptedClient }; | ||
request = typeof request === 'string' ? { path: request } : request || {}; | ||
request.originator = request.originator || interceptedClient; | ||
return responsePromise( | ||
requestHandler.call(context, request, config, meta), | ||
function (request) { | ||
var response, abort, next; | ||
next = target; | ||
if (request instanceof ComplexRequest) { | ||
// unpack request | ||
abort = request.abort; | ||
next = request.client || next; | ||
response = request.response; | ||
// normalize request, must be last | ||
request = request.request; | ||
function interceptedClient(request) { | ||
var context, meta; | ||
context = {}; | ||
meta = { 'arguments': Array.prototype.slice.call(arguments), client: interceptedClient }; | ||
request = typeof request === 'string' ? { path: request } : request || {}; | ||
request.originator = request.originator || interceptedClient; | ||
return responsePromise( | ||
requestHandler.call(context, request, config, meta), | ||
function (request) { | ||
var response, abort, next; | ||
next = target; | ||
if (request instanceof ComplexRequest) { | ||
// unpack request | ||
abort = request.abort; | ||
next = request.client || next; | ||
response = request.response; | ||
// normalize request, must be last | ||
request = request.request; | ||
} | ||
response = response || Promise.resolve(request).then(function (request) { | ||
return Promise.resolve(next(request)).then( | ||
function (response) { | ||
return successResponseHandler.call(context, response, config, meta); | ||
}, | ||
function (response) { | ||
return errorResponseHandler.call(context, response, config, meta); | ||
} | ||
response = response || when(request, function (request) { | ||
return when( | ||
next(request), | ||
function (response) { | ||
return successResponseHandler.call(context, response, config, meta); | ||
}, | ||
function (response) { | ||
return errorResponseHandler.call(context, response, config, meta); | ||
} | ||
); | ||
}); | ||
return abort ? race([response, abort]) : response; | ||
}, | ||
function (error) { | ||
return when.reject({ request: request, error: error }); | ||
} | ||
); | ||
); | ||
}); | ||
return abort ? Promise.race([response, abort]) : response; | ||
}, | ||
function (error) { | ||
return Promise.reject({ request: request, error: error }); | ||
} | ||
return client(interceptedClient, target); | ||
}; | ||
); | ||
} | ||
interceptor.ComplexRequest = ComplexRequest; | ||
return client(interceptedClient, target); | ||
}; | ||
} | ||
return interceptor; | ||
interceptor.ComplexRequest = ComplexRequest; | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
module.exports = interceptor; |
/* | ||
* Copyright 2012-2013 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,42 +8,32 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var interceptor, base64; | ||
var interceptor, base64; | ||
interceptor = require('../interceptor'); | ||
base64 = require('../util/base64'); | ||
interceptor = require('../interceptor'); | ||
base64 = require('../util/base64'); | ||
/** | ||
* Authenticates the request using HTTP Basic Authentication (rfc2617) | ||
* | ||
* @param {Client} [client] client to wrap | ||
* @param {string} config.username username | ||
* @param {string} [config.password=''] password for the user | ||
* | ||
* @returns {Client} | ||
*/ | ||
module.exports = interceptor({ | ||
request: function handleRequest(request, config) { | ||
var headers, username, password; | ||
/** | ||
* Authenticates the request using HTTP Basic Authentication (rfc2617) | ||
* | ||
* @param {Client} [client] client to wrap | ||
* @param {string} config.username username | ||
* @param {string} [config.password=''] password for the user | ||
* | ||
* @returns {Client} | ||
*/ | ||
return interceptor({ | ||
request: function handleRequest(request, config) { | ||
var headers, username, password; | ||
headers = request.headers || (request.headers = {}); | ||
username = request.username || config.username; | ||
password = request.password || config.password || ''; | ||
headers = request.headers || (request.headers = {}); | ||
username = request.username || config.username; | ||
password = request.password || config.password || ''; | ||
if (username) { | ||
headers.Authorization = 'Basic ' + base64.encode(username + ':' + password); | ||
} | ||
if (username) { | ||
headers.Authorization = 'Basic ' + base64.encode(username + ':' + password); | ||
} | ||
return request; | ||
} | ||
}); | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
return request; | ||
} | ||
}); |
/* | ||
* Copyright 2013 the original author or authors | ||
* Copyright 2013-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,55 +8,45 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var interceptor; | ||
var interceptor; | ||
interceptor = require('../interceptor'); | ||
interceptor = require('../interceptor'); | ||
/** | ||
* Applies a Cross-Site Request Forgery protection header to a request | ||
* | ||
* CSRF protection helps a server verify that a request came from a | ||
* trusted client and not another client that was able to masquerade | ||
* as an authorized client. Sites that use cookie based authentication | ||
* are particularly vulnerable to request forgeries without extra | ||
* protection. | ||
* | ||
* @see http://en.wikipedia.org/wiki/Cross-site_request_forgery | ||
* | ||
* @param {Client} [client] client to wrap | ||
* @param {string} [config.name='X-Csrf-Token'] name of the request | ||
* header, may be overridden by `request.csrfTokenName` | ||
* @param {string} [config.token] CSRF token, may be overridden by | ||
* `request.csrfToken` | ||
* | ||
* @returns {Client} | ||
*/ | ||
module.exports = interceptor({ | ||
init: function (config) { | ||
config.name = config.name || 'X-Csrf-Token'; | ||
return config; | ||
}, | ||
request: function handleRequest(request, config) { | ||
var headers, name, token; | ||
/** | ||
* Applies a Cross-Site Request Forgery protection header to a request | ||
* | ||
* CSRF protection helps a server verify that a request came from a | ||
* trusted client and not another client that was able to masquerade | ||
* as an authorized client. Sites that use cookie based authentication | ||
* are particularly vulnerable to request forgeries without extra | ||
* protection. | ||
* | ||
* @see http://en.wikipedia.org/wiki/Cross-site_request_forgery | ||
* | ||
* @param {Client} [client] client to wrap | ||
* @param {string} [config.name='X-Csrf-Token'] name of the request | ||
* header, may be overridden by `request.csrfTokenName` | ||
* @param {string} [config.token] CSRF token, may be overridden by | ||
* `request.csrfToken` | ||
* | ||
* @returns {Client} | ||
*/ | ||
return interceptor({ | ||
init: function (config) { | ||
config.name = config.name || 'X-Csrf-Token'; | ||
return config; | ||
}, | ||
request: function handleRequest(request, config) { | ||
var headers, name, token; | ||
headers = request.headers || (request.headers = {}); | ||
name = request.csrfTokenName || config.name; | ||
token = request.csrfToken || config.token; | ||
headers = request.headers || (request.headers = {}); | ||
name = request.csrfTokenName || config.name; | ||
token = request.csrfToken || config.token; | ||
if (token) { | ||
headers[name] = token; | ||
} | ||
if (token) { | ||
headers[name] = token; | ||
} | ||
return request; | ||
} | ||
}); | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
return request; | ||
} | ||
}); |
/* | ||
* Copyright 2013 the original author or authors | ||
* Copyright 2013-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,73 +8,63 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var interceptor, mixinUtil, defaulter; | ||
var interceptor, mixinUtil, defaulter; | ||
interceptor = require('../interceptor'); | ||
mixinUtil = require('../util/mixin'); | ||
interceptor = require('../interceptor'); | ||
mixinUtil = require('../util/mixin'); | ||
defaulter = (function () { | ||
defaulter = (function () { | ||
function mixin(prop, target, defaults) { | ||
if (prop in target || prop in defaults) { | ||
target[prop] = mixinUtil({}, defaults[prop], target[prop]); | ||
} | ||
} | ||
function mixin(prop, target, defaults) { | ||
if (prop in target || prop in defaults) { | ||
target[prop] = mixinUtil({}, defaults[prop], target[prop]); | ||
} | ||
} | ||
function copy(prop, target, defaults) { | ||
if (prop in defaults && !(prop in target)) { | ||
target[prop] = defaults[prop]; | ||
} | ||
} | ||
function copy(prop, target, defaults) { | ||
if (prop in defaults && !(prop in target)) { | ||
target[prop] = defaults[prop]; | ||
} | ||
} | ||
var mappings = { | ||
method: copy, | ||
path: copy, | ||
params: mixin, | ||
headers: mixin, | ||
entity: copy, | ||
mixin: mixin | ||
}; | ||
var mappings = { | ||
method: copy, | ||
path: copy, | ||
params: mixin, | ||
headers: mixin, | ||
entity: copy, | ||
mixin: mixin | ||
}; | ||
return function (target, defaults) { | ||
for (var prop in mappings) { | ||
/*jshint forin: false */ | ||
mappings[prop](prop, target, defaults); | ||
} | ||
return target; | ||
}; | ||
return function (target, defaults) { | ||
for (var prop in mappings) { | ||
/*jshint forin: false */ | ||
mappings[prop](prop, target, defaults); | ||
} | ||
return target; | ||
}; | ||
}()); | ||
}()); | ||
/** | ||
* Provide default values for a request. These values will be applied to the | ||
* request if the request object does not already contain an explicit value. | ||
* | ||
* For 'params', 'headers', and 'mixin', individual values are mixed in with the | ||
* request's values. The result is a new object representiing the combined | ||
* request and config values. Neither input object is mutated. | ||
* | ||
* @param {Client} [client] client to wrap | ||
* @param {string} [config.method] the default method | ||
* @param {string} [config.path] the default path | ||
* @param {Object} [config.params] the default params, mixed with the request's existing params | ||
* @param {Object} [config.headers] the default headers, mixed with the request's existing headers | ||
* @param {Object} [config.mixin] the default "mixins" (http/https options), mixed with the request's existing "mixins" | ||
* | ||
* @returns {Client} | ||
*/ | ||
return interceptor({ | ||
request: function handleRequest(request, config) { | ||
return defaulter(request, config); | ||
} | ||
}); | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
/** | ||
* Provide default values for a request. These values will be applied to the | ||
* request if the request object does not already contain an explicit value. | ||
* | ||
* For 'params', 'headers', and 'mixin', individual values are mixed in with the | ||
* request's values. The result is a new object representiing the combined | ||
* request and config values. Neither input object is mutated. | ||
* | ||
* @param {Client} [client] client to wrap | ||
* @param {string} [config.method] the default method | ||
* @param {string} [config.path] the default path | ||
* @param {Object} [config.params] the default params, mixed with the request's existing params | ||
* @param {Object} [config.headers] the default headers, mixed with the request's existing headers | ||
* @param {Object} [config.mixin] the default "mixins" (http/https options), mixed with the request's existing "mixins" | ||
* | ||
* @returns {Client} | ||
*/ | ||
module.exports = interceptor({ | ||
request: function handleRequest(request, config) { | ||
return defaulter(request, config); | ||
} | ||
}); |
/* | ||
* Copyright 2012-2014 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,39 +8,29 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var interceptor; | ||
var interceptor; | ||
interceptor = require('../interceptor'); | ||
interceptor = require('../interceptor'); | ||
if (typeof console !== 'undefined') { | ||
console.log('rest.js: rest/interceptor/entity is deprecated, please use response.entity() instead'); | ||
} | ||
if (typeof console !== 'undefined') { | ||
console.log('rest.js: rest/interceptor/entity is deprecated, please use response.entity() instead'); | ||
/** | ||
* @deprecated use response.entity() instead | ||
* | ||
* Returns the response entity as the response, discarding other response | ||
* properties. | ||
* | ||
* @param {Client} [client] client to wrap | ||
* | ||
* @returns {Client} | ||
*/ | ||
module.exports = interceptor({ | ||
response: function (response) { | ||
if ('entity' in response) { | ||
return response.entity; | ||
} | ||
/** | ||
* @deprecated use response.entity() instead | ||
* | ||
* Returns the response entity as the response, discarding other response | ||
* properties. | ||
* | ||
* @param {Client} [client] client to wrap | ||
* | ||
* @returns {Client} | ||
*/ | ||
return interceptor({ | ||
response: function (response) { | ||
if ('entity' in response) { | ||
return response.entity; | ||
} | ||
return response; | ||
} | ||
}); | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
return response; | ||
} | ||
}); |
/* | ||
* Copyright 2012-2013 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,41 +8,30 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var interceptor; | ||
var interceptor, when; | ||
interceptor = require('../interceptor'); | ||
interceptor = require('../interceptor'); | ||
when = require('when'); | ||
/** | ||
* Rejects the response promise based on the status code. | ||
* | ||
* Codes greater than or equal to the provided value are rejected. Default | ||
* value 400. | ||
* | ||
* @param {Client} [client] client to wrap | ||
* @param {number} [config.code=400] code to indicate a rejection | ||
* | ||
* @returns {Client} | ||
*/ | ||
return interceptor({ | ||
init: function (config) { | ||
config.code = config.code || 400; | ||
return config; | ||
}, | ||
response: function (response, config) { | ||
if (response.status && response.status.code >= config.code) { | ||
return when.reject(response); | ||
} | ||
return response; | ||
} | ||
}); | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
/** | ||
* Rejects the response promise based on the status code. | ||
* | ||
* Codes greater than or equal to the provided value are rejected. Default | ||
* value 400. | ||
* | ||
* @param {Client} [client] client to wrap | ||
* @param {number} [config.code=400] code to indicate a rejection | ||
* | ||
* @returns {Client} | ||
*/ | ||
module.exports = interceptor({ | ||
init: function (config) { | ||
config.code = config.code || 400; | ||
return config; | ||
}, | ||
response: function (response, config) { | ||
if (response.status && response.status.code >= config.code) { | ||
return Promise.reject(response); | ||
} | ||
return response; | ||
} | ||
}); |
/* | ||
* Copyright 2012-2013 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,142 +8,132 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var interceptor, pathPrefix, rfc5988LinkParser, find; | ||
var interceptor, pathPrefix, rfc5988LinkParser, find; | ||
interceptor = require('../interceptor'); | ||
pathPrefix = require('./pathPrefix'); | ||
rfc5988LinkParser = require('../parsers/rfc5988'); | ||
find = require('../util/find'); | ||
interceptor = require('../interceptor'); | ||
pathPrefix = require('./pathPrefix'); | ||
rfc5988LinkParser = require('../parsers/rfc5988'); | ||
find = require('../util/find'); | ||
/** | ||
* [Experimental] | ||
* | ||
* Supports 'Hypertext As The Engine Of Application State' style | ||
* services by indexing the 'links' property from the entity to make | ||
* accessing links via the 'rel' attribute easier. | ||
* | ||
* Links are index in two ways: | ||
* 1. as link's 'rel' which when accessed issues a request for the | ||
* linked resource. A promise for the related resourse is expected | ||
* to be returned. | ||
* 2. as link's 'rel' with 'Link' appended, as a reference to the link | ||
* object | ||
* | ||
* The 'Link' response header is also parsed for related resources | ||
* following rfc5988. The values parsed from the headers are indexed | ||
* into the response.links object. | ||
* | ||
* Also defines a 'clientFor' factory function that creates a new | ||
* client configured to communicate with a related resource. | ||
* | ||
* The client for the resoruce reference and the 'clientFor' function | ||
* can be provided by the 'client' config property. | ||
* | ||
* Index links are exposed by default on the entity. A child object may be | ||
* configed by the 'target' config property. | ||
* | ||
* @param {Client} [client] client to wrap | ||
* @param {string} [config.target=''] property to create on the entity and | ||
* parse links into. If empty, the response entity is used directly. | ||
* @param {Client} [config.client=request.originator] the parent client to | ||
* use when creating clients for a linked resources. Defaults to the | ||
* request's originator if available, otherwise the current interceptor's | ||
* client | ||
* | ||
* @returns {Client} | ||
*/ | ||
module.exports = interceptor({ | ||
init: function (config) { | ||
config.target = config.target || ''; | ||
return config; | ||
}, | ||
response: function (response, config, meta) { | ||
var client; | ||
/** | ||
* [Experimental] | ||
* | ||
* Supports 'Hypertext As The Engine Of Application State' style | ||
* services by indexing the 'links' property from the entity to make | ||
* accessing links via the 'rel' attribute easier. | ||
* | ||
* Links are index in two ways: | ||
* 1. as link's 'rel' which when accessed issues a request for the | ||
* linked resource. A promise for the related resourse is expected | ||
* to be returned. | ||
* 2. as link's 'rel' with 'Link' appended, as a reference to the link | ||
* object | ||
* | ||
* The 'Link' response header is also parsed for related resources | ||
* following rfc5988. The values parsed from the headers are indexed | ||
* into the response.links object. | ||
* | ||
* Also defines a 'clientFor' factory function that creates a new | ||
* client configured to communicate with a related resource. | ||
* | ||
* The client for the resoruce reference and the 'clientFor' function | ||
* can be provided by the 'client' config property. | ||
* | ||
* Index links are exposed by default on the entity. A child object may be | ||
* configed by the 'target' config property. | ||
* | ||
* @param {Client} [client] client to wrap | ||
* @param {string} [config.target=''] property to create on the entity and | ||
* parse links into. If empty, the response entity is used directly. | ||
* @param {Client} [config.client=request.originator] the parent client to | ||
* use when creating clients for a linked resources. Defaults to the | ||
* request's originator if available, otherwise the current interceptor's | ||
* client | ||
* | ||
* @returns {Client} | ||
*/ | ||
return interceptor({ | ||
init: function (config) { | ||
config.target = config.target || ''; | ||
return config; | ||
}, | ||
response: function (response, config, meta) { | ||
var client; | ||
client = config.client || (response.request && response.request.originator) || meta.client; | ||
client = config.client || (response.request && response.request.originator) || meta.client; | ||
function apply(target, links) { | ||
links.forEach(function (link) { | ||
Object.defineProperty(target, link.rel + 'Link', { | ||
enumerable: false, | ||
configurable: true, | ||
value: link | ||
}); | ||
function apply(target, links) { | ||
links.forEach(function (link) { | ||
Object.defineProperty(target, link.rel + 'Link', { | ||
enumerable: false, | ||
configurable: true, | ||
value: link | ||
}); | ||
Object.defineProperty(target, link.rel, { | ||
enumerable: false, | ||
configurable: true, | ||
get: function () { | ||
var response = client({ path: link.href }); | ||
Object.defineProperty(target, link.rel, { | ||
enumerable: false, | ||
configurable: true, | ||
get: function () { | ||
var response = client({ path: link.href }); | ||
Object.defineProperty(target, link.rel, { | ||
enumerable: false, | ||
configurable: true, | ||
value: response | ||
}); | ||
return response; | ||
} | ||
value: response | ||
}); | ||
}); | ||
return response; | ||
} | ||
}); | ||
}); | ||
// if only Proxy was well supported... | ||
Object.defineProperty(target, 'clientFor', { | ||
enumerable: false, | ||
value: function clientFor(rel, parentClient) { | ||
return pathPrefix( | ||
parentClient || client, | ||
{ prefix: target[rel + 'Link'].href } | ||
); | ||
} | ||
}); | ||
// if only Proxy was well supported... | ||
Object.defineProperty(target, 'clientFor', { | ||
enumerable: false, | ||
value: function clientFor(rel, parentClient) { | ||
return pathPrefix( | ||
parentClient || client, | ||
{ prefix: target[rel + 'Link'].href } | ||
); | ||
} | ||
}); | ||
} | ||
function parseLinkHeaders(headers) { | ||
var links = []; | ||
[].concat(headers).forEach(function (header) { | ||
try { | ||
links = links.concat(rfc5988LinkParser.parse(header)); | ||
} | ||
catch (e) { | ||
// ignore | ||
// TODO consider a debug mode that logs | ||
} | ||
}); | ||
return links; | ||
function parseLinkHeaders(headers) { | ||
var links = []; | ||
[].concat(headers).forEach(function (header) { | ||
try { | ||
links = links.concat(rfc5988LinkParser.parse(header)); | ||
} | ||
if (response.headers && response.headers.Link) { | ||
response.links = response.links || {}; | ||
apply(response.links, parseLinkHeaders(response.headers.Link)); | ||
catch (e) { | ||
// ignore | ||
// TODO consider a debug mode that logs | ||
} | ||
}); | ||
return links; | ||
} | ||
find.findProperties(response.entity, 'links', function (obj, host) { | ||
var target; | ||
if (response.headers && response.headers.Link) { | ||
response.links = response.links || {}; | ||
apply(response.links, parseLinkHeaders(response.headers.Link)); | ||
} | ||
if (Array.isArray(host.links)) { | ||
if (config.target === '') { | ||
target = host; | ||
} | ||
else { | ||
target = {}; | ||
Object.defineProperty(host, config.target, { | ||
enumerable: false, | ||
value: target | ||
}); | ||
} | ||
find.findProperties(response.entity, 'links', function (obj, host) { | ||
var target; | ||
apply(target, host.links); | ||
} | ||
}); | ||
if (Array.isArray(host.links)) { | ||
if (config.target === '') { | ||
target = host; | ||
} | ||
else { | ||
target = {}; | ||
Object.defineProperty(host, config.target, { | ||
enumerable: false, | ||
value: target | ||
}); | ||
} | ||
return response; | ||
apply(target, host.links); | ||
} | ||
}); | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
return response; | ||
} | ||
}); |
/* | ||
* Copyright 2012-2013 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,53 +8,43 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var interceptor, jsonpClient; | ||
var interceptor, jsonpClient; | ||
interceptor = require('../interceptor'); | ||
jsonpClient = require('../client/jsonp'); | ||
interceptor = require('../interceptor'); | ||
jsonpClient = require('../client/jsonp'); | ||
/** | ||
* Allows common configuration of JSONP clients. | ||
* | ||
* Values provided to this interceptor are added to the request, if the | ||
* request dose not already contain the property. | ||
* | ||
* The rest/client/jsonp client is used by default instead of the | ||
* common default client for the platform. | ||
* | ||
* @param {Client} [client=rest/client/jsonp] custom client to wrap | ||
* @param {string} [config.callback.param] the parameter name for which the | ||
* callback function name is the value | ||
* @param {string} [config.callback.prefix] prefix for the callback function, | ||
* as the callback is attached to the window object, a unique, unobtrusive | ||
* prefix is desired | ||
* @param {string} [request.callback.name=<generated>] pins the name of the | ||
* callback function, useful for cases where the server doesn't allow | ||
* custom callback names. Generally not recommended. | ||
* | ||
* @returns {Client} | ||
*/ | ||
return interceptor({ | ||
client: jsonpClient, | ||
init: function (config) { | ||
config.callback = config.callback || {}; | ||
return config; | ||
}, | ||
request: function (request, config) { | ||
request.callback = request.callback || {}; | ||
request.callback.param = request.callback.param || config.callback.param; | ||
request.callback.prefix = request.callback.prefix || config.callback.prefix; | ||
request.callback.name = request.callback.name || config.callback.name; | ||
return request; | ||
} | ||
}); | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
/** | ||
* Allows common configuration of JSONP clients. | ||
* | ||
* Values provided to this interceptor are added to the request, if the | ||
* request dose not already contain the property. | ||
* | ||
* The rest/client/jsonp client is used by default instead of the | ||
* common default client for the platform. | ||
* | ||
* @param {Client} [client=rest/client/jsonp] custom client to wrap | ||
* @param {string} [config.callback.param] the parameter name for which the | ||
* callback function name is the value | ||
* @param {string} [config.callback.prefix] prefix for the callback function, | ||
* as the callback is attached to the window object, a unique, unobtrusive | ||
* prefix is desired | ||
* @param {string} [request.callback.name=<generated>] pins the name of the | ||
* callback function, useful for cases where the server doesn't allow | ||
* custom callback names. Generally not recommended. | ||
* | ||
* @returns {Client} | ||
*/ | ||
module.exports = interceptor({ | ||
client: jsonpClient, | ||
init: function (config) { | ||
config.callback = config.callback || {}; | ||
return config; | ||
}, | ||
request: function (request, config) { | ||
request.callback = request.callback || {}; | ||
request.callback.param = request.callback.param || config.callback.param; | ||
request.callback.prefix = request.callback.prefix || config.callback.prefix; | ||
request.callback.name = request.callback.name || config.callback.name; | ||
return request; | ||
} | ||
}); |
/* | ||
* Copyright 2012-2013 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,55 +8,45 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var interceptor; | ||
var interceptor; | ||
interceptor = require('../interceptor'); | ||
interceptor = require('../interceptor'); | ||
function isRedirect(response, config) { | ||
var matchesRedirectCode = config.code === 0 || (response.status && response.status.code >= config.code); | ||
return response.headers && response.headers.Location && matchesRedirectCode; | ||
} | ||
function isRedirect(response, config) { | ||
var matchesRedirectCode = config.code === 0 || (response.status && response.status.code >= config.code); | ||
return response.headers && response.headers.Location && matchesRedirectCode; | ||
} | ||
/** | ||
* Follows the Location header in a response, if present. The response | ||
* returned is for the subsequent request. | ||
* | ||
* Most browsers will automatically follow HTTP 3xx redirects, however, | ||
* they will not automatically follow 2xx locations. | ||
* | ||
* @param {Client} [client] client to wrap | ||
* @param {Client} [config.client=request.originator] client to use for subsequent request | ||
* | ||
* @returns {Client} | ||
*/ | ||
module.exports = interceptor({ | ||
init: function (config) { | ||
config.code = config.code || 0; | ||
return config; | ||
}, | ||
success: function (response, config, client) { | ||
var request; | ||
/** | ||
* Follows the Location header in a response, if present. The response | ||
* returned is for the subsequent request. | ||
* | ||
* Most browsers will automatically follow HTTP 3xx redirects, however, | ||
* they will not automatically follow 2xx locations. | ||
* | ||
* @param {Client} [client] client to wrap | ||
* @param {Client} [config.client=request.originator] client to use for subsequent request | ||
* | ||
* @returns {Client} | ||
*/ | ||
return interceptor({ | ||
init: function (config) { | ||
config.code = config.code || 0; | ||
return config; | ||
}, | ||
success: function (response, config, client) { | ||
var request; | ||
if (isRedirect(response, config)) { | ||
request = response.request || {}; | ||
client = (config.client || request.originator || client.skip()); | ||
if (isRedirect(response, config)) { | ||
request = response.request || {}; | ||
client = (config.client || request.originator || client.skip()); | ||
return client({ | ||
method: 'GET', | ||
path: response.headers.Location | ||
}); | ||
} | ||
return client({ | ||
method: 'GET', | ||
path: response.headers.Location | ||
}); | ||
} | ||
return response; | ||
} | ||
}); | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
return response; | ||
} | ||
}); |
/* | ||
* Copyright 2012-2014 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,104 +8,103 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var interceptor, mime, registry, noopConverter, missingConverter, attempt; | ||
var interceptor, mime, registry, noopConverter, when; | ||
interceptor = require('../interceptor'); | ||
mime = require('../mime'); | ||
registry = require('../mime/registry'); | ||
attempt = require('../util/attempt'); | ||
interceptor = require('../interceptor'); | ||
mime = require('../mime'); | ||
registry = require('../mime/registry'); | ||
when = require('when'); | ||
noopConverter = { | ||
read: function (obj) { return obj; }, | ||
write: function (obj) { return obj; } | ||
}; | ||
noopConverter = { | ||
read: function (obj) { return obj; }, | ||
write: function (obj) { return obj; } | ||
}; | ||
missingConverter = { | ||
read: function () { throw 'No read method found on converter'; }, | ||
write: function () { throw 'No write method found on converter'; } | ||
}; | ||
/** | ||
* MIME type support for request and response entities. Entities are | ||
* (de)serialized using the converter for the MIME type. | ||
* | ||
* Request entities are converted using the desired converter and the | ||
* 'Accept' request header prefers this MIME. | ||
* | ||
* Response entities are converted based on the Content-Type response header. | ||
* | ||
* @param {Client} [client] client to wrap | ||
* @param {string} [config.mime='text/plain'] MIME type to encode the request | ||
* entity | ||
* @param {string} [config.accept] Accept header for the request | ||
* @param {Client} [config.client=<request.originator>] client passed to the | ||
* converter, defaults to the client originating the request | ||
* @param {Registry} [config.registry] MIME registry, defaults to the root | ||
* registry | ||
* @param {boolean} [config.permissive] Allow an unkown request MIME type | ||
* | ||
* @returns {Client} | ||
*/ | ||
return interceptor({ | ||
init: function (config) { | ||
config.registry = config.registry || registry; | ||
return config; | ||
}, | ||
request: function (request, config) { | ||
var type, headers; | ||
/** | ||
* MIME type support for request and response entities. Entities are | ||
* (de)serialized using the converter for the MIME type. | ||
* | ||
* Request entities are converted using the desired converter and the | ||
* 'Accept' request header prefers this MIME. | ||
* | ||
* Response entities are converted based on the Content-Type response header. | ||
* | ||
* @param {Client} [client] client to wrap | ||
* @param {string} [config.mime='text/plain'] MIME type to encode the request | ||
* entity | ||
* @param {string} [config.accept] Accept header for the request | ||
* @param {Client} [config.client=<request.originator>] client passed to the | ||
* converter, defaults to the client originating the request | ||
* @param {Registry} [config.registry] MIME registry, defaults to the root | ||
* registry | ||
* @param {boolean} [config.permissive] Allow an unkown request MIME type | ||
* | ||
* @returns {Client} | ||
*/ | ||
module.exports = interceptor({ | ||
init: function (config) { | ||
config.registry = config.registry || registry; | ||
return config; | ||
}, | ||
request: function (request, config) { | ||
var type, headers; | ||
headers = request.headers || (request.headers = {}); | ||
type = mime.parse(headers['Content-Type'] = headers['Content-Type'] || config.mime || 'text/plain'); | ||
headers.Accept = headers.Accept || config.accept || type.raw + ', application/json;q=0.8, text/plain;q=0.5, */*;q=0.2'; | ||
headers = request.headers || (request.headers = {}); | ||
type = mime.parse(headers['Content-Type'] || config.mime || 'text/plain'); | ||
headers.Accept = headers.Accept || config.accept || type.raw + ', application/json;q=0.8, text/plain;q=0.5, */*;q=0.2'; | ||
if (!('entity' in request)) { | ||
return request; | ||
} | ||
if (!('entity' in request)) { | ||
return request; | ||
} | ||
return config.registry.lookup(type).otherwise(function () { | ||
// failed to resolve converter | ||
if (config.permissive) { | ||
return noopConverter; | ||
} | ||
throw 'mime-unknown'; | ||
}).then(function (converter) { | ||
var client = config.client || request.originator; | ||
headers['Content-Type'] = type.raw; | ||
return when.attempt(converter.write, request.entity, { client: client, request: request, mime: type, registry: config.registry }) | ||
.otherwise(function() { | ||
throw 'mime-serialization'; | ||
}) | ||
.then(function(entity) { | ||
request.entity = entity; | ||
return request; | ||
}); | ||
return config.registry.lookup(type)['catch'](function () { | ||
// failed to resolve converter | ||
if (config.permissive) { | ||
return noopConverter; | ||
} | ||
throw 'mime-unknown'; | ||
}).then(function (converter) { | ||
var client = config.client || request.originator, | ||
write = converter.write || missingConverter.write; | ||
return attempt(write.bind(void 0, request.entity, { client: client, request: request, mime: type, registry: config.registry })) | ||
['catch'](function() { | ||
throw 'mime-serialization'; | ||
}) | ||
.then(function(entity) { | ||
request.entity = entity; | ||
return request; | ||
}); | ||
}, | ||
response: function (response, config) { | ||
if (!(response.headers && response.headers['Content-Type'] && response.entity)) { | ||
return response; | ||
} | ||
}); | ||
}, | ||
response: function (response, config) { | ||
if (!(response.headers && response.headers['Content-Type'] && response.entity)) { | ||
return response; | ||
} | ||
var type = mime.parse(response.headers['Content-Type']); | ||
var type = mime.parse(response.headers['Content-Type']); | ||
return config.registry.lookup(type).otherwise(function () { return noopConverter; }).then(function (converter) { | ||
var client = config.client || response.request && response.request.originator; | ||
return config.registry.lookup(type)['catch'](function () { return noopConverter; }).then(function (converter) { | ||
var client = config.client || response.request && response.request.originator, | ||
read = converter.read || missingConverter.read; | ||
return when.attempt(converter.read, response.entity, { client: client, response: response, mime: type, registry: config.registry }) | ||
.otherwise(function (e) { | ||
response.error = 'mime-deserialization'; | ||
response.cause = e; | ||
throw response; | ||
}) | ||
.then(function (entity) { | ||
response.entity = entity; | ||
return response; | ||
}); | ||
return attempt(read.bind(void 0, response.entity, { client: client, response: response, mime: type, registry: config.registry })) | ||
['catch'](function (e) { | ||
response.error = 'mime-deserialization'; | ||
response.cause = e; | ||
throw response; | ||
}) | ||
.then(function (entity) { | ||
response.entity = entity; | ||
return response; | ||
}); | ||
} | ||
}); | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
} | ||
}); |
/* | ||
* Copyright 2012-2013 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,141 +8,129 @@ * | ||
(function (define, global) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var interceptor, UrlBuilder, pubsub; | ||
var interceptor, UrlBuilder, pubsub, when; | ||
interceptor = require('../interceptor'); | ||
UrlBuilder = require('../UrlBuilder'); | ||
pubsub = require('../util/pubsub'); | ||
interceptor = require('../interceptor'); | ||
UrlBuilder = require('../UrlBuilder'); | ||
pubsub = require('../util/pubsub'); | ||
when = require('when'); | ||
function defaultOAuthCallback(hash) { | ||
var params, queryString, regex, m; | ||
function defaultOAuthCallback(hash) { | ||
var params, queryString, regex, m; | ||
queryString = hash.indexOf('#') === 0 ? hash.substring(1) : hash; | ||
params = {}; | ||
regex = /([^&=]+)=([^&]*)/g; | ||
queryString = hash.indexOf('#') === 0 ? hash.substring(1) : hash; | ||
params = {}; | ||
regex = /([^&=]+)=([^&]*)/g; | ||
m = regex.exec(queryString); | ||
do { | ||
params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]); | ||
m = regex.exec(queryString); | ||
} while (m); | ||
m = regex.exec(queryString); | ||
do { | ||
params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]); | ||
m = regex.exec(queryString); | ||
} while (m); | ||
/*jshint camelcase:false */ | ||
pubsub.publish(params.state, params.token_type + ' ' + params.access_token); | ||
} | ||
/*jshint camelcase:false */ | ||
pubsub.publish(params.state, params.token_type + ' ' + params.access_token); | ||
} | ||
function defaultWindowStrategy(url) { | ||
var w = window.open(url, '_blank', 'width=500,height=400'); | ||
return function () { | ||
w.close(); | ||
}; | ||
} | ||
function defaultWindowStrategy(url) { | ||
var w = window.open(url, '_blank', 'width=500,height=400'); | ||
return function () { | ||
w.close(); | ||
}; | ||
} | ||
function authorize(config) { | ||
var state, url, dismissWindow; | ||
function authorize(config) { | ||
var state, url, dismissWindow; | ||
return new Promise(function (resolve) { | ||
return when.promise(function (resolve) { | ||
state = Math.random() * new Date().getTime(); | ||
url = new UrlBuilder(config.authorizationUrlBase).build({ | ||
'response_type': 'token', | ||
'redirect_uri': config.redirectUrl, | ||
'client_id': config.clientId, | ||
'scope': config.scope, | ||
'state': state | ||
}); | ||
state = Math.random() * new Date().getTime(); | ||
url = new UrlBuilder(config.authorizationUrlBase).build({ | ||
'response_type': 'token', | ||
'redirect_uri': config.redirectUrl, | ||
'client_id': config.clientId, | ||
'scope': config.scope, | ||
'state': state | ||
}); | ||
dismissWindow = config.windowStrategy(url); | ||
dismissWindow = config.windowStrategy(url); | ||
pubsub.subscribe(state, function (authorization) { | ||
dismissWindow(); | ||
resolve(authorization); | ||
}); | ||
pubsub.subscribe(state, function (authorization) { | ||
dismissWindow(); | ||
resolve(authorization); | ||
}); | ||
}); | ||
} | ||
}); | ||
} | ||
/** | ||
* OAuth implicit flow support | ||
* | ||
* Authorizes request with the OAuth authorization token. Tokens are | ||
* requested from the authorization server as needed if there isn't a | ||
* token, or the token is expired. | ||
* | ||
* A custom window strategy can be provided to replace the default popup | ||
* window. The window strategy is a function that must accept a URL as an | ||
* argument and returns a function to close and cleanup the window. A | ||
* common custom strategy would be to use an iframe in a dialog. | ||
* | ||
* The callback function must be invoked when the authorization server | ||
* redirects the browser back to the application. | ||
* | ||
* NOTE: Registering a handler to receive the redirect is required and | ||
* outside the scope of this interceptor. The implementer must collect the | ||
* URL fragment and pass it to the callback function on the 'opener', or | ||
* 'parent' window. | ||
* | ||
* @param {Client} [target] client to wrap | ||
* @param {string} [config.token] pre-configured authentication token | ||
* @param {string} config.clientId OAuth clientId | ||
* @param {string} config.scope OAuth scope | ||
* @param {string} config.authorizationUrlBase URL of the authorization server | ||
* @param {string} [config.redirectUrl] callback URL from the authorization server. Will be converted to a fully qualified, absolute URL, if needed. Default's to the window's location or base href. | ||
* @param {Function} [config.windowStrategy] strategy for opening the authorization window, defaults to window.open | ||
* @param {string} [config.oAuthCallbackName='oAuthCallback'] name to register the callback as in global scope | ||
* @param {Function} [config.oAuthCallback] callback function to receive OAuth URL fragment | ||
* | ||
* @returns {Client} | ||
*/ | ||
module.exports = interceptor({ | ||
init: function (config) { | ||
config.redirectUrl = new UrlBuilder(config.redirectUrl).fullyQualify().build(); | ||
config.windowStrategy = config.windowStrategy || defaultWindowStrategy; | ||
config.oAuthCallback = config.oAuthCallback || defaultOAuthCallback; | ||
config.oAuthCallbackName = config.oAuthCallbackName || 'oAuthCallback'; | ||
/** | ||
* OAuth implicit flow support | ||
* | ||
* Authorizes request with the OAuth authorization token. Tokens are | ||
* requested from the authorization server as needed if there isn't a | ||
* token, or the token is expired. | ||
* | ||
* A custom window strategy can be provided to replace the default popup | ||
* window. The window strategy is a function that must accept a URL as an | ||
* argument and returns a function to close and cleanup the window. A | ||
* common custom strategy would be to use an iframe in a dialog. | ||
* | ||
* The callback function must be invoked when the authorization server | ||
* redirects the browser back to the application. | ||
* | ||
* NOTE: Registering a handler to receive the redirect is required and | ||
* outside the scope of this interceptor. The implementer must collect the | ||
* URL fragment and pass it to the callback function on the 'opener', or | ||
* 'parent' window. | ||
* | ||
* @param {Client} [target] client to wrap | ||
* @param {string} [config.token] pre-configured authentication token | ||
* @param {string} config.clientId OAuth clientId | ||
* @param {string} config.scope OAuth scope | ||
* @param {string} config.authorizationUrlBase URL of the authorization server | ||
* @param {string} [config.redirectUrl] callback URL from the authorization server. Will be converted to a fully qualified, absolute URL, if needed. Default's to the window's location or base href. | ||
* @param {Function} [config.windowStrategy] strategy for opening the authorization window, defaults to window.open | ||
* @param {string} [config.oAuthCallbackName='oAuthCallback'] name to register the callback as in global scope | ||
* @param {Function} [config.oAuthCallback] callback function to receive OAuth URL fragment | ||
* | ||
* @returns {Client} | ||
*/ | ||
return interceptor({ | ||
init: function (config) { | ||
config.redirectUrl = new UrlBuilder(config.redirectUrl).fullyQualify().build(); | ||
config.windowStrategy = config.windowStrategy || defaultWindowStrategy; | ||
config.oAuthCallback = config.oAuthCallback || defaultOAuthCallback; | ||
config.oAuthCallbackName = config.oAuthCallbackName || 'oAuthCallback'; | ||
window[config.oAuthCallbackName] = config.oAuthCallback; | ||
global[config.oAuthCallbackName] = config.oAuthCallback; | ||
return config; | ||
}, | ||
request: function (request, config) { | ||
request.headers = request.headers || {}; | ||
return config; | ||
}, | ||
request: function (request, config) { | ||
request.headers = request.headers || {}; | ||
if (config.token) { | ||
request.headers.Authorization = config.token; | ||
return request; | ||
} | ||
else { | ||
return authorize(config).then(function (authorization) { | ||
request.headers.Authorization = config.token = authorization; | ||
return request; | ||
}); | ||
} | ||
}, | ||
response: function (response, config, meta) { | ||
if (response.status.code === 401) { | ||
// token probably expired, reauthorize | ||
return authorize(config).then(function (authorization) { | ||
config.token = authorization; | ||
return meta.client(response.request); | ||
}); | ||
} | ||
else if (response.status.code === 403) { | ||
return Promise.reject(response); | ||
} | ||
if (config.token) { | ||
request.headers.Authorization = config.token; | ||
return request; | ||
} | ||
else { | ||
return authorize(config).then(function (authorization) { | ||
request.headers.Authorization = config.token = authorization; | ||
return request; | ||
}); | ||
} | ||
}, | ||
response: function (response, config, meta) { | ||
if (response.status.code === 401) { | ||
// token probably expired, reauthorize | ||
return authorize(config).then(function (authorization) { | ||
config.token = authorization; | ||
return meta.client(response.request); | ||
}); | ||
} | ||
else if (response.status.code === 403) { | ||
return when.reject(response); | ||
} | ||
return response; | ||
} | ||
}); | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }, | ||
typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : void 0 | ||
// Boilerplate for AMD and Node | ||
)); | ||
return response; | ||
} | ||
}); |
/* | ||
* Copyright 2012-2013 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,53 +8,43 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var interceptor, UrlBuilder; | ||
var interceptor, UrlBuilder; | ||
interceptor = require('../interceptor'); | ||
UrlBuilder = require('../UrlBuilder'); | ||
interceptor = require('../interceptor'); | ||
UrlBuilder = require('../UrlBuilder'); | ||
function startsWith(str, prefix) { | ||
return str.indexOf(prefix) === 0; | ||
} | ||
function startsWith(str, prefix) { | ||
return str.indexOf(prefix) === 0; | ||
} | ||
function endsWith(str, suffix) { | ||
return str.lastIndexOf(suffix) + suffix.length === str.length; | ||
} | ||
function endsWith(str, suffix) { | ||
return str.lastIndexOf(suffix) + suffix.length === str.length; | ||
} | ||
/** | ||
* Prefixes the request path with a common value. | ||
* | ||
* @param {Client} [client] client to wrap | ||
* @param {number} [config.prefix] path prefix | ||
* | ||
* @returns {Client} | ||
*/ | ||
module.exports = interceptor({ | ||
request: function (request, config) { | ||
var path; | ||
/** | ||
* Prefixes the request path with a common value. | ||
* | ||
* @param {Client} [client] client to wrap | ||
* @param {number} [config.prefix] path prefix | ||
* | ||
* @returns {Client} | ||
*/ | ||
return interceptor({ | ||
request: function (request, config) { | ||
var path; | ||
if (config.prefix && !(new UrlBuilder(request.path).isFullyQualified())) { | ||
path = config.prefix; | ||
if (request.path) { | ||
if (!endsWith(path, '/') && !startsWith(request.path, '/')) { | ||
// add missing '/' between path sections | ||
path += '/'; | ||
} | ||
path += request.path; | ||
} | ||
request.path = path; | ||
if (config.prefix && !(new UrlBuilder(request.path).isFullyQualified())) { | ||
path = config.prefix; | ||
if (request.path) { | ||
if (!endsWith(path, '/') && !startsWith(request.path, '/')) { | ||
// add missing '/' between path sections | ||
path += '/'; | ||
} | ||
return request; | ||
path += request.path; | ||
} | ||
}); | ||
request.path = path; | ||
} | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
return request; | ||
} | ||
}); |
/* | ||
* Copyright 2012-2014 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -9,52 +9,43 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var interceptor, delay; | ||
var interceptor, when; | ||
interceptor = require('../interceptor'); | ||
delay = require('../util/delay'); | ||
interceptor = require('../interceptor'); | ||
when = require('when'); | ||
/** | ||
* Retries a rejected request using an exponential backoff. | ||
* | ||
* Defaults to an initial interval of 100ms, a multiplier of 2, and no max interval. | ||
* | ||
* @param {Client} [client] client to wrap | ||
* @param {number} [config.intial=100] initial interval in ms | ||
* @param {number} [config.multiplier=2] interval multiplier | ||
* @param {number} [config.max] max interval in ms | ||
* | ||
* @returns {Client} | ||
*/ | ||
module.exports = interceptor({ | ||
init: function (config) { | ||
config.initial = config.initial || 100; | ||
config.multiplier = config.multiplier || 2; | ||
config.max = config.max || Infinity; | ||
return config; | ||
}, | ||
error: function (response, config, meta) { | ||
var request; | ||
/** | ||
* Retries a rejected request using an exponential backoff. | ||
* | ||
* Defaults to an initial interval of 100ms, a multiplier of 2, and no max interval. | ||
* | ||
* @param {Client} [client] client to wrap | ||
* @param {number} [config.intial=100] initial interval in ms | ||
* @param {number} [config.multiplier=2] interval multiplier | ||
* @param {number} [config.max] max interval in ms | ||
* | ||
* @returns {Client} | ||
*/ | ||
return interceptor({ | ||
init: function (config) { | ||
config.initial = config.initial || 100; | ||
config.multiplier = config.multiplier || 2; | ||
config.max = config.max || Infinity; | ||
return config; | ||
}, | ||
error: function (response, config, meta) { | ||
var request; | ||
request = response.request; | ||
request.retry = request.retry || config.initial; | ||
request = response.request; | ||
request.retry = request.retry || config.initial; | ||
return when(request).delay(request.retry).then(function (request) { | ||
if (request.canceled) { | ||
// cancel here in case client doesn't check canceled flag | ||
return when.reject({ request: request, error: 'precanceled' }); | ||
} | ||
request.retry = Math.min(request.retry * config.multiplier, config.max); | ||
return meta.client(request); | ||
}); | ||
return delay(request.retry, request).then(function (request) { | ||
if (request.canceled) { | ||
// cancel here in case client doesn't check canceled flag | ||
return Promise.reject({ request: request, error: 'precanceled' }); | ||
} | ||
request.retry = Math.min(request.retry * config.multiplier, config.max); | ||
return meta.client(request); | ||
}); | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
} | ||
}); |
/* | ||
* Copyright 2015 the original author or authors | ||
* Copyright 2015-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,50 +8,40 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var interceptor, uriTemplate, mixin; | ||
var interceptor, uriTemplate, mixin; | ||
interceptor = require('../interceptor'); | ||
uriTemplate = require('../util/uriTemplate'); | ||
mixin = require('../util/mixin'); | ||
interceptor = require('../interceptor'); | ||
uriTemplate = require('../util/uriTemplate'); | ||
mixin = require('../util/mixin'); | ||
/** | ||
* Applies request params to the path as a URI Template | ||
* | ||
* Params are removed from the request object, as they have been consumed. | ||
* | ||
* @see https://tools.ietf.org/html/rfc6570 | ||
* | ||
* @param {Client} [client] client to wrap | ||
* @param {Object} [config.params] default param values | ||
* @param {string} [config.template] default template | ||
* | ||
* @returns {Client} | ||
*/ | ||
module.exports = interceptor({ | ||
init: function (config) { | ||
config.params = config.params || {}; | ||
config.template = config.template || ''; | ||
return config; | ||
}, | ||
request: function (request, config) { | ||
var template, params; | ||
/** | ||
* Applies request params to the path as a URI Template | ||
* | ||
* Params are removed from the request object, as they have been consumed. | ||
* | ||
* @see https://tools.ietf.org/html/rfc6570 | ||
* | ||
* @param {Client} [client] client to wrap | ||
* @param {Object} [config.params] default param values | ||
* @param {string} [config.template] default template | ||
* | ||
* @returns {Client} | ||
*/ | ||
return interceptor({ | ||
init: function (config) { | ||
config.params = config.params || {}; | ||
config.template = config.template || ''; | ||
return config; | ||
}, | ||
request: function (request, config) { | ||
var template, params; | ||
template = request.path || config.template; | ||
params = mixin({}, request.params, config.params); | ||
template = request.path || config.template; | ||
params = mixin({}, request.params, config.params); | ||
request.path = uriTemplate.expand(template, params); | ||
delete request.params; | ||
request.path = uriTemplate.expand(template, params); | ||
delete request.params; | ||
return request; | ||
} | ||
}); | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
return request; | ||
} | ||
}); |
/* | ||
* Copyright 2012-2015 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -9,64 +9,55 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var interceptor; | ||
var interceptor, when; | ||
interceptor = require('../interceptor'); | ||
interceptor = require('../interceptor'); | ||
when = require('when'); | ||
/** | ||
* Cancels a request if it takes longer then the timeout value. | ||
* | ||
* @param {Client} [client] client to wrap | ||
* @param {number} [config.timeout=0] duration in milliseconds before canceling the request. Non-positive values disable the timeout | ||
* @param {boolean} [config.transient=false] if true, timed out requests will not be marked as canceled so that it may be retried | ||
* | ||
* @returns {Client} | ||
*/ | ||
return interceptor({ | ||
init: function (config) { | ||
config.timeout = config.timeout || 0; | ||
config.transient = !!config.transient; | ||
return config; | ||
}, | ||
request: function (request, config) { | ||
var timeout, abortTrigger, transient; | ||
timeout = 'timeout' in request ? request.timeout : config.timeout; | ||
transient = 'transient' in request ? request.transient : config.transient; | ||
if (timeout <= 0) { | ||
return request; | ||
/** | ||
* Cancels a request if it takes longer then the timeout value. | ||
* | ||
* @param {Client} [client] client to wrap | ||
* @param {number} [config.timeout=0] duration in milliseconds before canceling the request. Non-positive values disable the timeout | ||
* @param {boolean} [config.transient=false] if true, timed out requests will not be marked as canceled so that it may be retried | ||
* | ||
* @returns {Client} | ||
*/ | ||
module.exports = interceptor({ | ||
init: function (config) { | ||
config.timeout = config.timeout || 0; | ||
config.transient = !!config.transient; | ||
return config; | ||
}, | ||
request: function (request, config) { | ||
var timeout, abort, triggerAbort, transient; | ||
timeout = 'timeout' in request ? request.timeout : config.timeout; | ||
transient = 'transient' in request ? request.transient : config.transient; | ||
if (timeout <= 0) { | ||
return request; | ||
} | ||
abort = new Promise(function (resolve, reject) { | ||
triggerAbort = reject; | ||
}); | ||
this.timeout = setTimeout(function () { | ||
triggerAbort({ request: request, error: 'timeout' }); | ||
if (request.cancel) { | ||
request.cancel(); | ||
if (transient) { | ||
// unmark request as canceled for future requests | ||
request.canceled = false; | ||
} | ||
abortTrigger = when.defer(); | ||
this.timeout = setTimeout(function () { | ||
abortTrigger.reject({ request: request, error: 'timeout' }); | ||
if (request.cancel) { | ||
request.cancel(); | ||
if (transient) { | ||
// unmark request as canceled for future requests | ||
request.canceled = false; | ||
} | ||
} | ||
else if (!transient) { | ||
request.canceled = true; | ||
} | ||
}, timeout); | ||
return new interceptor.ComplexRequest({ request: request, abort: abortTrigger.promise }); | ||
}, | ||
response: function (response) { | ||
if (this.timeout) { | ||
clearTimeout(this.timeout); | ||
delete this.timeout; | ||
} | ||
return response; | ||
} | ||
}); | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
else if (!transient) { | ||
request.canceled = true; | ||
} | ||
}, timeout); | ||
return new interceptor.ComplexRequest({ request: request, abort: abort }); | ||
}, | ||
response: function (response) { | ||
if (this.timeout) { | ||
clearTimeout(this.timeout); | ||
delete this.timeout; | ||
} | ||
return response; | ||
} | ||
}); |
74
mime.js
/* | ||
* Copyright 2014 the original author or authors | ||
* Copyright 2014-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,47 +8,35 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
var undef; | ||
/** | ||
* Parse a MIME type into it's constituent parts | ||
* | ||
* @param {string} mime MIME type to parse | ||
* @return {{ | ||
* {string} raw the original MIME type | ||
* {string} type the type and subtype | ||
* {string} [suffix] mime suffix, including the plus, if any | ||
* {Object} params key/value pair of attributes | ||
* }} | ||
*/ | ||
function parse(mime) { | ||
var params, type; | ||
define(function (/* require */) { | ||
params = mime.split(';'); | ||
type = params[0].trim().split('+'); | ||
/** | ||
* Parse a MIME type into it's constituent parts | ||
* | ||
* @param {string} mime MIME type to parse | ||
* @return {{ | ||
* {string} raw the original MIME type | ||
* {string} type the type and subtype | ||
* {string} [suffix] mime suffix, including the plus, if any | ||
* {Object} params key/value pair of attributes | ||
* }} | ||
*/ | ||
function parse(mime) { | ||
var params, type; | ||
return { | ||
raw: mime, | ||
type: type[0], | ||
suffix: type[1] ? '+' + type[1] : '', | ||
params: params.slice(1).reduce(function (params, pair) { | ||
pair = pair.split('='); | ||
params[pair[0].trim()] = pair[1] ? pair[1].trim() : void 0; | ||
return params; | ||
}, {}) | ||
}; | ||
} | ||
params = mime.split(';'); | ||
type = params[0].trim().split('+'); | ||
return { | ||
raw: mime, | ||
type: type[0], | ||
suffix: type[1] ? '+' + type[1] : '', | ||
params: params.slice(1).reduce(function (params, pair) { | ||
pair = pair.split('='); | ||
params[pair[0].trim()] = pair[1] ? pair[1].trim() : undef; | ||
return params; | ||
}, {}) | ||
}; | ||
} | ||
return { | ||
parse: parse | ||
}; | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
module.exports = { | ||
parse: parse | ||
}; |
/* | ||
* Copyright 2012-2014 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,109 +8,98 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var mime, registry; | ||
var mime, when, registry; | ||
mime = require('../mime'); | ||
mime = require('../mime'); | ||
when = require('when'); | ||
function Registry(mimes) { | ||
function Registry(mimes) { | ||
/** | ||
* Lookup the converter for a MIME type | ||
* | ||
* @param {string} type the MIME type | ||
* @return a promise for the converter | ||
*/ | ||
this.lookup = function lookup(type) { | ||
var parsed; | ||
/** | ||
* Lookup the converter for a MIME type | ||
* | ||
* @param {string} type the MIME type | ||
* @return a promise for the converter | ||
*/ | ||
this.lookup = function lookup(type) { | ||
var parsed; | ||
parsed = typeof type === 'string' ? mime.parse(type) : type; | ||
parsed = typeof type === 'string' ? mime.parse(type) : type; | ||
if (mimes[parsed.raw]) { | ||
return mimes[parsed.raw]; | ||
} | ||
if (mimes[parsed.type + parsed.suffix]) { | ||
return mimes[parsed.type + parsed.suffix]; | ||
} | ||
if (mimes[parsed.type]) { | ||
return mimes[parsed.type]; | ||
} | ||
if (mimes[parsed.suffix]) { | ||
return mimes[parsed.suffix]; | ||
} | ||
if (mimes[parsed.raw]) { | ||
return mimes[parsed.raw]; | ||
} | ||
if (mimes[parsed.type + parsed.suffix]) { | ||
return mimes[parsed.type + parsed.suffix]; | ||
} | ||
if (mimes[parsed.type]) { | ||
return mimes[parsed.type]; | ||
} | ||
if (mimes[parsed.suffix]) { | ||
return mimes[parsed.suffix]; | ||
} | ||
return Promise.reject(new Error('Unable to locate converter for mime "' + parsed.raw + '"')); | ||
}; | ||
return when.reject(new Error('Unable to locate converter for mime "' + parsed.raw + '"')); | ||
}; | ||
/** | ||
* Create a late dispatched proxy to the target converter. | ||
* | ||
* Common when a converter is registered under multiple names and | ||
* should be kept in sync if updated. | ||
* | ||
* @param {string} type mime converter to dispatch to | ||
* @returns converter whose read/write methods target the desired mime converter | ||
*/ | ||
this.delegate = function delegate(type) { | ||
return { | ||
read: function () { | ||
var args = arguments; | ||
return this.lookup(type).then(function (converter) { | ||
return converter.read.apply(this, args); | ||
}.bind(this)); | ||
}.bind(this), | ||
write: function () { | ||
var args = arguments; | ||
return this.lookup(type).then(function (converter) { | ||
return converter.write.apply(this, args); | ||
}.bind(this)); | ||
}.bind(this) | ||
}; | ||
}; | ||
/** | ||
* Create a late dispatched proxy to the target converter. | ||
* | ||
* Common when a converter is registered under multiple names and | ||
* should be kept in sync if updated. | ||
* | ||
* @param {string} type mime converter to dispatch to | ||
* @returns converter whose read/write methods target the desired mime converter | ||
*/ | ||
this.delegate = function delegate(type) { | ||
return { | ||
read: function () { | ||
var args = arguments; | ||
return this.lookup(type).then(function (converter) { | ||
return converter.read.apply(this, args); | ||
}.bind(this)); | ||
}.bind(this), | ||
write: function () { | ||
var args = arguments; | ||
return this.lookup(type).then(function (converter) { | ||
return converter.write.apply(this, args); | ||
}.bind(this)); | ||
}.bind(this) | ||
}; | ||
}; | ||
/** | ||
* Register a custom converter for a MIME type | ||
* | ||
* @param {string} type the MIME type | ||
* @param converter the converter for the MIME type | ||
* @return a promise for the converter | ||
*/ | ||
this.register = function register(type, converter) { | ||
mimes[type] = Promise.resolve(converter); | ||
return mimes[type]; | ||
}; | ||
/** | ||
* Register a custom converter for a MIME type | ||
* | ||
* @param {string} type the MIME type | ||
* @param converter the converter for the MIME type | ||
* @return a promise for the converter | ||
*/ | ||
this.register = function register(type, converter) { | ||
mimes[type] = when(converter); | ||
return mimes[type]; | ||
}; | ||
/** | ||
* Create a child registry whoes registered converters remain local, while | ||
* able to lookup converters from its parent. | ||
* | ||
* @returns child MIME registry | ||
*/ | ||
this.child = function child() { | ||
return new Registry(Object.create(mimes)); | ||
}; | ||
/** | ||
* Create a child registry whoes registered converters remain local, while | ||
* able to lookup converters from its parent. | ||
* | ||
* @returns child MIME registry | ||
*/ | ||
this.child = function child() { | ||
return new Registry(Object.create(mimes)); | ||
}; | ||
} | ||
} | ||
registry = new Registry({}); | ||
registry = new Registry({}); | ||
// include provided serializers | ||
registry.register('application/hal', require('./type/application/hal')); | ||
registry.register('application/json', require('./type/application/json')); | ||
registry.register('application/x-www-form-urlencoded', require('./type/application/x-www-form-urlencoded')); | ||
registry.register('multipart/form-data', require('./type/multipart/form-data')); | ||
registry.register('text/plain', require('./type/text/plain')); | ||
// include provided serializers | ||
registry.register('application/hal', require('./type/application/hal')); | ||
registry.register('application/json', require('./type/application/json')); | ||
registry.register('application/x-www-form-urlencoded', require('./type/application/x-www-form-urlencoded')); | ||
registry.register('multipart/form-data', require('./type/multipart/form-data')); | ||
registry.register('text/plain', require('./type/text/plain')); | ||
registry.register('+json', registry.delegate('application/json')); | ||
registry.register('+json', registry.delegate('application/json')); | ||
return registry; | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
module.exports = registry; |
/* | ||
* Copyright 2013-2015 the original author or authors | ||
* Copyright 2013-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,133 +8,122 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var pathPrefix, template, find, lazyPromise, responsePromise; | ||
var pathPrefix, template, find, lazyPromise, responsePromise, when; | ||
pathPrefix = require('../../../interceptor/pathPrefix'); | ||
template = require('../../../interceptor/template'); | ||
find = require('../../../util/find'); | ||
lazyPromise = require('../../../util/lazyPromise'); | ||
responsePromise = require('../../../util/responsePromise'); | ||
pathPrefix = require('../../../interceptor/pathPrefix'); | ||
template = require('../../../interceptor/template'); | ||
find = require('../../../util/find'); | ||
lazyPromise = require('../../../util/lazyPromise'); | ||
responsePromise = require('../../../util/responsePromise'); | ||
when = require('when'); | ||
function defineProperty(obj, name, value) { | ||
Object.defineProperty(obj, name, { | ||
value: value, | ||
configurable: true, | ||
enumerable: false, | ||
writeable: true | ||
}); | ||
} | ||
function defineProperty(obj, name, value) { | ||
Object.defineProperty(obj, name, { | ||
value: value, | ||
configurable: true, | ||
enumerable: false, | ||
writeable: true | ||
}); | ||
} | ||
/** | ||
* Hypertext Application Language serializer | ||
* | ||
* Implemented to https://tools.ietf.org/html/draft-kelly-json-hal-06 | ||
* | ||
* As the spec is still a draft, this implementation will be updated as the | ||
* spec evolves | ||
* | ||
* Objects are read as HAL indexing links and embedded objects on to the | ||
* resource. Objects are written as plain JSON. | ||
* | ||
* Embedded relationships are indexed onto the resource by the relationship | ||
* as a promise for the related resource. | ||
* | ||
* Links are indexed onto the resource as a lazy promise that will GET the | ||
* resource when a handler is first registered on the promise. | ||
* | ||
* A `requestFor` method is added to the entity to make a request for the | ||
* relationship. | ||
* | ||
* A `clientFor` method is added to the entity to get a full Client for a | ||
* relationship. | ||
* | ||
* The `_links` and `_embedded` properties on the resource are made | ||
* non-enumerable. | ||
*/ | ||
module.exports = { | ||
/** | ||
* Hypertext Application Language serializer | ||
* | ||
* Implemented to https://tools.ietf.org/html/draft-kelly-json-hal-06 | ||
* | ||
* As the spec is still a draft, this implementation will be updated as the | ||
* spec evolves | ||
* | ||
* Objects are read as HAL indexing links and embedded objects on to the | ||
* resource. Objects are written as plain JSON. | ||
* | ||
* Embedded relationships are indexed onto the resource by the relationship | ||
* as a promise for the related resource. | ||
* | ||
* Links are indexed onto the resource as a lazy promise that will GET the | ||
* resource when a handler is first registered on the promise. | ||
* | ||
* A `requestFor` method is added to the entity to make a request for the | ||
* relationship. | ||
* | ||
* A `clientFor` method is added to the entity to get a full Client for a | ||
* relationship. | ||
* | ||
* The `_links` and `_embedded` properties on the resource are made | ||
* non-enumerable. | ||
*/ | ||
return { | ||
read: function (str, opts) { | ||
var client, console; | ||
read: function (str, opts) { | ||
var client, console; | ||
opts = opts || {}; | ||
client = opts.client; | ||
console = opts.console || console; | ||
opts = opts || {}; | ||
client = opts.client; | ||
console = opts.console || console; | ||
function deprecationWarning(relationship, deprecation) { | ||
if (deprecation && console && console.warn || console.log) { | ||
(console.warn || console.log).call(console, 'Relationship \'' + relationship + '\' is deprecated, see ' + deprecation); | ||
} | ||
} | ||
function deprecationWarning(relationship, deprecation) { | ||
if (deprecation && console && console.warn || console.log) { | ||
(console.warn || console.log).call(console, 'Relationship \'' + relationship + '\' is deprecated, see ' + deprecation); | ||
} | ||
} | ||
return opts.registry.lookup(opts.mime.suffix).then(function (converter) { | ||
return when(converter.read(str, opts)).then(function (root) { | ||
find.findProperties(root, '_embedded', function (embedded, resource, name) { | ||
Object.keys(embedded).forEach(function (relationship) { | ||
if (relationship in resource) { return; } | ||
var related = responsePromise({ | ||
entity: embedded[relationship] | ||
}); | ||
defineProperty(resource, relationship, related); | ||
}); | ||
defineProperty(resource, name, embedded); | ||
}); | ||
find.findProperties(root, '_links', function (links, resource, name) { | ||
Object.keys(links).forEach(function (relationship) { | ||
var link = links[relationship]; | ||
if (relationship in resource) { return; } | ||
defineProperty(resource, relationship, responsePromise.make(lazyPromise(function () { | ||
if (link.deprecation) { deprecationWarning(relationship, link.deprecation); } | ||
if (link.templated === true) { | ||
return template(client)({ path: link.href }); | ||
} | ||
return client({ path: link.href }); | ||
}))); | ||
}); | ||
defineProperty(resource, name, links); | ||
defineProperty(resource, 'clientFor', function (relationship, clientOverride) { | ||
var link = links[relationship]; | ||
if (!link) { | ||
throw new Error('Unknown relationship: ' + relationship); | ||
} | ||
if (link.deprecation) { deprecationWarning(relationship, link.deprecation); } | ||
if (link.templated === true) { | ||
return template( | ||
clientOverride || client, | ||
{ template: link.href } | ||
); | ||
} | ||
return pathPrefix( | ||
clientOverride || client, | ||
{ prefix: link.href } | ||
); | ||
}); | ||
defineProperty(resource, 'requestFor', function (relationship, request, clientOverride) { | ||
var client = this.clientFor(relationship, clientOverride); | ||
return client(request); | ||
}); | ||
}); | ||
return root; | ||
return opts.registry.lookup(opts.mime.suffix).then(function (converter) { | ||
return converter.read(str, opts); | ||
}).then(function (root) { | ||
find.findProperties(root, '_embedded', function (embedded, resource, name) { | ||
Object.keys(embedded).forEach(function (relationship) { | ||
if (relationship in resource) { return; } | ||
var related = responsePromise({ | ||
entity: embedded[relationship] | ||
}); | ||
defineProperty(resource, relationship, related); | ||
}); | ||
defineProperty(resource, name, embedded); | ||
}); | ||
find.findProperties(root, '_links', function (links, resource, name) { | ||
Object.keys(links).forEach(function (relationship) { | ||
var link = links[relationship]; | ||
if (relationship in resource) { return; } | ||
defineProperty(resource, relationship, responsePromise.make(lazyPromise(function () { | ||
if (link.deprecation) { deprecationWarning(relationship, link.deprecation); } | ||
if (link.templated === true) { | ||
return template(client)({ path: link.href }); | ||
} | ||
return client({ path: link.href }); | ||
}))); | ||
}); | ||
defineProperty(resource, name, links); | ||
defineProperty(resource, 'clientFor', function (relationship, clientOverride) { | ||
var link = links[relationship]; | ||
if (!link) { | ||
throw new Error('Unknown relationship: ' + relationship); | ||
} | ||
if (link.deprecation) { deprecationWarning(relationship, link.deprecation); } | ||
if (link.templated === true) { | ||
return template( | ||
clientOverride || client, | ||
{ template: link.href } | ||
); | ||
} | ||
return pathPrefix( | ||
clientOverride || client, | ||
{ prefix: link.href } | ||
); | ||
}); | ||
defineProperty(resource, 'requestFor', function (relationship, request, clientOverride) { | ||
var client = this.clientFor(relationship, clientOverride); | ||
return client(request); | ||
}); | ||
}); | ||
}, | ||
return root; | ||
}); | ||
write: function (obj, opts) { | ||
return opts.registry.lookup(opts.mime.suffix).then(function (converter) { | ||
return converter.write(obj, opts); | ||
}); | ||
} | ||
}, | ||
}; | ||
}); | ||
write: function (obj, opts) { | ||
return opts.registry.lookup(opts.mime.suffix).then(function (converter) { | ||
return converter.write(obj, opts); | ||
}); | ||
} | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
}; |
/* | ||
* Copyright 2012-2015 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,41 +8,31 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (/* require */) { | ||
/** | ||
* Create a new JSON converter with custom reviver/replacer. | ||
* | ||
* The extended converter must be published to a MIME registry in order | ||
* to be used. The existing converter will not be modified. | ||
* | ||
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON | ||
* | ||
* @param {function} [reviver=undefined] custom JSON.parse reviver | ||
* @param {function|Array} [replacer=undefined] custom JSON.stringify replacer | ||
*/ | ||
function createConverter(reviver, replacer) { | ||
return { | ||
/** | ||
* Create a new JSON converter with custom reviver/replacer. | ||
* | ||
* The extended converter must be published to a MIME registry in order | ||
* to be used. The existing converter will not be modified. | ||
* | ||
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON | ||
* | ||
* @param {function} [reviver=undefined] custom JSON.parse reviver | ||
* @param {function|Array} [replacer=undefined] custom JSON.stringify replacer | ||
*/ | ||
function createConverter(reviver, replacer) { | ||
return { | ||
read: function (str) { | ||
return JSON.parse(str, reviver); | ||
}, | ||
read: function (str) { | ||
return JSON.parse(str, reviver); | ||
}, | ||
write: function (obj) { | ||
return JSON.stringify(obj, replacer); | ||
}, | ||
write: function (obj) { | ||
return JSON.stringify(obj, replacer); | ||
}, | ||
extend: createConverter | ||
extend: createConverter | ||
}; | ||
} | ||
}; | ||
} | ||
return createConverter(); | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
module.exports = createConverter(); |
/* | ||
* Copyright 2012 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,84 +8,75 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (/* require */) { | ||
var encodedSpaceRE, urlEncodedSpaceRE; | ||
var encodedSpaceRE, urlEncodedSpaceRE; | ||
encodedSpaceRE = /%20/g; | ||
urlEncodedSpaceRE = /\+/g; | ||
encodedSpaceRE = /%20/g; | ||
urlEncodedSpaceRE = /\+/g; | ||
function urlEncode(str) { | ||
str = encodeURIComponent(str); | ||
// spec says space should be encoded as '+' | ||
return str.replace(encodedSpaceRE, '+'); | ||
} | ||
function urlEncode(str) { | ||
str = encodeURIComponent(str); | ||
// spec says space should be encoded as '+' | ||
return str.replace(encodedSpaceRE, '+'); | ||
} | ||
function urlDecode(str) { | ||
// spec says space should be encoded as '+' | ||
str = str.replace(urlEncodedSpaceRE, ' '); | ||
return decodeURIComponent(str); | ||
} | ||
function urlDecode(str) { | ||
// spec says space should be encoded as '+' | ||
str = str.replace(urlEncodedSpaceRE, ' '); | ||
return decodeURIComponent(str); | ||
function append(str, name, value) { | ||
if (Array.isArray(value)) { | ||
value.forEach(function (value) { | ||
str = append(str, name, value); | ||
}); | ||
} | ||
else { | ||
if (str.length > 0) { | ||
str += '&'; | ||
} | ||
str += urlEncode(name); | ||
if (value !== undefined && value !== null) { | ||
str += '=' + urlEncode(value); | ||
} | ||
} | ||
return str; | ||
} | ||
function append(str, name, value) { | ||
if (Array.isArray(value)) { | ||
value.forEach(function (value) { | ||
str = append(str, name, value); | ||
}); | ||
module.exports = { | ||
read: function (str) { | ||
var obj = {}; | ||
str.split('&').forEach(function (entry) { | ||
var pair, name, value; | ||
pair = entry.split('='); | ||
name = urlDecode(pair[0]); | ||
if (pair.length === 2) { | ||
value = urlDecode(pair[1]); | ||
} | ||
else { | ||
if (str.length > 0) { | ||
str += '&'; | ||
value = null; | ||
} | ||
if (name in obj) { | ||
if (!Array.isArray(obj[name])) { | ||
// convert to an array, perserving currnent value | ||
obj[name] = [obj[name]]; | ||
} | ||
str += urlEncode(name); | ||
if (value !== undefined && value !== null) { | ||
str += '=' + urlEncode(value); | ||
} | ||
obj[name].push(value); | ||
} | ||
return str; | ||
} | ||
return { | ||
read: function (str) { | ||
var obj = {}; | ||
str.split('&').forEach(function (entry) { | ||
var pair, name, value; | ||
pair = entry.split('='); | ||
name = urlDecode(pair[0]); | ||
if (pair.length === 2) { | ||
value = urlDecode(pair[1]); | ||
} | ||
else { | ||
value = null; | ||
} | ||
if (name in obj) { | ||
if (!Array.isArray(obj[name])) { | ||
// convert to an array, perserving currnent value | ||
obj[name] = [obj[name]]; | ||
} | ||
obj[name].push(value); | ||
} | ||
else { | ||
obj[name] = value; | ||
} | ||
}); | ||
return obj; | ||
}, | ||
write: function (obj) { | ||
var str = ''; | ||
Object.keys(obj).forEach(function (name) { | ||
str = append(str, name, obj[name]); | ||
}); | ||
return str; | ||
else { | ||
obj[name] = value; | ||
} | ||
}); | ||
return obj; | ||
}, | ||
}; | ||
}); | ||
write: function (obj) { | ||
var str = ''; | ||
Object.keys(obj).forEach(function (name) { | ||
str = append(str, name, obj[name]); | ||
}); | ||
return str; | ||
} | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
}; |
/* | ||
* Copyright 2014 the original author or authors | ||
* Copyright 2014-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -10,65 +10,56 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (/* require */) { | ||
function isFormElement(object) { | ||
return object && | ||
object.nodeType === 1 && // Node.ELEMENT_NODE | ||
object.tagName === 'FORM'; | ||
} | ||
function isFormElement(object) { | ||
return object && | ||
object.nodeType === 1 && // Node.ELEMENT_NODE | ||
object.tagName === 'FORM'; | ||
} | ||
function createFormDataFromObject(object) { | ||
var formData = new FormData(); | ||
function createFormDataFromObject(object) { | ||
var formData = new FormData(); | ||
var value; | ||
for (var property in object) { | ||
if (object.hasOwnProperty(property)) { | ||
value = object[property]; | ||
var value; | ||
for (var property in object) { | ||
if (object.hasOwnProperty(property)) { | ||
value = object[property]; | ||
if (value instanceof File) { | ||
formData.append(property, value, value.name); | ||
} else if (value instanceof Blob) { | ||
formData.append(property, value); | ||
} else { | ||
formData.append(property, String(value)); | ||
} | ||
} | ||
if (value instanceof File) { | ||
formData.append(property, value, value.name); | ||
} else if (value instanceof Blob) { | ||
formData.append(property, value); | ||
} else { | ||
formData.append(property, String(value)); | ||
} | ||
return formData; | ||
} | ||
} | ||
return { | ||
return formData; | ||
} | ||
write: function (object) { | ||
if (typeof FormData === 'undefined') { | ||
throw new Error('The multipart/form-data mime serializer requires FormData support'); | ||
} | ||
module.exports = { | ||
// Support FormData directly. | ||
if (object instanceof FormData) { | ||
return object; | ||
} | ||
write: function (object) { | ||
if (typeof FormData === 'undefined') { | ||
throw new Error('The multipart/form-data mime serializer requires FormData support'); | ||
} | ||
// Support <form> elements. | ||
if (isFormElement(object)) { | ||
return new FormData(object); | ||
} | ||
// Support FormData directly. | ||
if (object instanceof FormData) { | ||
return object; | ||
} | ||
// Support plain objects, may contain File/Blob as value. | ||
if (typeof object === 'object' && object !== null) { | ||
return createFormDataFromObject(object); | ||
} | ||
// Support <form> elements. | ||
if (isFormElement(object)) { | ||
return new FormData(object); | ||
} | ||
throw new Error('Unable to create FormData from object ' + object); | ||
} | ||
// Support plain objects, may contain File/Blob as value. | ||
if (typeof object === 'object' && object !== null) { | ||
return createFormDataFromObject(object); | ||
} | ||
}; | ||
}); | ||
throw new Error('Unable to create FormData from object ' + object); | ||
} | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
}; |
/* | ||
* Copyright 2012 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,23 +8,14 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (/* require */) { | ||
module.exports = { | ||
return { | ||
read: function (str) { | ||
return str; | ||
}, | ||
read: function (str) { | ||
return str; | ||
}, | ||
write: function (obj) { | ||
return obj.toString(); | ||
} | ||
write: function (obj) { | ||
return obj.toString(); | ||
} | ||
}; | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
}; |
22
node.js
/* | ||
* Copyright 2014 the original author or authors | ||
* Copyright 2014-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,19 +8,9 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var rest = require('./client/default'), | ||
node = require('./client/node'); | ||
var rest = require('./client/default'), | ||
node = require('./client/node'); | ||
rest.setPlatformDefaultClient(node); | ||
rest.setPlatformDefaultClient(node); | ||
return rest; | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
module.exports = rest; |
{ | ||
"name": "rest", | ||
"version": "1.3.2", | ||
"version": "2.0.0", | ||
"description": "RESTful HTTP client library", | ||
@@ -33,6 +33,5 @@ "keywords": ["rest", "http", "client", "rest-template", "spring", "cujojs"], | ||
], | ||
"dependencies": { | ||
"when": "~3" | ||
}, | ||
"dependencies": {}, | ||
"devDependencies": { | ||
"when": "~3", | ||
"wire": "~0.9", | ||
@@ -39,0 +38,0 @@ "test-support": "~0.4", |
@@ -1,4 +0,1 @@ | ||
(function (define) { | ||
define(function (require, exports, module) { | ||
module.exports = (function(){ | ||
@@ -10,3 +7,3 @@ /* | ||
*/ | ||
function quote(s) { | ||
@@ -34,3 +31,3 @@ /* | ||
} | ||
var result = { | ||
@@ -67,3 +64,3 @@ /* | ||
}; | ||
if (startRule !== undefined) { | ||
@@ -76,3 +73,3 @@ if (parseFunctions[startRule] === undefined) { | ||
} | ||
var pos = 0; | ||
@@ -82,6 +79,6 @@ var reportFailures = 0; | ||
var rightmostFailuresExpected = []; | ||
function padLeft(input, padding, length) { | ||
var result = input; | ||
var padLength = length - input.length; | ||
@@ -91,6 +88,6 @@ for (var i = 0; i < padLength; i++) { | ||
} | ||
return result; | ||
} | ||
function escape(ch) { | ||
@@ -100,3 +97,3 @@ var charCode = ch.charCodeAt(0); | ||
var length; | ||
if (charCode <= 0xFF) { | ||
@@ -109,6 +106,6 @@ escapeChar = 'x'; | ||
} | ||
return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length); | ||
} | ||
function matchFailed(failure) { | ||
@@ -118,3 +115,3 @@ if (pos < rightmostFailuresPos) { | ||
} | ||
if (pos > rightmostFailuresPos) { | ||
@@ -124,10 +121,10 @@ rightmostFailuresPos = pos; | ||
} | ||
rightmostFailuresExpected.push(failure); | ||
} | ||
function parse_start() { | ||
var result0, result1, result2, result3, result4; | ||
var pos0, pos1, pos2, pos3; | ||
pos0 = pos; | ||
@@ -241,7 +238,7 @@ pos1 = pos; | ||
} | ||
function parse_LinkValue() { | ||
var result0, result1, result2, result3, result4, result5; | ||
var pos0, pos1; | ||
pos0 = pos; | ||
@@ -316,7 +313,7 @@ pos1 = pos; | ||
} | ||
function parse_LinkParams() { | ||
var result0, result1, result2, result3; | ||
var pos0, pos1; | ||
pos0 = pos; | ||
@@ -365,7 +362,7 @@ pos1 = pos; | ||
} | ||
function parse_URIReference() { | ||
var result0, result1; | ||
var pos0; | ||
pos0 = pos; | ||
@@ -406,7 +403,7 @@ if (/^[^>]/.test(input.charAt(pos))) { | ||
} | ||
function parse_LinkParam() { | ||
var result0, result1; | ||
var pos0, pos1; | ||
pos0 = pos; | ||
@@ -436,7 +433,7 @@ pos1 = pos; | ||
} | ||
function parse_LinkParamName() { | ||
var result0, result1; | ||
var pos0; | ||
pos0 = pos; | ||
@@ -477,7 +474,7 @@ if (/^[a-z]/.test(input.charAt(pos))) { | ||
} | ||
function parse_LinkParamValue() { | ||
var result0, result1; | ||
var pos0, pos1; | ||
pos0 = pos; | ||
@@ -517,7 +514,7 @@ pos1 = pos; | ||
} | ||
function parse_PToken() { | ||
var result0, result1; | ||
var pos0; | ||
pos0 = pos; | ||
@@ -542,6 +539,6 @@ result1 = parse_PTokenChar(); | ||
} | ||
function parse_PTokenChar() { | ||
var result0; | ||
if (input.charCodeAt(pos) === 33) { | ||
@@ -861,6 +858,6 @@ result0 = "!"; | ||
} | ||
function parse_OptionalSP() { | ||
var result0, result1; | ||
result0 = []; | ||
@@ -874,7 +871,7 @@ result1 = parse_SP(); | ||
} | ||
function parse_QuotedString() { | ||
var result0, result1, result2; | ||
var pos0, pos1; | ||
pos0 = pos; | ||
@@ -909,7 +906,7 @@ pos1 = pos; | ||
} | ||
function parse_QuotedStringInternal() { | ||
var result0, result1; | ||
var pos0; | ||
pos0 = pos; | ||
@@ -936,6 +933,6 @@ result0 = []; | ||
} | ||
function parse_Char() { | ||
var result0; | ||
if (/^[\0-]/.test(input.charAt(pos))) { | ||
@@ -952,6 +949,6 @@ result0 = input.charAt(pos); | ||
} | ||
function parse_UpAlpha() { | ||
var result0; | ||
if (/^[A-Z]/.test(input.charAt(pos))) { | ||
@@ -968,6 +965,6 @@ result0 = input.charAt(pos); | ||
} | ||
function parse_LoAlpha() { | ||
var result0; | ||
if (/^[a-z]/.test(input.charAt(pos))) { | ||
@@ -984,6 +981,6 @@ result0 = input.charAt(pos); | ||
} | ||
function parse_Alpha() { | ||
var result0; | ||
result0 = parse_UpAlpha(); | ||
@@ -995,6 +992,6 @@ if (result0 === null) { | ||
} | ||
function parse_Digit() { | ||
var result0; | ||
if (/^[0-9]/.test(input.charAt(pos))) { | ||
@@ -1011,6 +1008,6 @@ result0 = input.charAt(pos); | ||
} | ||
function parse_SP() { | ||
var result0; | ||
if (/^[ ]/.test(input.charAt(pos))) { | ||
@@ -1027,6 +1024,6 @@ result0 = input.charAt(pos); | ||
} | ||
function parse_DQ() { | ||
var result0; | ||
if (/^["]/.test(input.charAt(pos))) { | ||
@@ -1043,6 +1040,6 @@ result0 = input.charAt(pos); | ||
} | ||
function parse_QDText() { | ||
var result0; | ||
if (/^[^"]/.test(input.charAt(pos))) { | ||
@@ -1059,7 +1056,7 @@ result0 = input.charAt(pos); | ||
} | ||
function parse_QuotedPair() { | ||
var result0, result1; | ||
var pos0; | ||
pos0 = pos; | ||
@@ -1089,7 +1086,7 @@ if (/^[\\]/.test(input.charAt(pos))) { | ||
} | ||
function cleanupExpected(expected) { | ||
expected.sort(); | ||
var lastExpected = null; | ||
@@ -1105,3 +1102,3 @@ var cleanExpected = []; | ||
} | ||
function computeErrorPosition() { | ||
@@ -1114,7 +1111,7 @@ /* | ||
*/ | ||
var line = 1; | ||
var column = 1; | ||
var seenCR = false; | ||
for (var i = 0; i < Math.max(pos, rightmostFailuresPos); i++) { | ||
@@ -1135,9 +1132,9 @@ var ch = input.charAt(i); | ||
} | ||
return { line: line, column: column }; | ||
} | ||
var result = parseFunctions[startRule](); | ||
/* | ||
@@ -1171,3 +1168,3 @@ * The parser is now in one of the following three states: | ||
var errorPosition = computeErrorPosition(); | ||
throw new this.SyntaxError( | ||
@@ -1181,16 +1178,16 @@ cleanupExpected(rightmostFailuresExpected), | ||
} | ||
return result; | ||
}, | ||
/* Returns the parser source code. */ | ||
toSource: function() { return this._source; } | ||
}; | ||
/* Thrown when a parser encounters a syntax error. */ | ||
result.SyntaxError = function(expected, found, offset, line, column) { | ||
function buildMessage(expected, found) { | ||
var expectedHumanized, foundHumanized; | ||
switch (expected.length) { | ||
@@ -1208,8 +1205,8 @@ case 0: | ||
} | ||
foundHumanized = found ? quote(found) : "end of input"; | ||
return "Expected " + expectedHumanized + " but " + foundHumanized + " found."; | ||
} | ||
this.name = "SyntaxError"; | ||
@@ -1223,11 +1220,6 @@ this.expected = expected; | ||
}; | ||
result.SyntaxError.prototype = Error.prototype; | ||
return result; | ||
})(); | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { factory(require, module.exports, module); } | ||
)); |
@@ -144,10 +144,8 @@ rest.js | ||
Tested environments: | ||
- Node.js (0.6, 0.8. 0.10, 4, 5) | ||
- Node.js (0.10, 4, 6) | ||
- Chrome (stable) | ||
- Firefox (stable, ESR, should work in earlier versions) | ||
- Edge | ||
- IE (6-11) | ||
- Safari (5-9, iOS 4-9.2, should work in earlier versions) | ||
- Android (4.0-5.1, should work in earlier versions) | ||
- Opera (11, 12, should work in earlier versions) | ||
- IE (11, should work in earlier versions) | ||
- Safari (8-9, iOS 8-9, should work in earlier versions) | ||
- Android (4.3-5, should work in earlier versions) | ||
@@ -178,3 +176,3 @@ Specific browser test are provided by [Travis CI](https://travis-ci.org/cujojs/rest) and [Sauce Labs' Open Sauce Plan](https://saucelabs.com/opensource). You can see [specific browser test results](https://saucelabs.com/u/cujojs-rest), although odds are they do not reference this specific release/branch/commit. | ||
rest.js is designed to run in a browser environment, utilizing [AMD modules](https://github.com/amdjs/amdjs-api/wiki/AMD), or within [Node.js](http://nodejs.org/) as CommonJS modules. Any module loader capable of loading either AMD or CommonJS modules should be able to load rest.js. cujoJS [curl.js](https://github.com/cujojs/curl) is actively tested. | ||
rest.js is designed to run in a browser environment, utilizing a CommonJS Module loader, a transformer such as Browserify or WebPack, or within [Node.js](http://nodejs.org/). Any module loader capable of loading either CommonJS modules should be able to load rest.js. cujoJS [curl.js](https://github.com/cujojs/curl) is actively tested with the cjsm11 loader. | ||
@@ -233,3 +231,3 @@ An ECMAScript 5 compatible environment is assumed. Older browsers, ::cough:: IE, that do not support ES5 natively can be shimmed. Any shim should work, although we test with cujoJS [poly.js](https://github.com/cujojs/poly) | ||
Copyright 2012-2015 the original author or authors | ||
Copyright 2012-2016 the original author or authors | ||
@@ -242,2 +240,19 @@ rest.js is made available under the MIT license. See LICENSE.txt for details. | ||
2.0.0 | ||
- MAJOR: Drop hard when.js dependency in favor of ES6 Promise API. See https://github.com/cujojs/when/blob/master/docs/es6-promise-shim.md to use when.js as an ES6 Promise polyfill. | ||
- MAJOR: AMD modules are no longer supported. curl.js users can use the cjsm11 loader, see https://github.com/cujojs/curl#api-at-a-glance | ||
- Moved path token param replacement from the clients into the `rest/interceptor/params` interceptor, which is also deprecated. The behavior will no longer be applied automatically in the client. Using the `rest/interceptor/template` interceptor is far more powerful and preferred. | ||
- Fixed an issue preventing uri template exploded values from expanding correctly. | ||
- Update tested environments: | ||
- Android 5.1, 4.4 and 4.3 | ||
- Chrome latest | ||
- Edge latest | ||
- Firefox latest, 45 ESR, 38 ESR | ||
- Node 0.10, 4, 6 | ||
- IE 11 | ||
- iOS 8 and 9 | ||
- Safari 8 and 9 | ||
- Removed old IE XDomainRequest client and xhr and xdr interceptors | ||
- mime interceptor no longer sets Content-Type on requests without an entity | ||
1.3.2 | ||
@@ -244,0 +259,0 @@ - fix to correctly url encode character codes 0-15, such as \n |
22
rest.js
/* | ||
* Copyright 2012-2014 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,18 +8,8 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
if (console) { | ||
(console.warn || console.log).call(console, 'rest.js: The main module has moved, please switch your configuration to use \'rest/browser\' as the main module for browser applications.'); | ||
} | ||
if (console) { | ||
(console.warn || console.log).call(console, 'rest.js: The main module has moved, please switch your configuration to use \'rest/browser\' as the main module for browser applications.'); | ||
} | ||
return require('./browser'); | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
module.exports = require('./browser'); |
@@ -18,3 +18,3 @@ /* | ||
define('rest/browser-test', function (require) { | ||
define('rest-test/browser-test', function (require) { | ||
@@ -21,0 +21,0 @@ var rest, defaultClient, xhr; |
[ | ||
// we don't really care about the platform, but without it the browser may fail to resolve | ||
{ browserName: 'MicrosoftEdge', platform: 'Windows 10' } | ||
{ browserName: 'MicrosoftEdge', platform: 'Windows 10' } | ||
] |
[ | ||
// we don't really care about the platform, but without it the browser may fail to resolve | ||
{ browserName: 'firefox', platform: 'Windows 2008' } | ||
{ browserName: 'firefox', platform: 'Windows 10' } | ||
] |
[ | ||
// we don't really care about the platform, but without it the browser may fail to resolve | ||
{ browserName: 'ipad', version: '9.2', platform: 'OS X 10.10' } | ||
{ browserName: 'ipad', version: '9.2', platform: 'Mac 10.10' } | ||
] |
[ | ||
// we don't really care about the platform, but without it the browser may fail to resolve | ||
{ browserName: 'safari', version: '9.0', platform: 'OS X 10.11' } | ||
{ browserName: 'safari', version: '9', platform: 'Mac 10.11' } | ||
] |
/* | ||
* Copyright 2012-2014 the original author or authors | ||
* Copyright 2012-2015 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -10,2 +10,6 @@ * | ||
if (typeof Promise === 'undefined') { | ||
require('when/es6-shim/Promise'); | ||
} | ||
config['rest:node'] = { | ||
@@ -41,2 +45,3 @@ environment: 'node', | ||
libs: [ | ||
'node_modules/when/es6-shim/Promise.js', | ||
'test/curl-config.js', | ||
@@ -43,0 +48,0 @@ 'node_modules/curl/src/curl.js' |
@@ -18,3 +18,3 @@ /* | ||
define('rest/client-test', function (require) { | ||
define('rest-test/client-test', function (require) { | ||
@@ -21,0 +21,0 @@ var client, rest, interceptor, defaultClient, skippableClient, defaultInterceptor; |
/* | ||
* Copyright 2012-2014 the original author or authors | ||
* Copyright 2012-2015 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -18,3 +18,3 @@ * | ||
define('rest/client/jsonp-test', function (require) { | ||
define('rest-test/client/jsonp-test', function (require) { | ||
@@ -29,10 +29,10 @@ var client, jsonpInterceptor, rest; | ||
'should make a cross origin request': function () { | ||
var request = { path: 'https://api.github.com/' }; | ||
var request = { path: 'http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=jsonp' }; | ||
return client(request).then(function (response) { | ||
assert.match(response.url, 'https://api.github.com/?callback='); | ||
assert(response.entity.data); | ||
assert.match(response.url, 'http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=jsonp&callback='); | ||
assert(Object.keys(response.entity).length); | ||
assert.same(request, response.request); | ||
refute(request.canceled); | ||
refute(response.raw.parentNode); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -47,7 +47,7 @@ 'should use the jsonp client from the jsonp interceptor by default': function () { | ||
refute(response.raw.parentNode); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
'should abort the request if canceled': function () { | ||
var request, response; | ||
request = { path: 'http://ajax.googleapis.com/ajax/services/search/web?v=1.0', params: { q: 'jsonp' } }; | ||
request = { path: 'http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=jsonp' }; | ||
response = client(request).then( | ||
@@ -77,3 +77,3 @@ fail, | ||
'should not make a request that has already been canceled': function () { | ||
var request = { canceled: true, path: 'http://ajax.googleapis.com/ajax/services/search/web?v=1.0', params: { q: 'html5' } }; | ||
var request = { canceled: true, path: 'http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=html5' }; | ||
return client(request).then( | ||
@@ -109,7 +109,7 @@ fail, | ||
'should normalize a string to a request object': function () { | ||
var request = 'https://api.github.com/'; | ||
var request = 'http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=jsonp'; | ||
return client(request).then(function (response) { | ||
assert.match(response.url, 'https://api.github.com/?callback='); | ||
assert.match(response.url, 'http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=jsonp&callback='); | ||
assert.same(request, response.request.path); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -125,3 +125,3 @@ 'should not be the default client': function () { | ||
var response = client(); | ||
response.otherwise(function () {}); | ||
response['catch'](function () {}); | ||
assert.isFunction(response.entity); | ||
@@ -128,0 +128,0 @@ } |
/* | ||
* Copyright 2012-2014 the original author or authors | ||
* Copyright 2012-2015 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -19,3 +19,3 @@ * | ||
define('rest/client/node-test', function (require) { | ||
define('rest-test/client/node-test', function (require) { | ||
@@ -81,3 +81,3 @@ var rest, client, http, https, fs, serverHttp, serverHttps; | ||
refute(request.canceled); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -93,3 +93,3 @@ 'should make an explicit GET': function () { | ||
refute(request.canceled); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -107,3 +107,3 @@ 'should make a POST with an entity': function () { | ||
refute(request.canceled); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -118,3 +118,3 @@ 'should make an explicit POST with an entity': function () { | ||
refute(request.canceled); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -138,3 +138,3 @@ 'should make an https request': function () { | ||
refute(request.canceled); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -180,3 +180,3 @@ 'should abort the request if canceled': function () { | ||
assert.same('http://localhost:8080/', response.request.path); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -192,3 +192,3 @@ 'should be the default client': function () { | ||
var response = client(); | ||
response.otherwise(function () {}); | ||
response['catch'](function () {}); | ||
assert.isFunction(response.entity); | ||
@@ -195,0 +195,0 @@ } |
/* | ||
* Copyright 2012-2014 the original author or authors | ||
* Copyright 2012-2015 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -18,14 +18,10 @@ * | ||
define('rest/client/xhr-test', function (require) { | ||
define('rest-test/client/xhr-test', function (require) { | ||
var xhr, rest, xhrFallback, when, client; | ||
var client, rest, when; | ||
xhr = require('rest/client/xhr'); | ||
client = require('rest/client/xhr'); | ||
rest = require('rest'); | ||
xhrFallback = require('rest/interceptor/ie/xhr'); | ||
when = require('when'); | ||
// use xhrFallback when XHR is not native | ||
client = !XMLHttpRequest ? xhr.wrap(xhrFallback) : xhr; | ||
buster.testCase('rest/client/xhr', { | ||
@@ -50,3 +46,3 @@ 'should make a GET by default': function () { | ||
refute(request.canceled); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -71,3 +67,3 @@ 'should make an explicit GET': function () { | ||
refute(request.canceled); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -92,3 +88,3 @@ 'should make a POST with an entity': function () { | ||
refute(request.canceled); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -113,3 +109,3 @@ 'should make an explicit POST with an entity': function () { | ||
refute(request.canceled); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -124,3 +120,3 @@ 'should mixin additional properties': { | ||
refute.equals(xhr.foo, 'bar'); | ||
}).otherwise(function (err) { | ||
})['catch'](function (err) { | ||
fail(JSON.stringify(err)); | ||
@@ -186,7 +182,6 @@ }); | ||
var request = { path: '/' }; | ||
return xhr(request).then( | ||
return client(request).then( | ||
fail, | ||
failOnThrow(function (response) { | ||
assert.same(request, response.request); | ||
assert.equals(response.url, '/'); | ||
assert.same('xhr-not-available', response.error); | ||
@@ -201,10 +196,10 @@ }) | ||
assert.same('/', response.request.path); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
'should be the default client': function () { | ||
rest.resetDefaultClient(); | ||
assert.same(xhr, rest.getDefaultClient()); | ||
assert.same(client, rest.getDefaultClient()); | ||
}, | ||
'should support interceptor wrapping': function () { | ||
assert(typeof xhr.wrap === 'function'); | ||
assert(typeof client.wrap === 'function'); | ||
}, | ||
@@ -211,0 +206,0 @@ 'should return a ResponsePromise': function () { |
/* | ||
* Copyright 2012-2014 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,17 +8,14 @@ * | ||
(function (global) { | ||
'use strict'; | ||
'use strict'; | ||
global.curl = { | ||
packages: [ | ||
{ name: 'rest', location: './', main: 'browser' }, | ||
{ name: 'curl', location: 'node_modules/curl/src/curl', main: 'curl' }, | ||
{ name: 'poly', location: 'node_modules/poly', main: 'poly' }, | ||
{ name: 'when', location: 'node_modules/when', main: 'when' }, | ||
{ name: 'wire', location: 'node_modules/wire', main: 'wire' } | ||
], | ||
// avoid poly/xhr as we need to test the case without it | ||
preloads: ['poly/object', 'poly/string', 'poly/date', 'poly/array', 'poly/function', 'poly/json'] | ||
}; | ||
}(this)); | ||
window.curl = { | ||
packages: [ | ||
{ name: 'rest', location: './', main: 'browser', config: { moduleLoader: 'curl/loader/cjsm11' } }, | ||
{ name: 'curl', location: 'node_modules/curl/src/curl', main: 'curl' }, | ||
{ name: 'poly', location: 'node_modules/poly', main: 'poly' }, | ||
{ name: 'when', location: 'node_modules/when', main: 'when' }, | ||
{ name: 'wire', location: 'node_modules/wire', main: 'wire' } | ||
], | ||
// avoid poly/xhr as we need to test the case without it | ||
preloads: ['poly/object', 'poly/string', 'poly/date', 'poly/array', 'poly/function', 'poly/json'] | ||
}; |
@@ -18,3 +18,3 @@ /* | ||
define('rest/interceptor-test', function (require) { | ||
define('rest-test/interceptor-test', function (require) { | ||
@@ -52,3 +52,3 @@ var interceptor, rest, when; | ||
assert.same(client, response.request.originator); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -64,3 +64,3 @@ 'should use the client configured into the interceptor by default': function () { | ||
assert.same(client, response.request.originator); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -76,3 +76,3 @@ 'should override the client configured into the interceptor by default': function () { | ||
assert.same(client, response.request.originator); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -90,3 +90,3 @@ 'should intercept the request phase': function () { | ||
assert.same('request', response.request.phase); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -107,3 +107,3 @@ 'should intercept the request phase and handle a promise': function () { | ||
assert.same('request', response.request.phase); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -140,3 +140,3 @@ 'should intercept the request phase and handle a rejected promise': function () { | ||
assert.same('response', response.phase); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -156,3 +156,3 @@ 'should intercept the response phase and handle a promise': function () { | ||
assert.same('response', response.phase); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -235,3 +235,3 @@ 'should intercept the response phase and handle a rejceted promise': function () { | ||
assert.same('success', response.phase); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -252,3 +252,3 @@ 'should intercept the success phase and handle a promise': function () { | ||
assert.same('success', response.phase); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -284,3 +284,3 @@ 'should intercept the success phase and handle a rejceted promise': function () { | ||
assert.same('error', response.phase); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -299,3 +299,3 @@ 'should intercept the error phase and handle a promise': function () { | ||
assert.same('error', response.phase); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -338,3 +338,3 @@ 'should intercept the error phase and handle a rejceted promise': function () { | ||
assert.same('response', response.phase); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -366,3 +366,3 @@ 'should share context between handlers that is unique per request': function () { | ||
assert(counted.indexOf(3) >= 0); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -383,3 +383,3 @@ 'should use the client provided by a ComplexRequest': function () { | ||
assert.same(client, response.request.originator); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -399,3 +399,3 @@ 'should use the repsponse provided by a ComplexRequest': function () { | ||
assert.same(client, response.request.originator); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -439,3 +439,3 @@ 'should cancel requests with the abort trigger provided by a ComplexRequest': function () { | ||
assert.same('default', response.id); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -460,3 +460,3 @@ 'should have access to the invocation args': function () { | ||
assert.same('default', response.id); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -490,3 +490,3 @@ 'should initialize the config object, modifying the provided object': function () { | ||
assert.same('default', response.id); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -499,3 +499,3 @@ 'should normalize a string to a request object': function () { | ||
assert.same('/', response.request.path); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -502,0 +502,0 @@ 'should have the default client as the parent by default': function () { |
@@ -17,3 +17,3 @@ /* | ||
define('rest/interceptor/basicAuth-test', function (require) { | ||
define('rest-test/interceptor/basicAuth-test', function (require) { | ||
@@ -33,3 +33,3 @@ var basicAuth, rest; | ||
assert.equals('Basic dXNlcjpwYXNz', response.request.headers.Authorization); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -42,3 +42,3 @@ 'should authenticate the requst from the request': function () { | ||
assert.equals('Basic dXNlcjpwYXNz', response.request.headers.Authorization); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -51,3 +51,3 @@ 'should not authenticate without a username': function () { | ||
refute.defined(response.request.headers.Authorization); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -54,0 +54,0 @@ 'should have the default client as the parent by default': function () { |
/* | ||
* Copyright 2013-2014 the original author or authors | ||
* Copyright 2013-2015 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -17,3 +17,3 @@ * | ||
define('rest/interceptor/csrf-test', function (require) { | ||
define('rest-test/interceptor/csrf-test', function (require) { | ||
@@ -33,3 +33,3 @@ var csrf, rest; | ||
assert.equals('abc123xyz789', response.request.headers['X-Csrf-Token']); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -42,3 +42,3 @@ 'should protect the requst from the request': function () { | ||
assert.equals('abc123xyz789', response.request.headers['X-Csrf-Token']); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -52,3 +52,3 @@ 'should protect the requst from the config using a custom header': function () { | ||
assert.equals('abc123xyz789', response.request.headers['Csrf-Token']); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -61,3 +61,3 @@ 'should protect the requst from the request using a custom header': function () { | ||
assert.equals('abc123xyz789', response.request.headers['Csrf-Token']); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -70,3 +70,3 @@ 'should not protect without a token': function () { | ||
refute.defined(response.request.headers['X-Csrf-Token']); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -73,0 +73,0 @@ 'should have the default client as the parent by default': function () { |
/* | ||
* Copyright 2013-2014 the original author or authors | ||
* Copyright 2013-2015 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -17,3 +17,3 @@ * | ||
define('rest/interceptor/defaultRequest-test', function (require) { | ||
define('rest-test/interceptor/defaultRequest-test', function (require) { | ||
@@ -36,3 +36,3 @@ var defaultRequest, rest; | ||
assert.equals({}, response.request); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -43,3 +43,3 @@ 'should default the method': function () { | ||
assert.equals('PUT', response.request.method); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -50,3 +50,3 @@ 'should not overwrite the method': function () { | ||
assert.equals('GET', response.request.method); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -57,3 +57,3 @@ 'should default the path': function () { | ||
assert.equals('/foo', response.request.path); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -64,3 +64,3 @@ 'should not overwrite the path': function () { | ||
assert.equals('/bar', response.request.path); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -72,3 +72,3 @@ 'should default params': function () { | ||
assert.equals('false', response.request.params.bool); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -81,3 +81,3 @@ 'should merge params': function () { | ||
assert.equals('bloop', response.request.params.bleep); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -89,3 +89,3 @@ 'should default headers': function () { | ||
assert.equals('false', response.request.headers.bool); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -98,3 +98,3 @@ 'should merge headers': function () { | ||
assert.equals('bloop', response.request.headers.bleep); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -105,3 +105,3 @@ 'should default the entity': function () { | ||
assert.same(Math, response.request.entity); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -112,3 +112,3 @@ 'should not overwrite the entity': function () { | ||
assert.same(Date, response.request.entity); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -115,0 +115,0 @@ 'should have the default client as the parent by default': function () { |
/* | ||
* Copyright 2012-2014 the original author or authors | ||
* Copyright 2012-2015 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -17,3 +17,3 @@ * | ||
define('rest/interceptor/entity-test', function (require) { | ||
define('rest-test/interceptor/entity-test', function (require) { | ||
@@ -34,3 +34,3 @@ var entity, rest; | ||
assert.same(body, response); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -45,3 +45,3 @@ 'should return the whole response if there is no entity': function () { | ||
assert.same(response, r); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -48,0 +48,0 @@ 'should have the default client as the parent by default': function () { |
/* | ||
* Copyright 2012-2014 the original author or authors | ||
* Copyright 2012-2015 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -18,3 +18,3 @@ * | ||
define('rest/interceptor/errorCode-test', function (require) { | ||
define('rest-test/interceptor/errorCode-test', function (require) { | ||
@@ -33,3 +33,3 @@ var errorCode, rest; | ||
assert.equals(399, response.status.code); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -36,0 +36,0 @@ 'should reject for 400 or greater by default': function () { |
/* | ||
* Copyright 2012-2014 the original author or authors | ||
* Copyright 2012-2015 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -17,3 +17,3 @@ * | ||
define('rest/interceptor/hateoas-test', function (require) { | ||
define('rest-test/interceptor/hateoas-test', function (require) { | ||
@@ -69,3 +69,3 @@ var hateoas, rest, when, supports; | ||
assert.same(response.links.nextLink.title, 'next chapter'); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -86,3 +86,3 @@ 'should parse compound header links': function () { | ||
assert.same(response.links.nextLink.title, 'next chapter'); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -98,3 +98,3 @@ 'should gracefully recover from maleformed header links': function () { | ||
assert.same(entity, response.entity); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -116,3 +116,3 @@ '': { | ||
assert.same(self, response.entity._links.selfLink); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -131,3 +131,3 @@ 'should parse links in the entity into the entity': function () { | ||
assert.same(self, response.entity.selfLink); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -148,3 +148,3 @@ 'should create a client for the related resource': function () { | ||
}); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -161,3 +161,3 @@ 'should return the same value for multiple property accesses': function () { | ||
assert.same(response.entity.self, response.entity.self); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
} | ||
@@ -184,3 +184,3 @@ }, | ||
}); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
} | ||
@@ -187,0 +187,0 @@ }, |
/* | ||
* Copyright 2012-2014 the original author or authors | ||
* Copyright 2012-2015 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -17,3 +17,3 @@ * | ||
define('rest/interceptor/jsonp-test', function (require) { | ||
define('rest-test/interceptor/jsonp-test', function (require) { | ||
@@ -37,3 +37,3 @@ var jsonp, rest, jsonpClient, when; | ||
assert.equals('jsonp123456', response.request.callback.name); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -49,3 +49,3 @@ 'should include callback info from request overridding config values': function () { | ||
assert.equals('customName', response.request.callback.name); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -52,0 +52,0 @@ 'should have the jsonp client as the parent by default': function () { |
/* | ||
* Copyright 2012-2014 the original author or authors | ||
* Copyright 2012-2015 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -17,3 +17,3 @@ * | ||
define('rest/interceptor/location-test', function (require) { | ||
define('rest-test/interceptor/location-test', function (require) { | ||
@@ -46,3 +46,3 @@ var location, rest; | ||
refute(spy.returnValues[2].headers.Location); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -68,3 +68,3 @@ 'should follow the location header when status code is greater or equal to configured status code': function () { | ||
assert.same(spy.args[1][0].path, '/foo'); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -78,3 +78,3 @@ 'should return the response if there is no location header': function () { | ||
assert.same(1, spy.callCount); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -81,0 +81,0 @@ 'should have the default client as the parent by default': function () { |
/* | ||
* Copyright 2012-2014 the original author or authors | ||
* Copyright 2012-2015 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -18,3 +18,3 @@ * | ||
define('rest/interceptor/mime-test', function (require) { | ||
define('rest-test/interceptor/mime-test', function (require) { | ||
@@ -38,3 +38,3 @@ var mime, registry, rest, when; | ||
assert.equals({}, response.entity); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -53,3 +53,3 @@ 'should encode the request entity': function () { | ||
assert.equals('{}', response.request.entity); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -70,3 +70,3 @@ 'should encode the request entity from the Content-Type of the request, ignoring the filter config': function () { | ||
assert.equals(0, response.request.headers.Accept.indexOf('application/json')); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -87,4 +87,19 @@ 'should not overwrite the requests Accept header': function () { | ||
assert.equals('foo', response.request.headers.Accept); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
'should not set the requests Content-Type header if there is no entity': function () { | ||
var client; | ||
client = mime( | ||
function (request) { | ||
return { request: request, headers: {} }; | ||
}, | ||
{ mime: 'application/json' } | ||
); | ||
return client({}).then(function (response) { | ||
assert.equals(undefined, response.request.entity); | ||
assert.equals(undefined, response.request.headers['Content-Type']); | ||
})['catch'](fail); | ||
}, | ||
'should error the request if unable to find a converter for the desired mime': function () { | ||
@@ -119,3 +134,3 @@ var client, request; | ||
assert.equals('application/vnd.com.example', response.request.headers['Content-Type']); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -131,3 +146,3 @@ 'should use text/plain converter for a response if unable to find a converter for the desired mime': function () { | ||
assert.same('{}', response.entity); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -174,3 +189,3 @@ 'should use the configured mime registry': function () { | ||
}); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -276,3 +291,3 @@ 'should reject the response if the serializer fails to write the request': function () { | ||
assert.equals('response entity', response.entity); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -301,3 +316,3 @@ 'should wait for entity to resolve before returning when serializer returns a promise while writing request entity': function () { | ||
assert.equals('request entity', response.request.entity); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -304,0 +319,0 @@ 'should reject the response if serializer rejects promise while writing request entity': function () { |
/* | ||
* Copyright 2012-2014 the original author or authors | ||
* Copyright 2012-2015 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -17,3 +17,3 @@ * | ||
define('rest/interceptor/pathPrefix-test', function (require) { | ||
define('rest-test/interceptor/pathPrefix-test', function (require) { | ||
@@ -33,3 +33,3 @@ var pathPrefix, rest; | ||
assert.equals('/foo/bar', response.request.path); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -43,3 +43,3 @@ 'should prepend prefix before path, adding slash between path segments': function () { | ||
assert.equals('/foo/bar', response.request.path); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -53,3 +53,3 @@ 'should prepend prefix before path, not adding extra slash between path segments': function () { | ||
assert.equals('/foo/bar', response.request.path); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -63,3 +63,3 @@ 'should not prepend prefix before a fully qualified path': function () { | ||
assert.equals('http://www.example.com/', response.request.path); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -66,0 +66,0 @@ 'should have the default client as the parent by default': function () { |
/* | ||
* Copyright 2012-2014 the original author or authors | ||
* Copyright 2012-2015 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -9,3 +9,3 @@ * | ||
(function (buster, define, nextTick) { | ||
(function (buster, define) { | ||
'use strict'; | ||
@@ -19,5 +19,5 @@ | ||
define('rest/interceptor/retry-test', function (require) { | ||
define('rest-test/interceptor/retry-test', function (require) { | ||
var interceptor, retry, rest, when, clock; | ||
var interceptor, retry, rest, when; | ||
@@ -43,38 +43,27 @@ interceptor = require('rest/interceptor'); | ||
assert.equals(200, response.status.code); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
'should accept custom config': { | ||
setUp: function () { | ||
clock = this.useFakeTimers(); | ||
}, | ||
tearDown: function () { | ||
clock.restore(); | ||
}, | ||
'': function () { | ||
var count = 0, client, start, config; | ||
'should accept custom config': function () { | ||
var count = 0, client, start, config; | ||
start = new Date().getTime(); | ||
config = { initial: 10, multiplier: 3, max: 20 }; | ||
client = retry( | ||
function (request) { | ||
var tick = Math.min(Math.pow(config.multiplier, count) * config.initial, config.max); | ||
count += 1; | ||
if (count === 4) { | ||
return { request: request, status: { code: 200 } }; | ||
} else { | ||
nextTick(function () { | ||
clock.tick(tick); | ||
}, 0); | ||
return when.reject({ request: request, error: 'Thrown by fake client' }); | ||
} | ||
}, | ||
config | ||
); | ||
start = new Date().getTime(); | ||
config = { initial: 10, multiplier: 3, max: 20 }; | ||
client = retry( | ||
function (request) { | ||
count += 1; | ||
if (count === 4) { | ||
return { request: request, status: { code: 200 } }; | ||
} else { | ||
return when.reject({ request: request, error: 'Thrown by fake client' }); | ||
} | ||
}, | ||
config | ||
); | ||
return client({}).then(function (response) { | ||
assert.equals(200, response.status.code); | ||
assert.equals(count, 4); | ||
assert.equals(50, new Date().getTime() - start); | ||
}).otherwise(fail); | ||
} | ||
return client({}).then(function (response) { | ||
var durration = Date.now() - start; | ||
assert.equals(200, response.status.code); | ||
assert.equals(count, 4); | ||
assert(40 <= durration); | ||
})['catch'](fail); | ||
}, | ||
@@ -120,14 +109,4 @@ 'should not make propagate request if marked as canceled': function () { | ||
}); | ||
}, | ||
// retain access to the native setTimeout function | ||
(function (setTimeout) { | ||
return typeof process !== 'undefined' && process.nextTick ? | ||
function (work) { | ||
process.nextTick(work); | ||
} : | ||
function (work) { | ||
setTimeout(work, 0); | ||
}; | ||
}(setTimeout)) | ||
} | ||
// Boilerplate for AMD and Node | ||
)); |
@@ -17,3 +17,3 @@ /* | ||
define('rest/interceptor/template-test', function (require) { | ||
define('rest-test/interceptor/template-test', function (require) { | ||
@@ -39,3 +39,3 @@ var template, rest; | ||
refute('params' in response.request); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -51,3 +51,3 @@ 'should apply the template and params from the config if not defined on the request': function () { | ||
refute('params' in response.request); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -63,3 +63,3 @@ 'should individually mix config params into the request': function () { | ||
refute('params' in response.request); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -75,3 +75,3 @@ 'should ignore missing and overdefined params': function () { | ||
refute('params' in response.request); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -78,0 +78,0 @@ 'should have the default client as the parent by default': function () { |
@@ -19,3 +19,3 @@ /* | ||
define('rest/interceptor/timeout-test', function (require) { | ||
define('rest-test/interceptor/timeout-test', function (require) { | ||
@@ -63,7 +63,7 @@ var timeout, rest, when; | ||
}); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
'should resolve if client responds before timeout': function () { | ||
var client, request; | ||
client = timeout(delayedClient, { timeout: 100 }); | ||
client = timeout(delayedClient, { timeout: 200 }); | ||
request = {}; | ||
@@ -74,3 +74,3 @@ return client(request).then(function (response) { | ||
refute(request.canceled); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -111,3 +111,3 @@ 'should reject even if client responds after timeout': function () { | ||
refute(request.canceled); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -122,3 +122,3 @@ 'should not reject without a configured timeout value': function () { | ||
refute(request.canceled); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -125,0 +125,0 @@ 'should cancel request if client support cancelation': function () { |
@@ -17,3 +17,3 @@ /* | ||
define('rest/mime-test', function (require) { | ||
define('rest-test/mime-test', function (require) { | ||
@@ -20,0 +20,0 @@ var mime; |
/* | ||
* Copyright 2012-2014 the original author or authors | ||
* Copyright 2012-2015 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -17,3 +17,3 @@ * | ||
define('rest/mime/registry-test', function (require) { | ||
define('rest-test/mime/registry-test', function (require) { | ||
@@ -33,3 +33,3 @@ var mimeRegistry, when, registry; | ||
assert.isFunction(converter.write); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -41,3 +41,3 @@ 'should return registed converter': function () { | ||
assert.same(converter, c); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -59,3 +59,3 @@ 'should reject for non-existant converter': function () { | ||
assert.same(converter, c); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -71,3 +71,3 @@ 'should override parent registries when registering in a child': function () { | ||
assert.same(converterChild, c); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -83,3 +83,3 @@ 'should not have any side effects in a parent registry from a child': function () { | ||
assert.same(converterParent, c); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -91,3 +91,3 @@ 'should ignore charset in mime resolution': function () { | ||
assert.same(converter, c); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -99,3 +99,3 @@ 'should ignore suffix in mime resolution': function () { | ||
assert.same(converter, c); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -107,3 +107,3 @@ 'should fallback to suffix if mime type is not resolved': function () { | ||
assert.same(converter, c); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -110,0 +110,0 @@ 'should invoke the delegate mime converter': function () { |
@@ -17,3 +17,3 @@ /* | ||
define('rest/mime/type/application/hal-test', function (require) { | ||
define('rest-test/mime/type/application/hal-test', function (require) { | ||
@@ -50,3 +50,3 @@ var hal, mime, registry, halMime, supports; | ||
assert.equals('{"foo":"bar"}', resource); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -56,3 +56,3 @@ 'should read json': function () { | ||
assert.equals({ foo: 'bar' }, resource); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -64,3 +64,3 @@ 'should place embedded relationships on the host object': function () { | ||
}); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -70,3 +70,3 @@ 'should not overwrite a property on the host oject with an embedded relationship': function () { | ||
assert.same(resource.prop, 'host'); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -76,3 +76,3 @@ 'should place linked relationships on the host object': function () { | ||
assert.isFunction(resource.prop.entity); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -82,3 +82,3 @@ 'should not overwrite a property on the host oject with a linked relationship': function () { | ||
assert.same(resource.prop, 'host'); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -97,3 +97,3 @@ 'should fetch a linked resource': function () { | ||
}); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -112,3 +112,3 @@ 'should fetch a templated linked resource': function () { | ||
}); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -121,3 +121,3 @@ 'should make a request for a relationship': function () { | ||
}); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -129,3 +129,3 @@ 'should get a client for a relationship': function () { | ||
}); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -138,3 +138,3 @@ 'should get a client for a templated relationship': function () { | ||
}); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -156,3 +156,3 @@ 'should safely warn when accessing a deprecated relationship': { | ||
}); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
@@ -172,3 +172,3 @@ }, | ||
}); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -184,3 +184,3 @@ 'doing nothing if the console is unavailable': function () { | ||
}); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
} | ||
@@ -187,0 +187,0 @@ }, |
@@ -16,3 +16,3 @@ /* | ||
define('rest/mime/type/application/json-test', function (require) { | ||
define('rest-test/mime/type/application/json-test', function (require) { | ||
@@ -19,0 +19,0 @@ var json = require('rest/mime/type/application/json'); |
@@ -16,3 +16,3 @@ /* | ||
define('rest/mime/type/application/x-www-form-urlencoded-test', function (require) { | ||
define('rest-test/mime/type/application/x-www-form-urlencoded-test', function (require) { | ||
@@ -19,0 +19,0 @@ var encodeder = require('rest/mime/type/application/x-www-form-urlencoded'); |
@@ -16,3 +16,3 @@ /* | ||
define('rest/mime/type/multipart/form-data-test', function (require) { | ||
define('rest-test/mime/type/multipart/form-data-test', function (require) { | ||
@@ -22,3 +22,3 @@ var encoder = require('rest/mime/type/multipart/form-data'); | ||
buster.testCase('rest/mime/type/multipart/form-data', { | ||
requiresSupportFor: { FormData: 'FormData' in window }, | ||
requiresSupportFor: { FormData: typeof FormData !== 'undefined' }, | ||
'should pass a FormData object through unmodified': function () { | ||
@@ -25,0 +25,0 @@ var data = new FormData(); |
@@ -16,3 +16,3 @@ /* | ||
define('rest/mime/type/text/plain-test', function (require) { | ||
define('rest-test/mime/type/text/plain-test', function (require) { | ||
@@ -19,0 +19,0 @@ var plain = require('rest/mime/type/text/plain'); |
@@ -18,3 +18,3 @@ /* | ||
define('rest/node-test', function (require) { | ||
define('rest-test/node-test', function (require) { | ||
@@ -21,0 +21,0 @@ var rest, defaultClient, node; |
@@ -11,10 +11,10 @@ /* | ||
define('rest/test/run', ['curl/_privileged', 'domReady!'], function (curl) { | ||
define('rest-test/test/run', ['curl/_privileged', 'domReady!'], function (curl) { | ||
var modules = Object.keys(curl.cache).filter(function (moduleId) { | ||
return moduleId.indexOf('-test') > 0; | ||
return moduleId.match(/-test(-browser)?$/); | ||
}); | ||
buster.testRunner.timeout = 5000; | ||
define('rest/test/run-faux', modules, function () { | ||
define('rest-test/test/run-faux', modules, function () { | ||
buster.run(); | ||
@@ -21,0 +21,0 @@ }); |
@@ -16,3 +16,3 @@ /* | ||
define('rest/UrlBuilder-test', function (require) { | ||
define('rest-test/UrlBuilder-test', function (require) { | ||
@@ -37,2 +37,5 @@ var UrlBuilder = require('rest/UrlBuilder'); | ||
}, | ||
'should add named param multiple times to query string if value is an array': function () { | ||
assert.equals('/foo/bar?foo=bar&foo=baz', new UrlBuilder('/foo/bar', { foo: ['bar', 'baz'] }).build()); | ||
}, | ||
'should add unused params to an exsisting query string': function () { | ||
@@ -42,3 +45,3 @@ assert.equals('/foo/bar?bleep=bloop', new UrlBuilder('/foo/{foo}', { foo: 'bar', bleep: 'bloop' }).build()); | ||
'should url encode all param names and values added to the url': function () { | ||
assert.equals('/foo/bar?bl%25eep=bl%20oop', new UrlBuilder('/foo/bar', { 'bl%eep': 'bl oop' }).build()); | ||
assert.equals('/foo/bar?bl%25eep=bl+oop', new UrlBuilder('/foo/bar', { 'bl%eep': 'bl oop' }).build()); | ||
}, | ||
@@ -45,0 +48,0 @@ 'should return a built url for string concatination': function () { |
@@ -16,3 +16,3 @@ /* | ||
define('rest/util/base64-test', function (require) { | ||
define('rest-test/util/base64-test', function (require) { | ||
@@ -19,0 +19,0 @@ var base64 = require('rest/util/base64'); |
@@ -16,3 +16,3 @@ /* | ||
define('rest/util/find-test', function (require) { | ||
define('rest-test/util/find-test', function (require) { | ||
@@ -19,0 +19,0 @@ var find = require('rest/util/find'); |
@@ -17,3 +17,3 @@ /* | ||
define('rest/util/lazyPromise-test', function (require) { | ||
define('rest-test/util/lazyPromise-test', function (require) { | ||
@@ -20,0 +20,0 @@ var lazyPromise = require('rest/util/lazyPromise'); |
@@ -16,3 +16,3 @@ /* | ||
define('rest/util/mixin-test', function (require) { | ||
define('rest-test/util/mixin-test', function (require) { | ||
@@ -19,0 +19,0 @@ var mixin = require('rest/util/mixin'); |
@@ -16,3 +16,3 @@ /* | ||
define('rest/util/normalizeHeaderName-test', function (require) { | ||
define('rest-test/util/normalizeHeaderName-test', function (require) { | ||
@@ -19,0 +19,0 @@ var normalizeHeaderName = require('rest/util/normalizeHeaderName'); |
@@ -16,3 +16,3 @@ /* | ||
define('rest/util/pubsub-test', function (require) { | ||
define('rest-test/util/pubsub-test', function (require) { | ||
@@ -19,0 +19,0 @@ var pubsub = require('rest/util/pubsub'); |
@@ -18,3 +18,3 @@ /* | ||
define('rest/util/responsePromise-test', function (require) { | ||
define('rest-test/util/responsePromise-test', function (require) { | ||
@@ -47,3 +47,3 @@ var responsePromise, mime, when, client; | ||
'should be an instance of Promise': function () { | ||
assert(responsePromise() instanceof when.Promise); | ||
assert(responsePromise() instanceof Promise); | ||
}, | ||
@@ -50,0 +50,0 @@ |
@@ -16,3 +16,3 @@ /* | ||
define('rest/util/uriTemplate-test', function (require) { | ||
define('rest-test/util/uriTemplate-test', function (require) { | ||
@@ -57,2 +57,7 @@ var uriTemplate, params; | ||
assert.same(uriTemplate.expand('{&count*}', params), '&count=one&count=two&count=three'); | ||
assert.same(uriTemplate.expand('{?count*,who}', params), '?count=one&count=two&count=three&who=fred'); | ||
assert.same(uriTemplate.expand('{?who,count*}', params), '?who=fred&count=one&count=two&count=three'); | ||
assert.same(uriTemplate.expand('{?keys*,who}', params), '?semi=%3B&dot=.&comma=%2C&who=fred'); | ||
assert.same(uriTemplate.expand('{?who,keys*}', params), '?who=fred&semi=%3B&dot=.&comma=%2C'); | ||
}, | ||
@@ -59,0 +64,0 @@ '3.2.2. Simple String Expansion: {var}': function () { |
@@ -16,3 +16,3 @@ /* | ||
define('rest/version-test', function (require) { | ||
define('rest-test/version-test', function (require) { | ||
@@ -19,0 +19,0 @@ var bowerJson, packageJson; |
@@ -18,3 +18,3 @@ /* | ||
define('rest/wire-test', function (require) { | ||
define('rest-test/wire-test', function (require) { | ||
@@ -56,3 +56,3 @@ var rest, pathPrefixInterceptor, wire; | ||
}); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -89,3 +89,3 @@ 'with interceptor references': function () { | ||
}); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -110,3 +110,3 @@ 'with interceptor string shortcuts': function () { | ||
assert.same(client, spec.client.skip().skip().skip()); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -134,3 +134,3 @@ 'with concrete interceptors': function () { | ||
}); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -149,3 +149,3 @@ 'using the default client': function () { | ||
assert.same(rest, spec.client.skip()); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -171,3 +171,3 @@ 'using a referenced parent client': function () { | ||
assert.same(client, spec.client.skip()); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
}, | ||
@@ -198,3 +198,3 @@ 'wiring interceptor configurations': function () { | ||
}); | ||
}).otherwise(fail); | ||
})['catch'](fail); | ||
} | ||
@@ -201,0 +201,0 @@ } |
/* | ||
* Copyright 2012-2013 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,223 +8,210 @@ * | ||
(function (define, location) { | ||
'use strict'; | ||
'use strict'; | ||
var undef; | ||
var mixin, xWWWFormURLEncoder, origin, urlRE, absoluteUrlRE, fullyQualifiedUrlRE; | ||
define(function (require) { | ||
mixin = require('./util/mixin'); | ||
xWWWFormURLEncoder = require('./mime/type/application/x-www-form-urlencoded'); | ||
var mixin, origin, urlRE, absoluteUrlRE, fullyQualifiedUrlRE; | ||
urlRE = /([a-z][a-z0-9\+\-\.]*:)\/\/([^@]+@)?(([^:\/]+)(:([0-9]+))?)?(\/[^?#]*)?(\?[^#]*)?(#\S*)?/i; | ||
absoluteUrlRE = /^([a-z][a-z0-9\-\+\.]*:\/\/|\/)/i; | ||
fullyQualifiedUrlRE = /([a-z][a-z0-9\+\-\.]*:)\/\/([^@]+@)?(([^:\/]+)(:([0-9]+))?)?\//i; | ||
mixin = require('./util/mixin'); | ||
/** | ||
* Apply params to the template to create a URL. | ||
* | ||
* Parameters that are not applied directly to the template, are appended | ||
* to the URL as query string parameters. | ||
* | ||
* @param {string} template the URI template | ||
* @param {Object} params parameters to apply to the template | ||
* @return {string} the resulting URL | ||
*/ | ||
function buildUrl(template, params) { | ||
// internal builder to convert template with params. | ||
var url, name, queryStringParams, queryString, re; | ||
urlRE = /([a-z][a-z0-9\+\-\.]*:)\/\/([^@]+@)?(([^:\/]+)(:([0-9]+))?)?(\/[^?#]*)?(\?[^#]*)?(#\S*)?/i; | ||
absoluteUrlRE = /^([a-z][a-z0-9\-\+\.]*:\/\/|\/)/i; | ||
fullyQualifiedUrlRE = /([a-z][a-z0-9\+\-\.]*:)\/\/([^@]+@)?(([^:\/]+)(:([0-9]+))?)?\//i; | ||
url = template; | ||
queryStringParams = {}; | ||
/** | ||
* Apply params to the template to create a URL. | ||
* | ||
* Parameters that are not applied directly to the template, are appended | ||
* to the URL as query string parameters. | ||
* | ||
* @param {string} template the URI template | ||
* @param {Object} params parameters to apply to the template | ||
* @return {string} the resulting URL | ||
*/ | ||
function buildUrl(template, params) { | ||
// internal builder to convert template with params. | ||
var url, name, queryStringParams, re; | ||
url = template; | ||
queryStringParams = {}; | ||
if (params) { | ||
for (name in params) { | ||
/*jshint forin:false */ | ||
re = new RegExp('\\{' + name + '\\}'); | ||
if (re.test(url)) { | ||
url = url.replace(re, encodeURIComponent(params[name]), 'g'); | ||
} | ||
else { | ||
queryStringParams[name] = params[name]; | ||
} | ||
} | ||
for (name in queryStringParams) { | ||
url += url.indexOf('?') === -1 ? '?' : '&'; | ||
url += encodeURIComponent(name); | ||
if (queryStringParams[name] !== null && queryStringParams[name] !== undefined) { | ||
url += '='; | ||
url += encodeURIComponent(queryStringParams[name]); | ||
} | ||
} | ||
if (params) { | ||
for (name in params) { | ||
/*jshint forin:false */ | ||
re = new RegExp('\\{' + name + '\\}'); | ||
if (re.test(url)) { | ||
url = url.replace(re, encodeURIComponent(params[name]), 'g'); | ||
} | ||
return url; | ||
else { | ||
queryStringParams[name] = params[name]; | ||
} | ||
} | ||
function startsWith(str, test) { | ||
return str.indexOf(test) === 0; | ||
queryString = xWWWFormURLEncoder.write(queryStringParams); | ||
if (queryString) { | ||
url += url.indexOf('?') === -1 ? '?' : '&'; | ||
url += queryString; | ||
} | ||
} | ||
return url; | ||
} | ||
/** | ||
* Create a new URL Builder | ||
* | ||
* @param {string|UrlBuilder} template the base template to build from, may be another UrlBuilder | ||
* @param {Object} [params] base parameters | ||
* @constructor | ||
*/ | ||
function UrlBuilder(template, params) { | ||
if (!(this instanceof UrlBuilder)) { | ||
// invoke as a constructor | ||
return new UrlBuilder(template, params); | ||
} | ||
function startsWith(str, test) { | ||
return str.indexOf(test) === 0; | ||
} | ||
if (template instanceof UrlBuilder) { | ||
this._template = template.template; | ||
this._params = mixin({}, this._params, params); | ||
} | ||
else { | ||
this._template = (template || '').toString(); | ||
this._params = params || {}; | ||
} | ||
} | ||
/** | ||
* Create a new URL Builder | ||
* | ||
* @param {string|UrlBuilder} template the base template to build from, may be another UrlBuilder | ||
* @param {Object} [params] base parameters | ||
* @constructor | ||
*/ | ||
function UrlBuilder(template, params) { | ||
if (!(this instanceof UrlBuilder)) { | ||
// invoke as a constructor | ||
return new UrlBuilder(template, params); | ||
} | ||
UrlBuilder.prototype = { | ||
if (template instanceof UrlBuilder) { | ||
this._template = template.template; | ||
this._params = mixin({}, this._params, params); | ||
} | ||
else { | ||
this._template = (template || '').toString(); | ||
this._params = params || {}; | ||
} | ||
} | ||
/** | ||
* Create a new UrlBuilder instance that extends the current builder. | ||
* The current builder is unmodified. | ||
* | ||
* @param {string} [template] URL template to append to the current template | ||
* @param {Object} [params] params to combine with current params. New params override existing params | ||
* @return {UrlBuilder} the new builder | ||
*/ | ||
append: function (template, params) { | ||
// TODO consider query strings and fragments | ||
return new UrlBuilder(this._template + template, mixin({}, this._params, params)); | ||
}, | ||
UrlBuilder.prototype = { | ||
/** | ||
* Create a new UrlBuilder with a fully qualified URL based on the | ||
* window's location or base href and the current templates relative URL. | ||
* | ||
* Path variables are preserved. | ||
* | ||
* *Browser only* | ||
* | ||
* @return {UrlBuilder} the fully qualified URL template | ||
*/ | ||
fullyQualify: function () { | ||
if (!location) { return this; } | ||
if (this.isFullyQualified()) { return this; } | ||
/** | ||
* Create a new UrlBuilder instance that extends the current builder. | ||
* The current builder is unmodified. | ||
* | ||
* @param {string} [template] URL template to append to the current template | ||
* @param {Object} [params] params to combine with current params. New params override existing params | ||
* @return {UrlBuilder} the new builder | ||
*/ | ||
append: function (template, params) { | ||
// TODO consider query strings and fragments | ||
return new UrlBuilder(this._template + template, mixin({}, this._params, params)); | ||
}, | ||
var template = this._template; | ||
/** | ||
* Create a new UrlBuilder with a fully qualified URL based on the | ||
* window's location or base href and the current templates relative URL. | ||
* | ||
* Path variables are preserved. | ||
* | ||
* *Browser only* | ||
* | ||
* @return {UrlBuilder} the fully qualified URL template | ||
*/ | ||
fullyQualify: function () { | ||
if (typeof location === 'undefined') { return this; } | ||
if (this.isFullyQualified()) { return this; } | ||
if (startsWith(template, '//')) { | ||
template = origin.protocol + template; | ||
} | ||
else if (startsWith(template, '/')) { | ||
template = origin.origin + template; | ||
} | ||
else if (!this.isAbsolute()) { | ||
template = origin.origin + origin.pathname.substring(0, origin.pathname.lastIndexOf('/') + 1); | ||
} | ||
var template = this._template; | ||
if (template.indexOf('/', 8) === -1) { | ||
// default the pathname to '/' | ||
template = template + '/'; | ||
} | ||
if (startsWith(template, '//')) { | ||
template = origin.protocol + template; | ||
} | ||
else if (startsWith(template, '/')) { | ||
template = origin.origin + template; | ||
} | ||
else if (!this.isAbsolute()) { | ||
template = origin.origin + origin.pathname.substring(0, origin.pathname.lastIndexOf('/') + 1); | ||
} | ||
return new UrlBuilder(template, this._params); | ||
}, | ||
if (template.indexOf('/', 8) === -1) { | ||
// default the pathname to '/' | ||
template = template + '/'; | ||
} | ||
/** | ||
* True if the URL is absolute | ||
* | ||
* @return {boolean} | ||
*/ | ||
isAbsolute: function () { | ||
return absoluteUrlRE.test(this.build()); | ||
}, | ||
return new UrlBuilder(template, this._params); | ||
}, | ||
/** | ||
* True if the URL is fully qualified | ||
* | ||
* @return {boolean} | ||
*/ | ||
isFullyQualified: function () { | ||
return fullyQualifiedUrlRE.test(this.build()); | ||
}, | ||
/** | ||
* True if the URL is absolute | ||
* | ||
* @return {boolean} | ||
*/ | ||
isAbsolute: function () { | ||
return absoluteUrlRE.test(this.build()); | ||
}, | ||
/** | ||
* True if the URL is cross origin. The protocol, host and port must not be | ||
* the same in order to be cross origin, | ||
* | ||
* @return {boolean} | ||
*/ | ||
isCrossOrigin: function () { | ||
if (!origin) { | ||
return true; | ||
} | ||
var url = this.parts(); | ||
return url.protocol !== origin.protocol || | ||
url.hostname !== origin.hostname || | ||
url.port !== origin.port; | ||
}, | ||
/** | ||
* True if the URL is fully qualified | ||
* | ||
* @return {boolean} | ||
*/ | ||
isFullyQualified: function () { | ||
return fullyQualifiedUrlRE.test(this.build()); | ||
}, | ||
/** | ||
* Split a URL into its consituent parts following the naming convention of | ||
* 'window.location'. One difference is that the port will contain the | ||
* protocol default if not specified. | ||
* | ||
* @see https://developer.mozilla.org/en-US/docs/DOM/window.location | ||
* | ||
* @returns {Object} a 'window.location'-like object | ||
*/ | ||
parts: function () { | ||
/*jshint maxcomplexity:20 */ | ||
var url, parts; | ||
url = this.fullyQualify().build().match(urlRE); | ||
parts = { | ||
href: url[0], | ||
protocol: url[1], | ||
host: url[3] || '', | ||
hostname: url[4] || '', | ||
port: url[6], | ||
pathname: url[7] || '', | ||
search: url[8] || '', | ||
hash: url[9] || '' | ||
}; | ||
parts.origin = parts.protocol + '//' + parts.host; | ||
parts.port = parts.port || (parts.protocol === 'https:' ? '443' : parts.protocol === 'http:' ? '80' : ''); | ||
return parts; | ||
}, | ||
/** | ||
* True if the URL is cross origin. The protocol, host and port must not be | ||
* the same in order to be cross origin, | ||
* | ||
* @return {boolean} | ||
*/ | ||
isCrossOrigin: function () { | ||
if (!origin) { | ||
return true; | ||
} | ||
var url = this.parts(); | ||
return url.protocol !== origin.protocol || | ||
url.hostname !== origin.hostname || | ||
url.port !== origin.port; | ||
}, | ||
/** | ||
* Expand the template replacing path variables with parameters | ||
* | ||
* @param {Object} [params] params to combine with current params. New params override existing params | ||
* @return {string} the expanded URL | ||
*/ | ||
build: function (params) { | ||
return buildUrl(this._template, mixin({}, this._params, params)); | ||
}, | ||
/** | ||
* Split a URL into its consituent parts following the naming convention of | ||
* 'window.location'. One difference is that the port will contain the | ||
* protocol default if not specified. | ||
* | ||
* @see https://developer.mozilla.org/en-US/docs/DOM/window.location | ||
* | ||
* @returns {Object} a 'window.location'-like object | ||
*/ | ||
parts: function () { | ||
/*jshint maxcomplexity:20 */ | ||
var url, parts; | ||
url = this.fullyQualify().build().match(urlRE); | ||
parts = { | ||
href: url[0], | ||
protocol: url[1], | ||
host: url[3] || '', | ||
hostname: url[4] || '', | ||
port: url[6], | ||
pathname: url[7] || '', | ||
search: url[8] || '', | ||
hash: url[9] || '' | ||
}; | ||
parts.origin = parts.protocol + '//' + parts.host; | ||
parts.port = parts.port || (parts.protocol === 'https:' ? '443' : parts.protocol === 'http:' ? '80' : ''); | ||
return parts; | ||
}, | ||
/** | ||
* @see build | ||
*/ | ||
toString: function () { | ||
return this.build(); | ||
} | ||
/** | ||
* Expand the template replacing path variables with parameters | ||
* | ||
* @param {Object} [params] params to combine with current params. New params override existing params | ||
* @return {string} the expanded URL | ||
*/ | ||
build: function (params) { | ||
return buildUrl(this._template, mixin({}, this._params, params)); | ||
}, | ||
}; | ||
/** | ||
* @see build | ||
*/ | ||
toString: function () { | ||
return this.build(); | ||
} | ||
origin = location ? new UrlBuilder(location.href).parts() : undef; | ||
}; | ||
return UrlBuilder; | ||
}); | ||
origin = typeof location !== 'undefined' ? new UrlBuilder(location.href).parts() : void 0; | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }, | ||
typeof window !== 'undefined' ? window.location : void 0 | ||
// Boilerplate for AMD and Node | ||
)); | ||
module.exports = UrlBuilder; |
@@ -27,130 +27,121 @@ /* | ||
* | ||
* Converted to AMD and linter refinement by Scott Andrews | ||
* Linter refinement by Scott Andrews | ||
*/ | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
/*jshint bitwise: false */ | ||
define(function (/* require */) { | ||
/*jshint bitwise: false */ | ||
var digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; | ||
var digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; | ||
/** | ||
* Base64-encodes a string of text. | ||
* | ||
* @param {string} text The text to encode. | ||
* @return {string} The base64-encoded string. | ||
*/ | ||
function base64Encode(text) { | ||
/** | ||
* Base64-encodes a string of text. | ||
* | ||
* @param {string} text The text to encode. | ||
* @return {string} The base64-encoded string. | ||
*/ | ||
function base64Encode(text) { | ||
if (/([^\u0000-\u00ff])/.test(text)) { | ||
throw new Error('Can\'t base64 encode non-ASCII characters.'); | ||
} | ||
if (/([^\u0000-\u00ff])/.test(text)) { | ||
throw new Error('Can\'t base64 encode non-ASCII characters.'); | ||
} | ||
var i = 0, | ||
cur, prev, byteNum, | ||
result = []; | ||
var i = 0, | ||
cur, prev, byteNum, | ||
result = []; | ||
while (i < text.length) { | ||
while (i < text.length) { | ||
cur = text.charCodeAt(i); | ||
byteNum = i % 3; | ||
cur = text.charCodeAt(i); | ||
byteNum = i % 3; | ||
switch (byteNum) { | ||
case 0: //first byte | ||
result.push(digits.charAt(cur >> 2)); | ||
break; | ||
switch (byteNum) { | ||
case 0: //first byte | ||
result.push(digits.charAt(cur >> 2)); | ||
break; | ||
case 1: //second byte | ||
result.push(digits.charAt((prev & 3) << 4 | (cur >> 4))); | ||
break; | ||
case 1: //second byte | ||
result.push(digits.charAt((prev & 3) << 4 | (cur >> 4))); | ||
break; | ||
case 2: //third byte | ||
result.push(digits.charAt((prev & 0x0f) << 2 | (cur >> 6))); | ||
result.push(digits.charAt(cur & 0x3f)); | ||
break; | ||
} | ||
prev = cur; | ||
i += 1; | ||
} | ||
if (byteNum === 0) { | ||
result.push(digits.charAt((prev & 3) << 4)); | ||
result.push('=='); | ||
} else if (byteNum === 1) { | ||
result.push(digits.charAt((prev & 0x0f) << 2)); | ||
result.push('='); | ||
} | ||
return result.join(''); | ||
case 2: //third byte | ||
result.push(digits.charAt((prev & 0x0f) << 2 | (cur >> 6))); | ||
result.push(digits.charAt(cur & 0x3f)); | ||
break; | ||
} | ||
/** | ||
* Base64-decodes a string of text. | ||
* | ||
* @param {string} text The text to decode. | ||
* @return {string} The base64-decoded string. | ||
*/ | ||
function base64Decode(text) { | ||
prev = cur; | ||
i += 1; | ||
} | ||
//ignore white space | ||
text = text.replace(/\s/g, ''); | ||
if (byteNum === 0) { | ||
result.push(digits.charAt((prev & 3) << 4)); | ||
result.push('=='); | ||
} else if (byteNum === 1) { | ||
result.push(digits.charAt((prev & 0x0f) << 2)); | ||
result.push('='); | ||
} | ||
//first check for any unexpected input | ||
if (!(/^[a-z0-9\+\/\s]+\={0,2}$/i.test(text)) || text.length % 4 > 0) { | ||
throw new Error('Not a base64-encoded string.'); | ||
} | ||
return result.join(''); | ||
} | ||
//local variables | ||
var cur, prev, digitNum, | ||
i = 0, | ||
result = []; | ||
/** | ||
* Base64-decodes a string of text. | ||
* | ||
* @param {string} text The text to decode. | ||
* @return {string} The base64-decoded string. | ||
*/ | ||
function base64Decode(text) { | ||
//remove any equals signs | ||
text = text.replace(/\=/g, ''); | ||
//ignore white space | ||
text = text.replace(/\s/g, ''); | ||
//loop over each character | ||
while (i < text.length) { | ||
//first check for any unexpected input | ||
if (!(/^[a-z0-9\+\/\s]+\={0,2}$/i.test(text)) || text.length % 4 > 0) { | ||
throw new Error('Not a base64-encoded string.'); | ||
} | ||
cur = digits.indexOf(text.charAt(i)); | ||
digitNum = i % 4; | ||
//local variables | ||
var cur, prev, digitNum, | ||
i = 0, | ||
result = []; | ||
switch (digitNum) { | ||
//remove any equals signs | ||
text = text.replace(/\=/g, ''); | ||
//case 0: first digit - do nothing, not enough info to work with | ||
//loop over each character | ||
while (i < text.length) { | ||
case 1: //second digit | ||
result.push(String.fromCharCode(prev << 2 | cur >> 4)); | ||
break; | ||
cur = digits.indexOf(text.charAt(i)); | ||
digitNum = i % 4; | ||
case 2: //third digit | ||
result.push(String.fromCharCode((prev & 0x0f) << 4 | cur >> 2)); | ||
break; | ||
switch (digitNum) { | ||
case 3: //fourth digit | ||
result.push(String.fromCharCode((prev & 3) << 6 | cur)); | ||
break; | ||
} | ||
//case 0: first digit - do nothing, not enough info to work with | ||
prev = cur; | ||
i += 1; | ||
} | ||
case 1: //second digit | ||
result.push(String.fromCharCode(prev << 2 | cur >> 4)); | ||
break; | ||
//return a string | ||
return result.join(''); | ||
case 2: //third digit | ||
result.push(String.fromCharCode((prev & 0x0f) << 4 | cur >> 2)); | ||
break; | ||
case 3: //fourth digit | ||
result.push(String.fromCharCode((prev & 3) << 6 | cur)); | ||
break; | ||
} | ||
return { | ||
encode: base64Encode, | ||
decode: base64Decode | ||
}; | ||
prev = cur; | ||
i += 1; | ||
} | ||
}); | ||
//return a string | ||
return result.join(''); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
} | ||
module.exports = { | ||
encode: base64Encode, | ||
decode: base64Decode | ||
}; |
/* | ||
* Copyright 2013 the original author or authors | ||
* Copyright 2013-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,35 +8,25 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (/* require */) { | ||
module.exports = { | ||
return { | ||
/** | ||
* Find objects within a graph the contain a property of a certain name. | ||
* | ||
* NOTE: this method will not discover object graph cycles. | ||
* | ||
* @param {*} obj object to search on | ||
* @param {string} prop name of the property to search for | ||
* @param {Function} callback function to receive the found properties and their parent | ||
*/ | ||
findProperties: function findProperties(obj, prop, callback) { | ||
if (typeof obj !== 'object' || obj === null) { return; } | ||
if (prop in obj) { | ||
callback(obj[prop], obj, prop); | ||
} | ||
Object.keys(obj).forEach(function (key) { | ||
findProperties(obj[key], prop, callback); | ||
}); | ||
} | ||
/** | ||
* Find objects within a graph the contain a property of a certain name. | ||
* | ||
* NOTE: this method will not discover object graph cycles. | ||
* | ||
* @param {*} obj object to search on | ||
* @param {string} prop name of the property to search for | ||
* @param {Function} callback function to receive the found properties and their parent | ||
*/ | ||
findProperties: function findProperties(obj, prop, callback) { | ||
if (typeof obj !== 'object' || obj === null) { return; } | ||
if (prop in obj) { | ||
callback(obj[prop], obj, prop); | ||
} | ||
Object.keys(obj).forEach(function (key) { | ||
findProperties(obj[key], prop, callback); | ||
}); | ||
} | ||
}; | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
}; |
/* | ||
* Copyright 2013 the original author or authors | ||
* Copyright 2013-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,49 +8,40 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var attempt = require('./attempt'); | ||
var when; | ||
/** | ||
* Create a promise whose work is started only when a handler is registered. | ||
* | ||
* The work function will be invoked at most once. Thrown values will result | ||
* in promise rejection. | ||
* | ||
* @param {Function} work function whose ouput is used to resolve the | ||
* returned promise. | ||
* @returns {Promise} a lazy promise | ||
*/ | ||
function lazyPromise(work) { | ||
var started, resolver, promise, then; | ||
when = require('when'); | ||
started = false; | ||
/** | ||
* Create a promise whose work is started only when a handler is registered. | ||
* | ||
* The work function will be invoked at most once. Thrown values will result | ||
* in promise rejection. | ||
* | ||
* @param {Function} work function whose ouput is used to resolve the | ||
* returned promise. | ||
* @returns {Promise} a lazy promise | ||
*/ | ||
function lazyPromise(work) { | ||
var defer, started, resolver, promise, then; | ||
promise = new Promise(function (resolve, reject) { | ||
resolver = { | ||
resolve: resolve, | ||
reject: reject | ||
}; | ||
}); | ||
then = promise.then; | ||
defer = when.defer(); | ||
started = false; | ||
resolver = defer.resolver; | ||
promise = defer.promise; | ||
then = promise.then; | ||
promise.then = function () { | ||
if (!started) { | ||
started = true; | ||
when.attempt(work).then(resolver.resolve, resolver.reject); | ||
} | ||
return then.apply(promise, arguments); | ||
}; | ||
return promise; | ||
promise.then = function () { | ||
if (!started) { | ||
started = true; | ||
attempt(work).then(resolver.resolve, resolver.reject); | ||
} | ||
return then.apply(promise, arguments); | ||
}; | ||
return lazyPromise; | ||
return promise; | ||
} | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
module.exports = lazyPromise; |
/* | ||
* Copyright 2012-2013 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,42 +8,31 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
// derived from dojo.mixin | ||
define(function (/* require */) { | ||
var empty = {}; | ||
var empty = {}; | ||
/** | ||
* Mix the properties from the source object into the destination object. | ||
* When the same property occurs in more then one object, the right most | ||
* value wins. | ||
* | ||
* @param {Object} dest the object to copy properties to | ||
* @param {Object} sources the objects to copy properties from. May be 1 to N arguments, but not an Array. | ||
* @return {Object} the destination object | ||
*/ | ||
function mixin(dest /*, sources... */) { | ||
var i, l, source, name; | ||
/** | ||
* Mix the properties from the source object into the destination object. | ||
* When the same property occurs in more then one object, the right most | ||
* value wins. | ||
* | ||
* @param {Object} dest the object to copy properties to | ||
* @param {Object} sources the objects to copy properties from. May be 1 to N arguments, but not an Array. | ||
* @return {Object} the destination object | ||
*/ | ||
function mixin(dest /*, sources... */) { | ||
var i, l, source, name; | ||
if (!dest) { dest = {}; } | ||
for (i = 1, l = arguments.length; i < l; i += 1) { | ||
source = arguments[i]; | ||
for (name in source) { | ||
if (!(name in dest) || (dest[name] !== source[name] && (!(name in empty) || empty[name] !== source[name]))) { | ||
dest[name] = source[name]; | ||
} | ||
} | ||
if (!dest) { dest = {}; } | ||
for (i = 1, l = arguments.length; i < l; i += 1) { | ||
source = arguments[i]; | ||
for (name in source) { | ||
if (!(name in dest) || (dest[name] !== source[name] && (!(name in empty) || empty[name] !== source[name]))) { | ||
dest[name] = source[name]; | ||
} | ||
return dest; // Object | ||
} | ||
} | ||
return mixin; | ||
return dest; // Object | ||
} | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
module.exports = mixin; |
/* | ||
* Copyright 2012 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,32 +8,22 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (/* require */) { | ||
/** | ||
* Normalize HTTP header names using the pseudo camel case. | ||
* | ||
* For example: | ||
* content-type -> Content-Type | ||
* accepts -> Accepts | ||
* x-custom-header-name -> X-Custom-Header-Name | ||
* | ||
* @param {string} name the raw header name | ||
* @return {string} the normalized header name | ||
*/ | ||
function normalizeHeaderName(name) { | ||
return name.toLowerCase() | ||
.split('-') | ||
.map(function (chunk) { return chunk.charAt(0).toUpperCase() + chunk.slice(1); }) | ||
.join('-'); | ||
} | ||
/** | ||
* Normalize HTTP header names using the pseudo camel case. | ||
* | ||
* For example: | ||
* content-type -> Content-Type | ||
* accepts -> Accepts | ||
* x-custom-header-name -> X-Custom-Header-Name | ||
* | ||
* @param {string} name the raw header name | ||
* @return {string} the normalized header name | ||
*/ | ||
function normalizeHeaderName(name) { | ||
return name.toLowerCase() | ||
.split('-') | ||
.map(function (chunk) { return chunk.charAt(0).toUpperCase() + chunk.slice(1); }) | ||
.join('-'); | ||
} | ||
return normalizeHeaderName; | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
module.exports = normalizeHeaderName; |
/* | ||
* Copyright 2012 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,49 +8,39 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (/* require */) { | ||
// A poor man's pub-sub. A single listener is supported per topic. When | ||
// the topic is published, the listener is unsubscribed. | ||
// A poor man's pub-sub. A single listener is supported per topic. When | ||
// the topic is published, the listener is unsubscribed. | ||
var topics = {}; | ||
var topics = {}; | ||
/** | ||
* Publishes the message to the topic, invoking the listener. | ||
* | ||
* The listener is unsubscribed from the topic after receiving a message. | ||
* | ||
* @param {string} topic the topic to publish to | ||
* @param {Object} message message to publish | ||
*/ | ||
function publish(topic /* , message... */) { | ||
if (!topics[topic]) { return; } | ||
topics[topic].apply({}, Array.prototype.slice.call(arguments, 1)); | ||
// auto cleanup | ||
delete topics[topic]; | ||
} | ||
/** | ||
* Publishes the message to the topic, invoking the listener. | ||
* | ||
* The listener is unsubscribed from the topic after receiving a message. | ||
* | ||
* @param {string} topic the topic to publish to | ||
* @param {Object} message message to publish | ||
*/ | ||
function publish(topic /* , message... */) { | ||
if (!topics[topic]) { return; } | ||
topics[topic].apply({}, Array.prototype.slice.call(arguments, 1)); | ||
// auto cleanup | ||
delete topics[topic]; | ||
} | ||
/** | ||
* Register a callback function to receive notification of a message published to the topic. | ||
* | ||
* Any existing callback for the topic will be unsubscribed. | ||
* | ||
* @param {string} topic the topic to listen on | ||
* @param {Function} callback the callback to receive the message published to the topic | ||
*/ | ||
function subscribe(topic, callback) { | ||
topics[topic] = callback; | ||
} | ||
/** | ||
* Register a callback function to receive notification of a message published to the topic. | ||
* | ||
* Any existing callback for the topic will be unsubscribed. | ||
* | ||
* @param {string} topic the topic to listen on | ||
* @param {Function} callback the callback to receive the message published to the topic | ||
*/ | ||
function subscribe(topic, callback) { | ||
topics[topic] = callback; | ||
} | ||
return { | ||
publish: publish, | ||
subscribe: subscribe | ||
}; | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
module.exports = { | ||
publish: publish, | ||
subscribe: subscribe | ||
}; |
/* | ||
* Copyright 2014-2015 the original author or authors | ||
* Copyright 2014-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,134 +8,128 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
/*jshint latedef: nofunc */ | ||
var when = require('when'), | ||
normalizeHeaderName = require('./normalizeHeaderName'); | ||
var normalizeHeaderName = require('./normalizeHeaderName'); | ||
function property(promise, name) { | ||
return promise.then( | ||
function (value) { | ||
return value && value[name]; | ||
}, | ||
function (value) { | ||
return when.reject(value && value[name]); | ||
} | ||
); | ||
function property(promise, name) { | ||
return promise.then( | ||
function (value) { | ||
return value && value[name]; | ||
}, | ||
function (value) { | ||
return Promise.reject(value && value[name]); | ||
} | ||
); | ||
} | ||
/** | ||
* Obtain the response entity | ||
* | ||
* @returns {Promise} for the response entity | ||
*/ | ||
function entity() { | ||
/*jshint validthis:true */ | ||
return property(this, 'entity'); | ||
} | ||
/** | ||
* Obtain the response entity | ||
* | ||
* @returns {Promise} for the response entity | ||
*/ | ||
function entity() { | ||
/*jshint validthis:true */ | ||
return property(this, 'entity'); | ||
} | ||
/** | ||
* Obtain the response status | ||
* | ||
* @returns {Promise} for the response status | ||
*/ | ||
function status() { | ||
/*jshint validthis:true */ | ||
return property(property(this, 'status'), 'code'); | ||
} | ||
/** | ||
* Obtain the response status | ||
* | ||
* @returns {Promise} for the response status | ||
*/ | ||
function status() { | ||
/*jshint validthis:true */ | ||
return property(property(this, 'status'), 'code'); | ||
} | ||
/** | ||
* Obtain the response headers map | ||
* | ||
* @returns {Promise} for the response headers map | ||
*/ | ||
function headers() { | ||
/*jshint validthis:true */ | ||
return property(this, 'headers'); | ||
} | ||
/** | ||
* Obtain the response headers map | ||
* | ||
* @returns {Promise} for the response headers map | ||
*/ | ||
function headers() { | ||
/*jshint validthis:true */ | ||
return property(this, 'headers'); | ||
} | ||
/** | ||
* Obtain a specific response header | ||
* | ||
* @param {String} headerName the header to retrieve | ||
* @returns {Promise} for the response header's value | ||
*/ | ||
function header(headerName) { | ||
/*jshint validthis:true */ | ||
headerName = normalizeHeaderName(headerName); | ||
return property(this.headers(), headerName); | ||
} | ||
/** | ||
* Obtain a specific response header | ||
* | ||
* @param {String} headerName the header to retrieve | ||
* @returns {Promise} for the response header's value | ||
*/ | ||
function header(headerName) { | ||
/*jshint validthis:true */ | ||
headerName = normalizeHeaderName(headerName); | ||
return property(this.headers(), headerName); | ||
} | ||
/** | ||
* Follow a related resource | ||
* | ||
* The relationship to follow may be define as a plain string, an object | ||
* with the rel and params, or an array containing one or more entries | ||
* with the previous forms. | ||
* | ||
* Examples: | ||
* response.follow('next') | ||
* | ||
* response.follow({ rel: 'next', params: { pageSize: 100 } }) | ||
* | ||
* response.follow([ | ||
* { rel: 'items', params: { projection: 'noImages' } }, | ||
* 'search', | ||
* { rel: 'findByGalleryIsNull', params: { projection: 'noImages' } }, | ||
* 'items' | ||
* ]) | ||
* | ||
* @param {String|Object|Array} rels one, or more, relationships to follow | ||
* @returns ResponsePromise<Response> related resource | ||
*/ | ||
function follow(rels) { | ||
/*jshint validthis:true */ | ||
rels = [].concat(rels); | ||
return make(when.reduce(rels, function (response, rel) { | ||
if (typeof rel === 'string') { | ||
rel = { rel: rel }; | ||
} | ||
if (typeof response.entity.clientFor !== 'function') { | ||
throw new Error('Hypermedia response expected'); | ||
} | ||
var client = response.entity.clientFor(rel.rel); | ||
return client({ params: rel.params }); | ||
}, this)); | ||
} | ||
/** | ||
* Follow a related resource | ||
* | ||
* The relationship to follow may be define as a plain string, an object | ||
* with the rel and params, or an array containing one or more entries | ||
* with the previous forms. | ||
* | ||
* Examples: | ||
* response.follow('next') | ||
* | ||
* response.follow({ rel: 'next', params: { pageSize: 100 } }) | ||
* | ||
* response.follow([ | ||
* { rel: 'items', params: { projection: 'noImages' } }, | ||
* 'search', | ||
* { rel: 'findByGalleryIsNull', params: { projection: 'noImages' } }, | ||
* 'items' | ||
* ]) | ||
* | ||
* @param {String|Object|Array} rels one, or more, relationships to follow | ||
* @returns ResponsePromise<Response> related resource | ||
*/ | ||
function follow(rels) { | ||
/*jshint validthis:true */ | ||
rels = [].concat(rels); | ||
/** | ||
* Wrap a Promise as an ResponsePromise | ||
* | ||
* @param {Promise<Response>} promise the promise for an HTTP Response | ||
* @returns {ResponsePromise<Response>} wrapped promise for Response with additional helper methods | ||
*/ | ||
function make(promise) { | ||
promise.status = status; | ||
promise.headers = headers; | ||
promise.header = header; | ||
promise.entity = entity; | ||
promise.follow = follow; | ||
return promise; | ||
} | ||
return make(rels.reduce(function (response, rel) { | ||
return response.then(function (response) { | ||
if (typeof rel === 'string') { | ||
rel = { rel: rel }; | ||
} | ||
if (typeof response.entity.clientFor !== 'function') { | ||
throw new Error('Hypermedia response expected'); | ||
} | ||
var client = response.entity.clientFor(rel.rel); | ||
return client({ params: rel.params }); | ||
}); | ||
}, this)); | ||
} | ||
function responsePromise() { | ||
return make(when.apply(when, arguments)); | ||
} | ||
/** | ||
* Wrap a Promise as an ResponsePromise | ||
* | ||
* @param {Promise<Response>} promise the promise for an HTTP Response | ||
* @returns {ResponsePromise<Response>} wrapped promise for Response with additional helper methods | ||
*/ | ||
function make(promise) { | ||
promise.status = status; | ||
promise.headers = headers; | ||
promise.header = header; | ||
promise.entity = entity; | ||
promise.follow = follow; | ||
return promise; | ||
} | ||
responsePromise.make = make; | ||
responsePromise.reject = function (val) { | ||
return make(when.reject(val)); | ||
}; | ||
responsePromise.promise = function (func) { | ||
return make(when.promise(func)); | ||
}; | ||
function responsePromise(obj, callback, errback) { | ||
return make(Promise.resolve(obj).then(callback, errback)); | ||
} | ||
return responsePromise; | ||
responsePromise.make = make; | ||
responsePromise.reject = function (val) { | ||
return make(Promise.reject(val)); | ||
}; | ||
responsePromise.promise = function (func) { | ||
return make(new Promise(func)); | ||
}; | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
module.exports = responsePromise; |
/* | ||
* Copyright 2015 the original author or authors | ||
* Copyright 2015-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,174 +8,164 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (/* require */) { | ||
var charMap; | ||
var charMap; | ||
charMap = (function () { | ||
var strings = { | ||
alpha: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', | ||
digit: '0123456789' | ||
}; | ||
charMap = (function () { | ||
var strings = { | ||
alpha: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', | ||
digit: '0123456789' | ||
}; | ||
strings.genDelims = ':/?#[]@'; | ||
strings.subDelims = '!$&\'()*+,;='; | ||
strings.reserved = strings.genDelims + strings.subDelims; | ||
strings.unreserved = strings.alpha + strings.digit + '-._~'; | ||
strings.url = strings.reserved + strings.unreserved; | ||
strings.scheme = strings.alpha + strings.digit + '+-.'; | ||
strings.userinfo = strings.unreserved + strings.subDelims + ':'; | ||
strings.host = strings.unreserved + strings.subDelims; | ||
strings.port = strings.digit; | ||
strings.pchar = strings.unreserved + strings.subDelims + ':@'; | ||
strings.segment = strings.pchar; | ||
strings.path = strings.segment + '/'; | ||
strings.query = strings.pchar + '/?'; | ||
strings.fragment = strings.pchar + '/?'; | ||
strings.genDelims = ':/?#[]@'; | ||
strings.subDelims = '!$&\'()*+,;='; | ||
strings.reserved = strings.genDelims + strings.subDelims; | ||
strings.unreserved = strings.alpha + strings.digit + '-._~'; | ||
strings.url = strings.reserved + strings.unreserved; | ||
strings.scheme = strings.alpha + strings.digit + '+-.'; | ||
strings.userinfo = strings.unreserved + strings.subDelims + ':'; | ||
strings.host = strings.unreserved + strings.subDelims; | ||
strings.port = strings.digit; | ||
strings.pchar = strings.unreserved + strings.subDelims + ':@'; | ||
strings.segment = strings.pchar; | ||
strings.path = strings.segment + '/'; | ||
strings.query = strings.pchar + '/?'; | ||
strings.fragment = strings.pchar + '/?'; | ||
return Object.keys(strings).reduce(function (charMap, set) { | ||
charMap[set] = strings[set].split('').reduce(function (chars, myChar) { | ||
chars[myChar] = true; | ||
return chars; | ||
}, {}); | ||
return charMap; | ||
}, {}); | ||
}()); | ||
return Object.keys(strings).reduce(function (charMap, set) { | ||
charMap[set] = strings[set].split('').reduce(function (chars, myChar) { | ||
chars[myChar] = true; | ||
return chars; | ||
}, {}); | ||
return charMap; | ||
}, {}); | ||
}()); | ||
function encode(str, allowed) { | ||
if (typeof str !== 'string') { | ||
throw new Error('String required for URL encoding'); | ||
} | ||
return str.split('').map(function (myChar) { | ||
if (allowed.hasOwnProperty(myChar)) { | ||
return myChar; | ||
} | ||
var code = myChar.charCodeAt(0); | ||
if (code <= 127) { | ||
var encoded = code.toString(16).toUpperCase(); | ||
return '%' + (encoded.length % 2 === 1 ? '0' : '') + encoded; | ||
} | ||
else { | ||
return encodeURIComponent(myChar).toUpperCase(); | ||
} | ||
}).join(''); | ||
function encode(str, allowed) { | ||
if (typeof str !== 'string') { | ||
throw new Error('String required for URL encoding'); | ||
} | ||
return str.split('').map(function (myChar) { | ||
if (allowed.hasOwnProperty(myChar)) { | ||
return myChar; | ||
} | ||
function makeEncoder(allowed) { | ||
allowed = allowed || charMap.unreserved; | ||
return function (str) { | ||
return encode(str, allowed); | ||
}; | ||
var code = myChar.charCodeAt(0); | ||
if (code <= 127) { | ||
var encoded = code.toString(16).toUpperCase(); | ||
return '%' + (encoded.length % 2 === 1 ? '0' : '') + encoded; | ||
} | ||
function decode(str) { | ||
return decodeURIComponent(str); | ||
else { | ||
return encodeURIComponent(myChar).toUpperCase(); | ||
} | ||
}).join(''); | ||
} | ||
return { | ||
function makeEncoder(allowed) { | ||
allowed = allowed || charMap.unreserved; | ||
return function (str) { | ||
return encode(str, allowed); | ||
}; | ||
} | ||
/* | ||
* Decode URL encoded strings | ||
* | ||
* @param {string} URL encoded string | ||
* @returns {string} URL decoded string | ||
*/ | ||
decode: decode, | ||
function decode(str) { | ||
return decodeURIComponent(str); | ||
} | ||
/* | ||
* URL encode a string | ||
* | ||
* All but alpha-numerics and a very limited set of punctuation - . _ ~ are | ||
* encoded. | ||
* | ||
* @param {string} string to encode | ||
* @returns {string} URL encoded string | ||
*/ | ||
encode: makeEncoder(), | ||
module.exports = { | ||
/* | ||
* URL encode a URL | ||
* | ||
* All character permitted anywhere in a URL are left unencoded even | ||
* if that character is not permitted in that portion of a URL. | ||
* | ||
* Note: This method is typically not what you want. | ||
* | ||
* @param {string} string to encode | ||
* @returns {string} URL encoded string | ||
*/ | ||
encodeURL: makeEncoder(charMap.url), | ||
/* | ||
* Decode URL encoded strings | ||
* | ||
* @param {string} URL encoded string | ||
* @returns {string} URL decoded string | ||
*/ | ||
decode: decode, | ||
/* | ||
* URL encode the scheme portion of a URL | ||
* | ||
* @param {string} string to encode | ||
* @returns {string} URL encoded string | ||
*/ | ||
encodeScheme: makeEncoder(charMap.scheme), | ||
/* | ||
* URL encode a string | ||
* | ||
* All but alpha-numerics and a very limited set of punctuation - . _ ~ are | ||
* encoded. | ||
* | ||
* @param {string} string to encode | ||
* @returns {string} URL encoded string | ||
*/ | ||
encode: makeEncoder(), | ||
/* | ||
* URL encode the user info portion of a URL | ||
* | ||
* @param {string} string to encode | ||
* @returns {string} URL encoded string | ||
*/ | ||
encodeUserInfo: makeEncoder(charMap.userinfo), | ||
/* | ||
* URL encode a URL | ||
* | ||
* All character permitted anywhere in a URL are left unencoded even | ||
* if that character is not permitted in that portion of a URL. | ||
* | ||
* Note: This method is typically not what you want. | ||
* | ||
* @param {string} string to encode | ||
* @returns {string} URL encoded string | ||
*/ | ||
encodeURL: makeEncoder(charMap.url), | ||
/* | ||
* URL encode the host portion of a URL | ||
* | ||
* @param {string} string to encode | ||
* @returns {string} URL encoded string | ||
*/ | ||
encodeHost: makeEncoder(charMap.host), | ||
/* | ||
* URL encode the scheme portion of a URL | ||
* | ||
* @param {string} string to encode | ||
* @returns {string} URL encoded string | ||
*/ | ||
encodeScheme: makeEncoder(charMap.scheme), | ||
/* | ||
* URL encode the port portion of a URL | ||
* | ||
* @param {string} string to encode | ||
* @returns {string} URL encoded string | ||
*/ | ||
encodePort: makeEncoder(charMap.port), | ||
/* | ||
* URL encode the user info portion of a URL | ||
* | ||
* @param {string} string to encode | ||
* @returns {string} URL encoded string | ||
*/ | ||
encodeUserInfo: makeEncoder(charMap.userinfo), | ||
/* | ||
* URL encode a path segment portion of a URL | ||
* | ||
* @param {string} string to encode | ||
* @returns {string} URL encoded string | ||
*/ | ||
encodePathSegment: makeEncoder(charMap.segment), | ||
/* | ||
* URL encode the host portion of a URL | ||
* | ||
* @param {string} string to encode | ||
* @returns {string} URL encoded string | ||
*/ | ||
encodeHost: makeEncoder(charMap.host), | ||
/* | ||
* URL encode the path portion of a URL | ||
* | ||
* @param {string} string to encode | ||
* @returns {string} URL encoded string | ||
*/ | ||
encodePath: makeEncoder(charMap.path), | ||
/* | ||
* URL encode the port portion of a URL | ||
* | ||
* @param {string} string to encode | ||
* @returns {string} URL encoded string | ||
*/ | ||
encodePort: makeEncoder(charMap.port), | ||
/* | ||
* URL encode the query portion of a URL | ||
* | ||
* @param {string} string to encode | ||
* @returns {string} URL encoded string | ||
*/ | ||
encodeQuery: makeEncoder(charMap.query), | ||
/* | ||
* URL encode a path segment portion of a URL | ||
* | ||
* @param {string} string to encode | ||
* @returns {string} URL encoded string | ||
*/ | ||
encodePathSegment: makeEncoder(charMap.segment), | ||
/* | ||
* URL encode the fragment portion of a URL | ||
* | ||
* @param {string} string to encode | ||
* @returns {string} URL encoded string | ||
*/ | ||
encodeFragment: makeEncoder(charMap.fragment) | ||
/* | ||
* URL encode the path portion of a URL | ||
* | ||
* @param {string} string to encode | ||
* @returns {string} URL encoded string | ||
*/ | ||
encodePath: makeEncoder(charMap.path), | ||
}; | ||
/* | ||
* URL encode the query portion of a URL | ||
* | ||
* @param {string} string to encode | ||
* @returns {string} URL encoded string | ||
*/ | ||
encodeQuery: makeEncoder(charMap.query), | ||
}); | ||
/* | ||
* URL encode the fragment portion of a URL | ||
* | ||
* @param {string} string to encode | ||
* @returns {string} URL encoded string | ||
*/ | ||
encodeFragment: makeEncoder(charMap.fragment) | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
}; |
/* | ||
* Copyright 2015 the original author or authors | ||
* Copyright 2015-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,96 +8,58 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
var undef; | ||
var uriEncoder, operations, prefixRE; | ||
define(function (require) { | ||
uriEncoder = require('./uriEncoder'); | ||
var uriEncoder, operations, prefixRE; | ||
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 } | ||
}; | ||
uriEncoder = require('./uriEncoder'); | ||
function apply(operation, expression, params) { | ||
/*jshint maxcomplexity:11 */ | ||
return expression.split(',').reduce(function (result, variable) { | ||
var opts, value; | ||
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 } | ||
}; | ||
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]); | ||
} | ||
function apply(operation, expression, params) { | ||
/*jshint maxcomplexity:11 */ | ||
return expression.split(',').reduce(function (result, variable) { | ||
var opts, value; | ||
variable = uriEncoder.decode(variable); | ||
value = params[variable]; | ||
opts = {}; | ||
if (variable.slice(-1) === '*') { | ||
variable = variable.slice(0, -1); | ||
opts.explode = true; | ||
if (value === void 0 || 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; | ||
} | ||
} | ||
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; | ||
result += operation.first; | ||
if (operation.named) { | ||
@@ -107,68 +69,94 @@ result += operation.encoder(variable); | ||
} | ||
result += operation.encoder(value); | ||
} | ||
result += operation.encoder(value); | ||
return result; | ||
}, ''); | ||
}, result); | ||
} | ||
function expandExpression(expression, params) { | ||
var operation; | ||
operation = operations[expression.slice(0,1)]; | ||
if (operation) { | ||
expression = expression.slice(1); | ||
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; | ||
}, result); | ||
} | ||
else { | ||
value = String(value); | ||
if (opts.maxLength) { | ||
value = value.slice(0, opts.maxLength); | ||
} | ||
else { | ||
operation = operations['']; | ||
result += result.length ? operation.separator : operation.first; | ||
if (operation.named) { | ||
result += operation.encoder(variable); | ||
result += value.length ? '=' : operation.empty; | ||
} | ||
result += operation.encoder(value); | ||
} | ||
if (operation.reserved) { | ||
throw new Error('Reserved expression operations are not supported'); | ||
} | ||
return result; | ||
}, ''); | ||
} | ||
return apply(operation, expression, params); | ||
} | ||
function expandExpression(expression, params) { | ||
var operation; | ||
function expandTemplate(template, params) { | ||
var start, end, uri; | ||
operation = operations[expression.slice(0,1)]; | ||
if (operation) { | ||
expression = expression.slice(1); | ||
} | ||
else { | ||
operation = operations['']; | ||
} | ||
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); | ||
} | ||
if (operation.reserved) { | ||
throw new Error('Reserved expression operations are not supported'); | ||
} | ||
return uri; | ||
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 { | ||
return uri; | ||
} | ||
/** | ||
* 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 | ||
module.exports = { | ||
}; | ||
/** | ||
* 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 | ||
)); | ||
}; |
122
wire.js
/* | ||
* Copyright 2012-2015 the original author or authors | ||
* Copyright 2012-2016 the original author or authors | ||
* @license MIT, see LICENSE.txt for details | ||
@@ -8,75 +8,65 @@ * | ||
(function (define) { | ||
'use strict'; | ||
'use strict'; | ||
define(function (require) { | ||
var client, when, pipeline, plugin; | ||
var client, when, pipeline, plugin; | ||
client = require('./client/default'); | ||
when = require('when'); | ||
pipeline = require('when/pipeline'); | ||
client = require('./client/default'); | ||
when = require('when'); | ||
pipeline = require('when/pipeline'); | ||
function normalizeRestFactoryConfig(spec, wire) { | ||
var config = {}; | ||
function normalizeRestFactoryConfig(spec, wire) { | ||
var config = {}; | ||
config.parent = wire(spec.parent || client); | ||
config.interceptors = when.all((Array.isArray(spec) ? spec : spec.interceptors || []).map(function (interceptorDef) { | ||
var interceptorConfig = interceptorDef.config; | ||
delete interceptorDef.config; | ||
return when.all([ | ||
wire(typeof interceptorDef === 'string' ? { module: interceptorDef } : interceptorDef), | ||
wire(interceptorConfig) | ||
]).spread(function (interceptor, config) { | ||
return { interceptor: interceptor, config: config }; | ||
}); | ||
})); | ||
config.parent = wire(spec.parent || client); | ||
config.interceptors = when.all((Array.isArray(spec) ? spec : spec.interceptors || []).map(function (interceptorDef) { | ||
var interceptorConfig = interceptorDef.config; | ||
delete interceptorDef.config; | ||
return when.all([ | ||
wire(typeof interceptorDef === 'string' ? { module: interceptorDef } : interceptorDef), | ||
wire(interceptorConfig) | ||
]).spread(function (interceptor, config) { | ||
return { interceptor: interceptor, config: config }; | ||
}); | ||
})); | ||
return config; | ||
} | ||
return config; | ||
} | ||
/** | ||
* Creates a rest client for the "rest" factory. | ||
* @param resolver | ||
* @param spec | ||
* @param wire | ||
*/ | ||
function restFactory(resolver, spec, wire) { | ||
var config = normalizeRestFactoryConfig(spec.rest || spec.options, wire); | ||
return config.parent.then(function (parent) { | ||
return config.interceptors.then(function (interceptorDefs) { | ||
pipeline(interceptorDefs.map(function (interceptorDef) { | ||
return function (parent) { | ||
return interceptorDef.interceptor(parent, interceptorDef.config); | ||
}; | ||
}), parent).then(resolver.resolve, resolver.reject); | ||
}); | ||
}); | ||
} | ||
/** | ||
* Creates a rest client for the "rest" factory. | ||
* @param resolver | ||
* @param spec | ||
* @param wire | ||
*/ | ||
function restFactory(resolver, spec, wire) { | ||
var config = normalizeRestFactoryConfig(spec.rest || spec.options, wire); | ||
return config.parent.then(function (parent) { | ||
return config.interceptors.then(function (interceptorDefs) { | ||
pipeline(interceptorDefs.map(function (interceptorDef) { | ||
return function (parent) { | ||
return interceptorDef.interceptor(parent, interceptorDef.config); | ||
}; | ||
}), parent).then(resolver.resolve, resolver.reject); | ||
}); | ||
}); | ||
/** | ||
* The plugin instance. Can be the same for all wiring runs | ||
*/ | ||
plugin = { | ||
resolvers: { | ||
client: function () { | ||
throw new Error('rest.js: client! wire reference resolved is deprecated, use \'rest\' facotry instead'); | ||
} | ||
}, | ||
factories: { | ||
rest: restFactory | ||
} | ||
}; | ||
/** | ||
* The plugin instance. Can be the same for all wiring runs | ||
*/ | ||
plugin = { | ||
resolvers: { | ||
client: function () { | ||
throw new Error('rest.js: client! wire reference resolved is deprecated, use \'rest\' facotry instead'); | ||
} | ||
}, | ||
factories: { | ||
rest: restFactory | ||
} | ||
}; | ||
return { | ||
wire$plugin: function restPlugin(/* ready, destroyed, options */) { | ||
return plugin; | ||
} | ||
}; | ||
}); | ||
}( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
)); | ||
module.exports = { | ||
wire$plugin: function restPlugin(/* ready, destroyed, options */) { | ||
return plugin; | ||
} | ||
}; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
0
389
52
416280
5
128
8892
4
- Removedwhen@~3
- Removedwhen@3.7.8(transitive)