From 3a70de7d2b2e7d2bc9f9cd65eb0391a6a4131e76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Germade?= Date: Fri, 16 Feb 2018 18:47:46 +0100 Subject: [PATCH] updating dist --- dist/LICENSE | 21 +++ dist/README.md | 81 ++++++++ dist/browser.js | 396 +++++++++++++++++++++++++++++++++++++++ dist/browser.umd.js | 402 +++++++++++++++++++++++++++++++++++++++ dist/deserialize.js | 37 ++++ dist/fetch.js | 441 +++++++++++++++++++++++++++++++++++++++++++ dist/fetch.umd.js | 447 ++++++++++++++++++++++++++++++++++++++++++++ dist/http-node.js | 70 +++++++ dist/package.json | 33 ++++ dist/wrapper.js | 324 ++++++++++++++++++++++++++++++++ 10 files changed, 2252 insertions(+) create mode 100644 dist/LICENSE create mode 100644 dist/README.md create mode 100644 dist/browser.js create mode 100644 dist/browser.umd.js create mode 100644 dist/deserialize.js create mode 100644 dist/fetch.js create mode 100644 dist/fetch.umd.js create mode 100644 dist/http-node.js create mode 100644 dist/package.json create mode 100644 dist/wrapper.js diff --git a/dist/LICENSE b/dist/LICENSE new file mode 100644 index 0000000..2fdfcc3 --- /dev/null +++ b/dist/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Jesús Manuel Germade Castiñeiras + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dist/README.md b/dist/README.md new file mode 100644 index 0000000..f9203e9 --- /dev/null +++ b/dist/README.md @@ -0,0 +1,81 @@ + +# http-rest + +`ajax / http` wrapper for browser and node that allows config inheritance ( uses [fetch API](https://developer.mozilla.org/es/docs/Web/API/Fetch_API) when present ) + +[![npm](https://img.shields.io/npm/v/http-rest.svg)](https://www.npmjs.com/package/http-rest) [![bower](https://img.shields.io/bower/v/http-rest.svg)](http://bower.io/search/?q=http-rest) +[![Build Status](https://travis-ci.org/kiltjs/http-rest.svg?branch=master)](https://travis-ci.org/kiltjs/http-rest) +[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) + +### Installation + +> Node module + +``` sh +npm install http-rest --save +``` +``` js +var $http = require('http-rest'); +``` + +> Browser using node bundler + +``` js +var $http = require('http-rest/browser'); + +// if you want to use fetch API when present +var $http = require('http-rest/fetch'); +``` + +> Browser using bower + +``` sh +bower install http-rest --save +``` + +``` js +// if you want to use fetch API when present (in bower.json) +// ... +"overrides": { + "http-rest": { + "main": "dist/fetch.js" + } +}, +// ... +``` + + +### Usage + +``` js +// GET .../items?prop1=value1 +$http.get('/items', { params: { prop1: value1 } }); + +$http.post('/items', { + sample: 'payload' +}); + +$http.put('/items/:itemId', { + sample: 'payload' +}); + +$http.patch('/items/:itemId', { + sample: 'payload' +}); + +$http.delete('/items/:itemId'); +``` + +### Base configurations + +``` js +var httpItems = $http.base('items'); + +httpItems.post({ prop1: 'value1' }); + +httpItems.get(itemId); + +httpItems.put(itemId, { prop1: 'another value' }); + +httpItems.delete(itemId); +``` diff --git a/dist/browser.js b/dist/browser.js new file mode 100644 index 0000000..7a96137 --- /dev/null +++ b/dist/browser.js @@ -0,0 +1,396 @@ +'use strict'; + +var isType = function (type, o) { + return o ? typeof o === type : function (_o) { + return typeof _o === type; + }; + }; + +function isObject (o) { + return o !== null && typeof o === 'object'; +} + +var isArray = Array.isArray || function (o) { + return o instanceof Array; +}; + +var isString = isType('string'); +var isFunction = isType('function'); + +function toUnderscoreCase (text) { + return text.replace(/-/g, '_').replace(/([a-z])([A-Z])/, function (matched, a, b) { return a + '_' + b; }).toLowerCase(); +} + +function toCamelCase (text) { + return text.replace(/([a-z])[-_]([a-z])/g, function (matched, a, b) { return a + b.toUpperCase(); }); +} + +function toHeaderCase (text) { + var key = text.replace(/_/g, '-').replace(/([a-z])([A-Z])/, function (matched, a, b) { return a + '-' + b; }); + return key[0].toUpperCase() + key.substr(1).toLowerCase().replace(/-[a-z]/g, function (matched) { return matched.toUpperCase(); }); +} + +function _passThrought (value) { + return value; +} + +var case_formatters = { + underscore: toUnderscoreCase, + camel: toCamelCase, + header: toHeaderCase, +}; + +function mapObject (o, iteratee, thisArg, mapFormatter) { + var result = {}; + mapFormatter = mapFormatter || _passThrought; + for( var key in o ) { + result[mapFormatter(key)] = iteratee.call(thisArg, o[key], key); + } + return result; +} + +function copy (src, mapFormatter) { + if( typeof mapFormatter === 'string' ) mapFormatter = case_formatters[mapFormatter]; + + if( isArray(src) ) { + return src.map(function (item) { + return copy(item, mapFormatter); + }); + } + + if( isObject(src) ) { + return mapObject(src, function (item) { + return copy(item, mapFormatter); + }, src, mapFormatter); + } + + return src; +} + +function extend (dest, src) { + dest = dest || {}; + for( var key in src ) dest[key] = src[key]; + return dest; +} + +function _mergeArrays(dest, src, concatArrays) { + if( !concatArrays ) return src.map(function (item) { return copy(item); }); + [].push.apply(dest, src); + for( var i = 0, n = src.length ; i < n ; i++ ) { + dest.push( dest[i] ? merge(dest[i], src[i]) : copy(src[i]) ); + } + return dest; +} + +function merge (dest, src, concatArrays) { + if( typeof dest !== typeof src ) { + if( isArray(src) ) dest = []; + else if( typeof src === 'object' ) dest = {}; + else return src; + } + if( isArray(src) ) return _mergeArrays(dest, src, concatArrays); + if( typeof src === 'object' ) { + for( var key in src ) { + dest[key] = merge(dest[key], src[key]); + } + return dest; + } + return src; +} + +function resolveFunctions (o, args, this_arg) { + for( var key in o ) { + if( isFunction(o[key]) ) { + o[key] = o[key].apply(this_arg, args); + } else if( isObject(o[key]) ) { + o[key] = resolveFunctions(o[key], args, this_arg); + } + } + return o; +} + +var RE_contentType = /([^/]+)\/([^+]+\+)?([^;]*)/; +function parseContentType(contentType) { + var matches = contentType && contentType.match(RE_contentType); + return matches ? matches[3] : 'text'; +} + + +var arrayPush = Array.prototype.push; +var arraySlice = Array.prototype.slice; + +function _sanitizePath(path, i, last) { + if( i > 0 ) path = path.replace(/^\.*\//, ''); + if( !last ) path = path.replace(/\/$/, ''); + return path.split(/\/+/); +} + +function _joinPaths (paths) { + var last = paths.length - 1; + return paths.reduce(function (result, path, i) { + if( path === '.' ) return result; + if( /^[a-z]+:\/\//.test(path) ) return [i === last ? path : path.replace(/\/$/, '')]; + if( /^\//.test(path) ) return _sanitizePath(path, 0, i === last ); + + path = path.replace(/\.\.\//g, function () { + result = result.slice(0, -1); + return ''; + }).replace(/\.\//, ''); + + arrayPush.apply( result, _sanitizePath(path, i, i === last) ); + + return result; + + }, []).join('/'); +} + +function _unraise (paths) { + var result = []; + + paths.forEach(function (path) { + if( !path ) return; + + // https://jsperf.com/array-prototype-push-apply-vs-concat/17 + if( path instanceof Array ) arrayPush.apply(result, _unraise(path) ); + else if( typeof path === 'string' ) result.push(path); + else throw new Error('paths parts should be Array or String'); + }); + + return result; +} + +function joinPaths () { + return _joinPaths( _unraise(arraySlice.call(arguments)) ); +} + +function keysTobrackets (keys) { + return keys.reduce(function (result, key, i) { + return result + (i ? ( '[' + key + ']' ) : key); + }, ''); +} + +function _serialize (data, params, keys) { + + if( typeof data === 'object' ) { + if( Array.isArray(data) ) { + for( var i = 0, n = data.length; i < n ; i++ ) { + _serialize( data[i], params, keys.concat( typeof data[i] === 'object' ? i : '' ) ); + } + } else { + for( var k in data ) { + _serialize( data[k], params, keys.concat(k) ); + } + } + } else { + params.push( keysTobrackets(keys) + '=' + encodeURIComponent('' + data) ); + // params.push( keysTobrackets(keys) + '=' + '' + data ); + } + + return params; +} + +function serializeQS (data) { + // eslint-disable-next-line + // console.log('serialize', data, _serialize(data, [], []) ); + return _serialize(data, [], []).join('&'); +} + +var http_defaults = {}; +var makeRequest = function () {}; +var Parole = typeof Promise !== 'undefined' ? Promise : function () {}; + +function _plainOptions (_options_pile, method) { + var options_pile = _options_pile ? copy(_options_pile) : []; + + var plain_options = {}, + options = options_pile.shift(); + + while( options ) { + merge(plain_options, options); + options = options_pile.shift(); + } + + if(method) plain_options.method = method; + + plain_options.url = joinPaths( _options_pile.reduce(function (paths, options) { + if( !options.url ) return paths; + + if( options.url instanceof Function ) return paths.concat( options.url(plain_options) ); + + return paths.concat(options.url); + }, []) ); + + return plain_options; +} + +function http$1 (url, _config, body) { + + var config = _plainOptions([http_defaults, _config || {}]); + + config = copy( isObject(url) ? url : config || {} ); + config.url = url === config ? config.url : url; + config.method = config.method ? config.method.toUpperCase() : 'GET'; + config.timestamp = new Date().getTime(); + config.body = body || config.body; + + if( !isString(config.url) ) throw new Error('url must be a string'); + + config = resolveFunctions(config, [config]); + + if( config.params ) { + config.url += ( /\?/.test(config.url) ? '&' : '?' ) + serializeQS( config.params ).join('&'); + } + + var headers = copy(config.headers || {}, 'underscore'); + + if( config.json && !config.body ) { + headers.content_type = headers.content_type || 'application/json'; + config.body = JSON.stringify(config.json); + } else if( headers.content_type === 'application/json' && typeof config.body === 'object' ) { + config.body = JSON.stringify(config.body); + } else if( typeof config.body === 'object' && + !Blob.prototype.isPrototypeOf(config.body) && + !FormData.prototype.isPrototypeOf(config.body) ) { + config.body = JSON.stringify(config.body); + headers.content_type = headers.content_type || 'application/json'; + } else if( !headers.content_type ) headers.content_type || 'application/json'; + + headers.accept = headers.accept || headers.content_type || 'application/json'; + + config.headers = copy(headers, 'header'); + + var request = new Parole(function (resolve, reject) { + makeRequest(config, resolve, reject); + }); + + request.config = config; + + return request; +} + +http$1.responseData = function (response) { + return response.data; +}; + +function httpBase (target, options, options_pile) { + var requestMethod = function (method, hasData) { + return hasData ? function (url, data, _options) { + if( typeof url === 'object' ) { _options = data; data = url; url = null; } + _options = Object.create(_options || {}); + if( url ) _options.url = url; + _options = _plainOptions( _options ? options_pile.concat(_options) : options_pile, method ); + return http$1( _options.url, _options, data ); + } : function (url, _options, params) { + if( typeof url === 'object' ) { params = _options; _options = url; url = null; } + _options = Object.create(_options || {}); + if( url ) _options.url = url; + if( params ) _options.params = params; + _options = _plainOptions( _options ? options_pile.concat(_options) : options_pile, method ); + return http$1( _options.url, _options ); + }; + }; + + return extend(target, { + head: requestMethod('head'), + get: requestMethod('get'), + post: requestMethod('post', true), + put: requestMethod('put', true), + patch: requestMethod('patch', true), + delete: requestMethod('delete'), + base: function (url, _options) { + var options = _options ? Object.create(_options) :{}; + options.url = url; + return httpBase( requestMethod('get'), options, options_pile.concat(options) ); + }, + config: function (_options) { + if( options === undefined ) return _plainOptions( [http_defaults].concat(this.options_pile).concat(options) ); + merge( options, _options ); + }, + responseData: http$1.responseData, + }); +} + +http$1.base = httpBase; +httpBase(http$1, http_defaults, []); + +http$1.usePromise = function (P) { Parole = P; return http$1; }; +http$1.useRequest = function (request) { + if( !isFunction(request) ) throw new Error('request should be a function'); + else makeRequest = request; + return http$1; +}; + +http$1.config = function (options) { + merge( http_defaults, options ); + return http$1; +}; + +/* global ActiveXObject */ + +var parseData = { + json: function (data) { + return JSON.parse(data); + } +}; + +function _getXMLHeaders (request) { + var headers = {}; + request.getAllResponseHeaders().split('\n').forEach(function (headerLine) { + var matched = headerLine.match(/(.*?):(.*)/); + if( matched ) { + headers[toUnderscoreCase(matched[1])] = matched[2].trim(); + } + }); + + return headers; +} + +function xmlRequest (config, resolve, reject) { + + var request = null; + + try { // Firefox, Opera 8.0+, Safari + request = new XMLHttpRequest(); + } catch (e) { // Internet Explorer + try { request = new ActiveXObject('Msxml2.XMLHTTP'); } // jshint ignore:line + catch (er) { request = new ActiveXObject('Microsoft.XMLHTTP'); } // jshint ignore:line + } + if( request === null ) { throw 'Browser does not support HTTP Request'; } + + if( config.withCredentials || config.credentials === 'include' ) request.withCredentials = true; + + request.onreadystatechange = function() { + if( request.readyState === 'complete' || request.readyState === 4 ) { + // var type = parseContentType( request.getResponseHeader('Content-Type') ), + var headers = _getXMLHeaders(request), + type = parseContentType( headers.contentType ), + response = { + config: config, + status: request.status, + statusText: request.statusText, + headers: headers, + data: type === 'xml' ? request.responseXML : (parseData[type] ? parseData[type](request.responseText) : request.responseText), + }; + + if( request.status >= 200 && request.status < 400 ) { + resolve( response ); + } else { + reject( response ); + } + } + }; + + request.open(config.method, config.url, true); + + if( config.headers ) { + for( var key in config.headers ) { + request.setRequestHeader( key, config.headers[key] ); + } + } + + request.send( config.body ); +} + +http$1.useRequest(xmlRequest); + +module.exports = http$1; diff --git a/dist/browser.umd.js b/dist/browser.umd.js new file mode 100644 index 0000000..9bd2c97 --- /dev/null +++ b/dist/browser.umd.js @@ -0,0 +1,402 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.$http = factory()); +}(this, (function () { 'use strict'; + +var isType = function (type, o) { + return o ? typeof o === type : function (_o) { + return typeof _o === type; + }; + }; + +function isObject (o) { + return o !== null && typeof o === 'object'; +} + +var isArray = Array.isArray || function (o) { + return o instanceof Array; +}; + +var isString = isType('string'); +var isFunction = isType('function'); + +function toUnderscoreCase (text) { + return text.replace(/-/g, '_').replace(/([a-z])([A-Z])/, function (matched, a, b) { return a + '_' + b; }).toLowerCase(); +} + +function toCamelCase (text) { + return text.replace(/([a-z])[-_]([a-z])/g, function (matched, a, b) { return a + b.toUpperCase(); }); +} + +function toHeaderCase (text) { + var key = text.replace(/_/g, '-').replace(/([a-z])([A-Z])/, function (matched, a, b) { return a + '-' + b; }); + return key[0].toUpperCase() + key.substr(1).toLowerCase().replace(/-[a-z]/g, function (matched) { return matched.toUpperCase(); }); +} + +function _passThrought (value) { + return value; +} + +var case_formatters = { + underscore: toUnderscoreCase, + camel: toCamelCase, + header: toHeaderCase, +}; + +function mapObject (o, iteratee, thisArg, mapFormatter) { + var result = {}; + mapFormatter = mapFormatter || _passThrought; + for( var key in o ) { + result[mapFormatter(key)] = iteratee.call(thisArg, o[key], key); + } + return result; +} + +function copy (src, mapFormatter) { + if( typeof mapFormatter === 'string' ) mapFormatter = case_formatters[mapFormatter]; + + if( isArray(src) ) { + return src.map(function (item) { + return copy(item, mapFormatter); + }); + } + + if( isObject(src) ) { + return mapObject(src, function (item) { + return copy(item, mapFormatter); + }, src, mapFormatter); + } + + return src; +} + +function extend (dest, src) { + dest = dest || {}; + for( var key in src ) dest[key] = src[key]; + return dest; +} + +function _mergeArrays(dest, src, concatArrays) { + if( !concatArrays ) return src.map(function (item) { return copy(item); }); + [].push.apply(dest, src); + for( var i = 0, n = src.length ; i < n ; i++ ) { + dest.push( dest[i] ? merge(dest[i], src[i]) : copy(src[i]) ); + } + return dest; +} + +function merge (dest, src, concatArrays) { + if( typeof dest !== typeof src ) { + if( isArray(src) ) dest = []; + else if( typeof src === 'object' ) dest = {}; + else return src; + } + if( isArray(src) ) return _mergeArrays(dest, src, concatArrays); + if( typeof src === 'object' ) { + for( var key in src ) { + dest[key] = merge(dest[key], src[key]); + } + return dest; + } + return src; +} + +function resolveFunctions (o, args, this_arg) { + for( var key in o ) { + if( isFunction(o[key]) ) { + o[key] = o[key].apply(this_arg, args); + } else if( isObject(o[key]) ) { + o[key] = resolveFunctions(o[key], args, this_arg); + } + } + return o; +} + +var RE_contentType = /([^/]+)\/([^+]+\+)?([^;]*)/; +function parseContentType(contentType) { + var matches = contentType && contentType.match(RE_contentType); + return matches ? matches[3] : 'text'; +} + + +var arrayPush = Array.prototype.push; +var arraySlice = Array.prototype.slice; + +function _sanitizePath(path, i, last) { + if( i > 0 ) path = path.replace(/^\.*\//, ''); + if( !last ) path = path.replace(/\/$/, ''); + return path.split(/\/+/); +} + +function _joinPaths (paths) { + var last = paths.length - 1; + return paths.reduce(function (result, path, i) { + if( path === '.' ) return result; + if( /^[a-z]+:\/\//.test(path) ) return [i === last ? path : path.replace(/\/$/, '')]; + if( /^\//.test(path) ) return _sanitizePath(path, 0, i === last ); + + path = path.replace(/\.\.\//g, function () { + result = result.slice(0, -1); + return ''; + }).replace(/\.\//, ''); + + arrayPush.apply( result, _sanitizePath(path, i, i === last) ); + + return result; + + }, []).join('/'); +} + +function _unraise (paths) { + var result = []; + + paths.forEach(function (path) { + if( !path ) return; + + // https://jsperf.com/array-prototype-push-apply-vs-concat/17 + if( path instanceof Array ) arrayPush.apply(result, _unraise(path) ); + else if( typeof path === 'string' ) result.push(path); + else throw new Error('paths parts should be Array or String'); + }); + + return result; +} + +function joinPaths () { + return _joinPaths( _unraise(arraySlice.call(arguments)) ); +} + +function keysTobrackets (keys) { + return keys.reduce(function (result, key, i) { + return result + (i ? ( '[' + key + ']' ) : key); + }, ''); +} + +function _serialize (data, params, keys) { + + if( typeof data === 'object' ) { + if( Array.isArray(data) ) { + for( var i = 0, n = data.length; i < n ; i++ ) { + _serialize( data[i], params, keys.concat( typeof data[i] === 'object' ? i : '' ) ); + } + } else { + for( var k in data ) { + _serialize( data[k], params, keys.concat(k) ); + } + } + } else { + params.push( keysTobrackets(keys) + '=' + encodeURIComponent('' + data) ); + // params.push( keysTobrackets(keys) + '=' + '' + data ); + } + + return params; +} + +function serializeQS (data) { + // eslint-disable-next-line + // console.log('serialize', data, _serialize(data, [], []) ); + return _serialize(data, [], []).join('&'); +} + +var http_defaults = {}; +var makeRequest = function () {}; +var Parole = typeof Promise !== 'undefined' ? Promise : function () {}; + +function _plainOptions (_options_pile, method) { + var options_pile = _options_pile ? copy(_options_pile) : []; + + var plain_options = {}, + options = options_pile.shift(); + + while( options ) { + merge(plain_options, options); + options = options_pile.shift(); + } + + if(method) plain_options.method = method; + + plain_options.url = joinPaths( _options_pile.reduce(function (paths, options) { + if( !options.url ) return paths; + + if( options.url instanceof Function ) return paths.concat( options.url(plain_options) ); + + return paths.concat(options.url); + }, []) ); + + return plain_options; +} + +function http$1 (url, _config, body) { + + var config = _plainOptions([http_defaults, _config || {}]); + + config = copy( isObject(url) ? url : config || {} ); + config.url = url === config ? config.url : url; + config.method = config.method ? config.method.toUpperCase() : 'GET'; + config.timestamp = new Date().getTime(); + config.body = body || config.body; + + if( !isString(config.url) ) throw new Error('url must be a string'); + + config = resolveFunctions(config, [config]); + + if( config.params ) { + config.url += ( /\?/.test(config.url) ? '&' : '?' ) + serializeQS( config.params ).join('&'); + } + + var headers = copy(config.headers || {}, 'underscore'); + + if( config.json && !config.body ) { + headers.content_type = headers.content_type || 'application/json'; + config.body = JSON.stringify(config.json); + } else if( headers.content_type === 'application/json' && typeof config.body === 'object' ) { + config.body = JSON.stringify(config.body); + } else if( typeof config.body === 'object' && + !Blob.prototype.isPrototypeOf(config.body) && + !FormData.prototype.isPrototypeOf(config.body) ) { + config.body = JSON.stringify(config.body); + headers.content_type = headers.content_type || 'application/json'; + } else if( !headers.content_type ) headers.content_type || 'application/json'; + + headers.accept = headers.accept || headers.content_type || 'application/json'; + + config.headers = copy(headers, 'header'); + + var request = new Parole(function (resolve, reject) { + makeRequest(config, resolve, reject); + }); + + request.config = config; + + return request; +} + +http$1.responseData = function (response) { + return response.data; +}; + +function httpBase (target, options, options_pile) { + var requestMethod = function (method, hasData) { + return hasData ? function (url, data, _options) { + if( typeof url === 'object' ) { _options = data; data = url; url = null; } + _options = Object.create(_options || {}); + if( url ) _options.url = url; + _options = _plainOptions( _options ? options_pile.concat(_options) : options_pile, method ); + return http$1( _options.url, _options, data ); + } : function (url, _options, params) { + if( typeof url === 'object' ) { params = _options; _options = url; url = null; } + _options = Object.create(_options || {}); + if( url ) _options.url = url; + if( params ) _options.params = params; + _options = _plainOptions( _options ? options_pile.concat(_options) : options_pile, method ); + return http$1( _options.url, _options ); + }; + }; + + return extend(target, { + head: requestMethod('head'), + get: requestMethod('get'), + post: requestMethod('post', true), + put: requestMethod('put', true), + patch: requestMethod('patch', true), + delete: requestMethod('delete'), + base: function (url, _options) { + var options = _options ? Object.create(_options) :{}; + options.url = url; + return httpBase( requestMethod('get'), options, options_pile.concat(options) ); + }, + config: function (_options) { + if( options === undefined ) return _plainOptions( [http_defaults].concat(this.options_pile).concat(options) ); + merge( options, _options ); + }, + responseData: http$1.responseData, + }); +} + +http$1.base = httpBase; +httpBase(http$1, http_defaults, []); + +http$1.usePromise = function (P) { Parole = P; return http$1; }; +http$1.useRequest = function (request) { + if( !isFunction(request) ) throw new Error('request should be a function'); + else makeRequest = request; + return http$1; +}; + +http$1.config = function (options) { + merge( http_defaults, options ); + return http$1; +}; + +/* global ActiveXObject */ + +var parseData = { + json: function (data) { + return JSON.parse(data); + } +}; + +function _getXMLHeaders (request) { + var headers = {}; + request.getAllResponseHeaders().split('\n').forEach(function (headerLine) { + var matched = headerLine.match(/(.*?):(.*)/); + if( matched ) { + headers[toUnderscoreCase(matched[1])] = matched[2].trim(); + } + }); + + return headers; +} + +function xmlRequest (config, resolve, reject) { + + var request = null; + + try { // Firefox, Opera 8.0+, Safari + request = new XMLHttpRequest(); + } catch (e) { // Internet Explorer + try { request = new ActiveXObject('Msxml2.XMLHTTP'); } // jshint ignore:line + catch (er) { request = new ActiveXObject('Microsoft.XMLHTTP'); } // jshint ignore:line + } + if( request === null ) { throw 'Browser does not support HTTP Request'; } + + if( config.withCredentials || config.credentials === 'include' ) request.withCredentials = true; + + request.onreadystatechange = function() { + if( request.readyState === 'complete' || request.readyState === 4 ) { + // var type = parseContentType( request.getResponseHeader('Content-Type') ), + var headers = _getXMLHeaders(request), + type = parseContentType( headers.contentType ), + response = { + config: config, + status: request.status, + statusText: request.statusText, + headers: headers, + data: type === 'xml' ? request.responseXML : (parseData[type] ? parseData[type](request.responseText) : request.responseText), + }; + + if( request.status >= 200 && request.status < 400 ) { + resolve( response ); + } else { + reject( response ); + } + } + }; + + request.open(config.method, config.url, true); + + if( config.headers ) { + for( var key in config.headers ) { + request.setRequestHeader( key, config.headers[key] ); + } + } + + request.send( config.body ); +} + +http$1.useRequest(xmlRequest); + +return http$1; + +}))); diff --git a/dist/deserialize.js b/dist/deserialize.js new file mode 100644 index 0000000..28736fc --- /dev/null +++ b/dist/deserialize.js @@ -0,0 +1,37 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = deserializeQS; + +function _qsKey(o, keys, value) { + // eslint-disable-next-line + // console.log('_qsKey', o, keys, value ); + + var key = keys.shift(); + + if (key === undefined) { + return value; + } else if (key === '') { + if (!Array.isArray(o)) throw new Error('trying to assing empty key to non Array object'); + o.push(_qsKey(keys[0] === '' ? [] : {}, keys, value)); + } else { + o[key] = _qsKey(o[key] || (keys[0] === '' ? [] : {}), keys, value); + } + + return o; +} + +function deserializeQS(query_string) { + var data = {}; + + query_string.split('&').forEach(function (param) { + if (!param) return; + var parts = param.split('='), + keys = parts[0].replace(/^\[|\]$/g, '').replace(/\]\[|\[|\]/g, '.').split('.'); + _qsKey(data, keys, decodeURIComponent(parts[1])); + }); + + return data; +} diff --git a/dist/fetch.js b/dist/fetch.js new file mode 100644 index 0000000..7fc4ff0 --- /dev/null +++ b/dist/fetch.js @@ -0,0 +1,441 @@ +'use strict'; + +var isType = function (type, o) { + return o ? typeof o === type : function (_o) { + return typeof _o === type; + }; + }; + +function isObject (o) { + return o !== null && typeof o === 'object'; +} + +var isArray = Array.isArray || function (o) { + return o instanceof Array; +}; + +var isString = isType('string'); +var isFunction = isType('function'); + +function toUnderscoreCase (text) { + return text.replace(/-/g, '_').replace(/([a-z])([A-Z])/, function (matched, a, b) { return a + '_' + b; }).toLowerCase(); +} + +function toCamelCase (text) { + return text.replace(/([a-z])[-_]([a-z])/g, function (matched, a, b) { return a + b.toUpperCase(); }); +} + +function toHeaderCase (text) { + var key = text.replace(/_/g, '-').replace(/([a-z])([A-Z])/, function (matched, a, b) { return a + '-' + b; }); + return key[0].toUpperCase() + key.substr(1).toLowerCase().replace(/-[a-z]/g, function (matched) { return matched.toUpperCase(); }); +} + +function _passThrought (value) { + return value; +} + +var case_formatters = { + underscore: toUnderscoreCase, + camel: toCamelCase, + header: toHeaderCase, +}; + +function mapObject (o, iteratee, thisArg, mapFormatter) { + var result = {}; + mapFormatter = mapFormatter || _passThrought; + for( var key in o ) { + result[mapFormatter(key)] = iteratee.call(thisArg, o[key], key); + } + return result; +} + +function copy (src, mapFormatter) { + if( typeof mapFormatter === 'string' ) mapFormatter = case_formatters[mapFormatter]; + + if( isArray(src) ) { + return src.map(function (item) { + return copy(item, mapFormatter); + }); + } + + if( isObject(src) ) { + return mapObject(src, function (item) { + return copy(item, mapFormatter); + }, src, mapFormatter); + } + + return src; +} + +function extend (dest, src) { + dest = dest || {}; + for( var key in src ) dest[key] = src[key]; + return dest; +} + +function _mergeArrays(dest, src, concatArrays) { + if( !concatArrays ) return src.map(function (item) { return copy(item); }); + [].push.apply(dest, src); + for( var i = 0, n = src.length ; i < n ; i++ ) { + dest.push( dest[i] ? merge(dest[i], src[i]) : copy(src[i]) ); + } + return dest; +} + +function merge (dest, src, concatArrays) { + if( typeof dest !== typeof src ) { + if( isArray(src) ) dest = []; + else if( typeof src === 'object' ) dest = {}; + else return src; + } + if( isArray(src) ) return _mergeArrays(dest, src, concatArrays); + if( typeof src === 'object' ) { + for( var key in src ) { + dest[key] = merge(dest[key], src[key]); + } + return dest; + } + return src; +} + +function resolveFunctions (o, args, this_arg) { + for( var key in o ) { + if( isFunction(o[key]) ) { + o[key] = o[key].apply(this_arg, args); + } else if( isObject(o[key]) ) { + o[key] = resolveFunctions(o[key], args, this_arg); + } + } + return o; +} + +var RE_contentType = /([^/]+)\/([^+]+\+)?([^;]*)/; +function parseContentType(contentType) { + var matches = contentType && contentType.match(RE_contentType); + return matches ? matches[3] : 'text'; +} + + +var arrayPush = Array.prototype.push; +var arraySlice = Array.prototype.slice; + +function _sanitizePath(path, i, last) { + if( i > 0 ) path = path.replace(/^\.*\//, ''); + if( !last ) path = path.replace(/\/$/, ''); + return path.split(/\/+/); +} + +function _joinPaths (paths) { + var last = paths.length - 1; + return paths.reduce(function (result, path, i) { + if( path === '.' ) return result; + if( /^[a-z]+:\/\//.test(path) ) return [i === last ? path : path.replace(/\/$/, '')]; + if( /^\//.test(path) ) return _sanitizePath(path, 0, i === last ); + + path = path.replace(/\.\.\//g, function () { + result = result.slice(0, -1); + return ''; + }).replace(/\.\//, ''); + + arrayPush.apply( result, _sanitizePath(path, i, i === last) ); + + return result; + + }, []).join('/'); +} + +function _unraise (paths) { + var result = []; + + paths.forEach(function (path) { + if( !path ) return; + + // https://jsperf.com/array-prototype-push-apply-vs-concat/17 + if( path instanceof Array ) arrayPush.apply(result, _unraise(path) ); + else if( typeof path === 'string' ) result.push(path); + else throw new Error('paths parts should be Array or String'); + }); + + return result; +} + +function joinPaths () { + return _joinPaths( _unraise(arraySlice.call(arguments)) ); +} + +function keysTobrackets (keys) { + return keys.reduce(function (result, key, i) { + return result + (i ? ( '[' + key + ']' ) : key); + }, ''); +} + +function _serialize (data, params, keys) { + + if( typeof data === 'object' ) { + if( Array.isArray(data) ) { + for( var i = 0, n = data.length; i < n ; i++ ) { + _serialize( data[i], params, keys.concat( typeof data[i] === 'object' ? i : '' ) ); + } + } else { + for( var k in data ) { + _serialize( data[k], params, keys.concat(k) ); + } + } + } else { + params.push( keysTobrackets(keys) + '=' + encodeURIComponent('' + data) ); + // params.push( keysTobrackets(keys) + '=' + '' + data ); + } + + return params; +} + +function serializeQS (data) { + // eslint-disable-next-line + // console.log('serialize', data, _serialize(data, [], []) ); + return _serialize(data, [], []).join('&'); +} + +var http_defaults = {}; +var makeRequest = function () {}; +var Parole = typeof Promise !== 'undefined' ? Promise : function () {}; + +function _plainOptions (_options_pile, method) { + var options_pile = _options_pile ? copy(_options_pile) : []; + + var plain_options = {}, + options = options_pile.shift(); + + while( options ) { + merge(plain_options, options); + options = options_pile.shift(); + } + + if(method) plain_options.method = method; + + plain_options.url = joinPaths( _options_pile.reduce(function (paths, options) { + if( !options.url ) return paths; + + if( options.url instanceof Function ) return paths.concat( options.url(plain_options) ); + + return paths.concat(options.url); + }, []) ); + + return plain_options; +} + +function http$1 (url, _config, body) { + + var config = _plainOptions([http_defaults, _config || {}]); + + config = copy( isObject(url) ? url : config || {} ); + config.url = url === config ? config.url : url; + config.method = config.method ? config.method.toUpperCase() : 'GET'; + config.timestamp = new Date().getTime(); + config.body = body || config.body; + + if( !isString(config.url) ) throw new Error('url must be a string'); + + config = resolveFunctions(config, [config]); + + if( config.params ) { + config.url += ( /\?/.test(config.url) ? '&' : '?' ) + serializeQS( config.params ).join('&'); + } + + var headers = copy(config.headers || {}, 'underscore'); + + if( config.json && !config.body ) { + headers.content_type = headers.content_type || 'application/json'; + config.body = JSON.stringify(config.json); + } else if( headers.content_type === 'application/json' && typeof config.body === 'object' ) { + config.body = JSON.stringify(config.body); + } else if( typeof config.body === 'object' && + !Blob.prototype.isPrototypeOf(config.body) && + !FormData.prototype.isPrototypeOf(config.body) ) { + config.body = JSON.stringify(config.body); + headers.content_type = headers.content_type || 'application/json'; + } else if( !headers.content_type ) headers.content_type || 'application/json'; + + headers.accept = headers.accept || headers.content_type || 'application/json'; + + config.headers = copy(headers, 'header'); + + var request = new Parole(function (resolve, reject) { + makeRequest(config, resolve, reject); + }); + + request.config = config; + + return request; +} + +http$1.responseData = function (response) { + return response.data; +}; + +function httpBase (target, options, options_pile) { + var requestMethod = function (method, hasData) { + return hasData ? function (url, data, _options) { + if( typeof url === 'object' ) { _options = data; data = url; url = null; } + _options = Object.create(_options || {}); + if( url ) _options.url = url; + _options = _plainOptions( _options ? options_pile.concat(_options) : options_pile, method ); + return http$1( _options.url, _options, data ); + } : function (url, _options, params) { + if( typeof url === 'object' ) { params = _options; _options = url; url = null; } + _options = Object.create(_options || {}); + if( url ) _options.url = url; + if( params ) _options.params = params; + _options = _plainOptions( _options ? options_pile.concat(_options) : options_pile, method ); + return http$1( _options.url, _options ); + }; + }; + + return extend(target, { + head: requestMethod('head'), + get: requestMethod('get'), + post: requestMethod('post', true), + put: requestMethod('put', true), + patch: requestMethod('patch', true), + delete: requestMethod('delete'), + base: function (url, _options) { + var options = _options ? Object.create(_options) :{}; + options.url = url; + return httpBase( requestMethod('get'), options, options_pile.concat(options) ); + }, + config: function (_options) { + if( options === undefined ) return _plainOptions( [http_defaults].concat(this.options_pile).concat(options) ); + merge( options, _options ); + }, + responseData: http$1.responseData, + }); +} + +http$1.base = httpBase; +httpBase(http$1, http_defaults, []); + +http$1.usePromise = function (P) { Parole = P; return http$1; }; +http$1.useRequest = function (request) { + if( !isFunction(request) ) throw new Error('request should be a function'); + else makeRequest = request; + return http$1; +}; + +http$1.config = function (options) { + merge( http_defaults, options ); + return http$1; +}; + +/* global ActiveXObject */ + +var parseData = { + json: function (data) { + return JSON.parse(data); + } +}; + +function _getXMLHeaders (request) { + var headers = {}; + request.getAllResponseHeaders().split('\n').forEach(function (headerLine) { + var matched = headerLine.match(/(.*?):(.*)/); + if( matched ) { + headers[toUnderscoreCase(matched[1])] = matched[2].trim(); + } + }); + + return headers; +} + +function xmlRequest (config, resolve, reject) { + + var request = null; + + try { // Firefox, Opera 8.0+, Safari + request = new XMLHttpRequest(); + } catch (e) { // Internet Explorer + try { request = new ActiveXObject('Msxml2.XMLHTTP'); } // jshint ignore:line + catch (er) { request = new ActiveXObject('Microsoft.XMLHTTP'); } // jshint ignore:line + } + if( request === null ) { throw 'Browser does not support HTTP Request'; } + + if( config.withCredentials || config.credentials === 'include' ) request.withCredentials = true; + + request.onreadystatechange = function() { + if( request.readyState === 'complete' || request.readyState === 4 ) { + // var type = parseContentType( request.getResponseHeader('Content-Type') ), + var headers = _getXMLHeaders(request), + type = parseContentType( headers.contentType ), + response = { + config: config, + status: request.status, + statusText: request.statusText, + headers: headers, + data: type === 'xml' ? request.responseXML : (parseData[type] ? parseData[type](request.responseText) : request.responseText), + }; + + if( request.status >= 200 && request.status < 400 ) { + resolve( response ); + } else { + reject( response ); + } + } + }; + + request.open(config.method, config.url, true); + + if( config.headers ) { + for( var key in config.headers ) { + request.setRequestHeader( key, config.headers[key] ); + } + } + + request.send( config.body ); +} + +function getFetchResponse (response, config) { + var headers = {}, + iterator = response.headers.entries(), + entry = iterator.next(); + + while( entry && !entry.done ) { + headers[toUnderscoreCase(entry.value[0])] = entry.value[1]; + entry = iterator.next(); + } + + var type = parseContentType(headers.contentType); + + return ( response[config.format || type] ? response[config.format || type]() : response.text() ).then(function (data) { + return { + config: config, + status: response.status, + statusText: response.statusText, + data: data, + headers: headers, + }; + }); +} + +function fetchRequest (config, resolve, reject) { + fetch(config.url, extend( copy(config) , { + headers: new Headers(config.headers), redirect: 'follow', + credentials: config.credentials || (config.withCredentials ? 'include' : 'same-origin'), + }) ).then(function (response) { + getFetchResponse(response, config).then(response.ok ? resolve : reject); + }, function (response) { + getFetchResponse(response, config).then(reject); + }); +} + +var useRequest = http$1.useRequest; +var requests = { xml: xmlRequest, fetch: fetchRequest }; + +http$1.useRequest = function (request) { + if( typeof request === 'string' ) { + if( !requests[request] ) throw new Error('request type `' + request + '` missing'); + useRequest( requests[request] ); + } else if( !Function.prototype.isPrototypeOf(request) ) throw new Error('request should be a function'); + else useRequest( request ); +}; + +useRequest( window.fetch ? requests.fetch : requests.xml ); + +module.exports = http$1; diff --git a/dist/fetch.umd.js b/dist/fetch.umd.js new file mode 100644 index 0000000..e4e8a05 --- /dev/null +++ b/dist/fetch.umd.js @@ -0,0 +1,447 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.$http = factory()); +}(this, (function () { 'use strict'; + +var isType = function (type, o) { + return o ? typeof o === type : function (_o) { + return typeof _o === type; + }; + }; + +function isObject (o) { + return o !== null && typeof o === 'object'; +} + +var isArray = Array.isArray || function (o) { + return o instanceof Array; +}; + +var isString = isType('string'); +var isFunction = isType('function'); + +function toUnderscoreCase (text) { + return text.replace(/-/g, '_').replace(/([a-z])([A-Z])/, function (matched, a, b) { return a + '_' + b; }).toLowerCase(); +} + +function toCamelCase (text) { + return text.replace(/([a-z])[-_]([a-z])/g, function (matched, a, b) { return a + b.toUpperCase(); }); +} + +function toHeaderCase (text) { + var key = text.replace(/_/g, '-').replace(/([a-z])([A-Z])/, function (matched, a, b) { return a + '-' + b; }); + return key[0].toUpperCase() + key.substr(1).toLowerCase().replace(/-[a-z]/g, function (matched) { return matched.toUpperCase(); }); +} + +function _passThrought (value) { + return value; +} + +var case_formatters = { + underscore: toUnderscoreCase, + camel: toCamelCase, + header: toHeaderCase, +}; + +function mapObject (o, iteratee, thisArg, mapFormatter) { + var result = {}; + mapFormatter = mapFormatter || _passThrought; + for( var key in o ) { + result[mapFormatter(key)] = iteratee.call(thisArg, o[key], key); + } + return result; +} + +function copy (src, mapFormatter) { + if( typeof mapFormatter === 'string' ) mapFormatter = case_formatters[mapFormatter]; + + if( isArray(src) ) { + return src.map(function (item) { + return copy(item, mapFormatter); + }); + } + + if( isObject(src) ) { + return mapObject(src, function (item) { + return copy(item, mapFormatter); + }, src, mapFormatter); + } + + return src; +} + +function extend (dest, src) { + dest = dest || {}; + for( var key in src ) dest[key] = src[key]; + return dest; +} + +function _mergeArrays(dest, src, concatArrays) { + if( !concatArrays ) return src.map(function (item) { return copy(item); }); + [].push.apply(dest, src); + for( var i = 0, n = src.length ; i < n ; i++ ) { + dest.push( dest[i] ? merge(dest[i], src[i]) : copy(src[i]) ); + } + return dest; +} + +function merge (dest, src, concatArrays) { + if( typeof dest !== typeof src ) { + if( isArray(src) ) dest = []; + else if( typeof src === 'object' ) dest = {}; + else return src; + } + if( isArray(src) ) return _mergeArrays(dest, src, concatArrays); + if( typeof src === 'object' ) { + for( var key in src ) { + dest[key] = merge(dest[key], src[key]); + } + return dest; + } + return src; +} + +function resolveFunctions (o, args, this_arg) { + for( var key in o ) { + if( isFunction(o[key]) ) { + o[key] = o[key].apply(this_arg, args); + } else if( isObject(o[key]) ) { + o[key] = resolveFunctions(o[key], args, this_arg); + } + } + return o; +} + +var RE_contentType = /([^/]+)\/([^+]+\+)?([^;]*)/; +function parseContentType(contentType) { + var matches = contentType && contentType.match(RE_contentType); + return matches ? matches[3] : 'text'; +} + + +var arrayPush = Array.prototype.push; +var arraySlice = Array.prototype.slice; + +function _sanitizePath(path, i, last) { + if( i > 0 ) path = path.replace(/^\.*\//, ''); + if( !last ) path = path.replace(/\/$/, ''); + return path.split(/\/+/); +} + +function _joinPaths (paths) { + var last = paths.length - 1; + return paths.reduce(function (result, path, i) { + if( path === '.' ) return result; + if( /^[a-z]+:\/\//.test(path) ) return [i === last ? path : path.replace(/\/$/, '')]; + if( /^\//.test(path) ) return _sanitizePath(path, 0, i === last ); + + path = path.replace(/\.\.\//g, function () { + result = result.slice(0, -1); + return ''; + }).replace(/\.\//, ''); + + arrayPush.apply( result, _sanitizePath(path, i, i === last) ); + + return result; + + }, []).join('/'); +} + +function _unraise (paths) { + var result = []; + + paths.forEach(function (path) { + if( !path ) return; + + // https://jsperf.com/array-prototype-push-apply-vs-concat/17 + if( path instanceof Array ) arrayPush.apply(result, _unraise(path) ); + else if( typeof path === 'string' ) result.push(path); + else throw new Error('paths parts should be Array or String'); + }); + + return result; +} + +function joinPaths () { + return _joinPaths( _unraise(arraySlice.call(arguments)) ); +} + +function keysTobrackets (keys) { + return keys.reduce(function (result, key, i) { + return result + (i ? ( '[' + key + ']' ) : key); + }, ''); +} + +function _serialize (data, params, keys) { + + if( typeof data === 'object' ) { + if( Array.isArray(data) ) { + for( var i = 0, n = data.length; i < n ; i++ ) { + _serialize( data[i], params, keys.concat( typeof data[i] === 'object' ? i : '' ) ); + } + } else { + for( var k in data ) { + _serialize( data[k], params, keys.concat(k) ); + } + } + } else { + params.push( keysTobrackets(keys) + '=' + encodeURIComponent('' + data) ); + // params.push( keysTobrackets(keys) + '=' + '' + data ); + } + + return params; +} + +function serializeQS (data) { + // eslint-disable-next-line + // console.log('serialize', data, _serialize(data, [], []) ); + return _serialize(data, [], []).join('&'); +} + +var http_defaults = {}; +var makeRequest = function () {}; +var Parole = typeof Promise !== 'undefined' ? Promise : function () {}; + +function _plainOptions (_options_pile, method) { + var options_pile = _options_pile ? copy(_options_pile) : []; + + var plain_options = {}, + options = options_pile.shift(); + + while( options ) { + merge(plain_options, options); + options = options_pile.shift(); + } + + if(method) plain_options.method = method; + + plain_options.url = joinPaths( _options_pile.reduce(function (paths, options) { + if( !options.url ) return paths; + + if( options.url instanceof Function ) return paths.concat( options.url(plain_options) ); + + return paths.concat(options.url); + }, []) ); + + return plain_options; +} + +function http$1 (url, _config, body) { + + var config = _plainOptions([http_defaults, _config || {}]); + + config = copy( isObject(url) ? url : config || {} ); + config.url = url === config ? config.url : url; + config.method = config.method ? config.method.toUpperCase() : 'GET'; + config.timestamp = new Date().getTime(); + config.body = body || config.body; + + if( !isString(config.url) ) throw new Error('url must be a string'); + + config = resolveFunctions(config, [config]); + + if( config.params ) { + config.url += ( /\?/.test(config.url) ? '&' : '?' ) + serializeQS( config.params ).join('&'); + } + + var headers = copy(config.headers || {}, 'underscore'); + + if( config.json && !config.body ) { + headers.content_type = headers.content_type || 'application/json'; + config.body = JSON.stringify(config.json); + } else if( headers.content_type === 'application/json' && typeof config.body === 'object' ) { + config.body = JSON.stringify(config.body); + } else if( typeof config.body === 'object' && + !Blob.prototype.isPrototypeOf(config.body) && + !FormData.prototype.isPrototypeOf(config.body) ) { + config.body = JSON.stringify(config.body); + headers.content_type = headers.content_type || 'application/json'; + } else if( !headers.content_type ) headers.content_type || 'application/json'; + + headers.accept = headers.accept || headers.content_type || 'application/json'; + + config.headers = copy(headers, 'header'); + + var request = new Parole(function (resolve, reject) { + makeRequest(config, resolve, reject); + }); + + request.config = config; + + return request; +} + +http$1.responseData = function (response) { + return response.data; +}; + +function httpBase (target, options, options_pile) { + var requestMethod = function (method, hasData) { + return hasData ? function (url, data, _options) { + if( typeof url === 'object' ) { _options = data; data = url; url = null; } + _options = Object.create(_options || {}); + if( url ) _options.url = url; + _options = _plainOptions( _options ? options_pile.concat(_options) : options_pile, method ); + return http$1( _options.url, _options, data ); + } : function (url, _options, params) { + if( typeof url === 'object' ) { params = _options; _options = url; url = null; } + _options = Object.create(_options || {}); + if( url ) _options.url = url; + if( params ) _options.params = params; + _options = _plainOptions( _options ? options_pile.concat(_options) : options_pile, method ); + return http$1( _options.url, _options ); + }; + }; + + return extend(target, { + head: requestMethod('head'), + get: requestMethod('get'), + post: requestMethod('post', true), + put: requestMethod('put', true), + patch: requestMethod('patch', true), + delete: requestMethod('delete'), + base: function (url, _options) { + var options = _options ? Object.create(_options) :{}; + options.url = url; + return httpBase( requestMethod('get'), options, options_pile.concat(options) ); + }, + config: function (_options) { + if( options === undefined ) return _plainOptions( [http_defaults].concat(this.options_pile).concat(options) ); + merge( options, _options ); + }, + responseData: http$1.responseData, + }); +} + +http$1.base = httpBase; +httpBase(http$1, http_defaults, []); + +http$1.usePromise = function (P) { Parole = P; return http$1; }; +http$1.useRequest = function (request) { + if( !isFunction(request) ) throw new Error('request should be a function'); + else makeRequest = request; + return http$1; +}; + +http$1.config = function (options) { + merge( http_defaults, options ); + return http$1; +}; + +/* global ActiveXObject */ + +var parseData = { + json: function (data) { + return JSON.parse(data); + } +}; + +function _getXMLHeaders (request) { + var headers = {}; + request.getAllResponseHeaders().split('\n').forEach(function (headerLine) { + var matched = headerLine.match(/(.*?):(.*)/); + if( matched ) { + headers[toUnderscoreCase(matched[1])] = matched[2].trim(); + } + }); + + return headers; +} + +function xmlRequest (config, resolve, reject) { + + var request = null; + + try { // Firefox, Opera 8.0+, Safari + request = new XMLHttpRequest(); + } catch (e) { // Internet Explorer + try { request = new ActiveXObject('Msxml2.XMLHTTP'); } // jshint ignore:line + catch (er) { request = new ActiveXObject('Microsoft.XMLHTTP'); } // jshint ignore:line + } + if( request === null ) { throw 'Browser does not support HTTP Request'; } + + if( config.withCredentials || config.credentials === 'include' ) request.withCredentials = true; + + request.onreadystatechange = function() { + if( request.readyState === 'complete' || request.readyState === 4 ) { + // var type = parseContentType( request.getResponseHeader('Content-Type') ), + var headers = _getXMLHeaders(request), + type = parseContentType( headers.contentType ), + response = { + config: config, + status: request.status, + statusText: request.statusText, + headers: headers, + data: type === 'xml' ? request.responseXML : (parseData[type] ? parseData[type](request.responseText) : request.responseText), + }; + + if( request.status >= 200 && request.status < 400 ) { + resolve( response ); + } else { + reject( response ); + } + } + }; + + request.open(config.method, config.url, true); + + if( config.headers ) { + for( var key in config.headers ) { + request.setRequestHeader( key, config.headers[key] ); + } + } + + request.send( config.body ); +} + +function getFetchResponse (response, config) { + var headers = {}, + iterator = response.headers.entries(), + entry = iterator.next(); + + while( entry && !entry.done ) { + headers[toUnderscoreCase(entry.value[0])] = entry.value[1]; + entry = iterator.next(); + } + + var type = parseContentType(headers.contentType); + + return ( response[config.format || type] ? response[config.format || type]() : response.text() ).then(function (data) { + return { + config: config, + status: response.status, + statusText: response.statusText, + data: data, + headers: headers, + }; + }); +} + +function fetchRequest (config, resolve, reject) { + fetch(config.url, extend( copy(config) , { + headers: new Headers(config.headers), redirect: 'follow', + credentials: config.credentials || (config.withCredentials ? 'include' : 'same-origin'), + }) ).then(function (response) { + getFetchResponse(response, config).then(response.ok ? resolve : reject); + }, function (response) { + getFetchResponse(response, config).then(reject); + }); +} + +var useRequest = http$1.useRequest; +var requests = { xml: xmlRequest, fetch: fetchRequest }; + +http$1.useRequest = function (request) { + if( typeof request === 'string' ) { + if( !requests[request] ) throw new Error('request type `' + request + '` missing'); + useRequest( requests[request] ); + } else if( !Function.prototype.isPrototypeOf(request) ) throw new Error('request should be a function'); + else useRequest( request ); +}; + +useRequest( window.fetch ? requests.fetch : requests.xml ); + +return http$1; + +}))); diff --git a/dist/http-node.js b/dist/http-node.js new file mode 100644 index 0000000..e2d3da9 --- /dev/null +++ b/dist/http-node.js @@ -0,0 +1,70 @@ +/* eslint-env node */ +/*eslint no-console: 0*/ + +var URL = require('url'); +var http = require('./wrapper'); + +var RE_contentType = /([^/]+)\/([^+]+\+)?([^;]*)/; +function parseContentType(contentType) { + var matches = contentType && contentType.match(RE_contentType); + return matches ? matches[3] : 'text'; +} + +var parseData = { + json: function (data) { + return JSON.parse(data); + } +}; + +http.useRequest(function (config, resolve, reject) { + + var url = URL.parse(config.url); + + var options = { + method: config.method, + hostname: url.hostname, + port: url.port, + path: url.path, + encoding: null, + headers: config.headers + }; + + var data = null; + // var data = []; + + var req = require(url.protocol.replace(/:$/, '')).request(options, function (res) { + // console.log(`STATUS: ${res.statusCode}`); + // console.log(`HEADERS: ${JSON.stringify(res.headers)}`); + // res.setEncoding('utf8'); + res.setEncoding(config.headers['Content-Type'] ? 'utf8' : 'binary'); + + res.on('data', function (chunk) { + + data = data ? data.concat(chunk) : chunk; + // data.push(chunk); + + }); + + res.on('end', function () { + console.log('fetched', url.format() ); + var format = parseContentType(res.headers['Content-Type']); + resolve({ config: config, headers: res.headers, data: parseData[format] ? parseData[format](data) : data }); + // resolve({ config: options, data: Buffer.concat(data) }); + }); + + res.on('error', function(err) { + console.log('HTTP ERROR', err); + reject({ ok: false, status: res.statusCode, statusText: res.statusMessage }); + }); + }); + + req.on('error', function (e) { + reject(e); + // console.log(`problem with request: ${e.message}`); + }); + + req.end(); + +}); + +module.exports = http; diff --git a/dist/package.json b/dist/package.json new file mode 100644 index 0000000..291b84c --- /dev/null +++ b/dist/package.json @@ -0,0 +1,33 @@ +{ + "name": "http-rest", + "version": "0.2.1", + "description": "http jstool example", + "main": "http-node.js", + "scripts": { + "test": "make test" + }, + "repository": { + "type": "git", + "url": "https://github.com/kiltjs/http-rest.git" + }, + "keywords": [ + "javascript", + "http", + "fetch" + ], + "author": "Jesús Manuel Germade Castiñeiras ", + "license": "MIT", + "bugs": { + "url": "https://github.com/kiltjs/http-rest/issues" + }, + "homepage": "https://github.com/kiltjs/http-rest", + "dependencies": {}, + "devDependencies": { + "babel-cli": "^6.26.0", + "babel-core": "^6.26.0", + "babel-preset-env": "^1.6.1", + "eslint": "^4.4.1", + "mocha": "^4.0.1", + "rollup": "^0.45.2" + } +} diff --git a/dist/wrapper.js b/dist/wrapper.js new file mode 100644 index 0000000..8f3a906 --- /dev/null +++ b/dist/wrapper.js @@ -0,0 +1,324 @@ +'use strict'; + +var isType = function (type, o) { + return o ? typeof o === type : function (_o) { + return typeof _o === type; + }; + }; + +function isObject (o) { + return o !== null && typeof o === 'object'; +} + +var isArray = Array.isArray || function (o) { + return o instanceof Array; +}; + +var isString = isType('string'); +var isFunction = isType('function'); + +function toUnderscoreCase (text) { + return text.replace(/-/g, '_').replace(/([a-z])([A-Z])/, function (matched, a, b) { return a + '_' + b; }).toLowerCase(); +} + +function toCamelCase (text) { + return text.replace(/([a-z])[-_]([a-z])/g, function (matched, a, b) { return a + b.toUpperCase(); }); +} + +function toHeaderCase (text) { + var key = text.replace(/_/g, '-').replace(/([a-z])([A-Z])/, function (matched, a, b) { return a + '-' + b; }); + return key[0].toUpperCase() + key.substr(1).toLowerCase().replace(/-[a-z]/g, function (matched) { return matched.toUpperCase(); }); +} + +function _passThrought (value) { + return value; +} + +var case_formatters = { + underscore: toUnderscoreCase, + camel: toCamelCase, + header: toHeaderCase, +}; + +function mapObject (o, iteratee, thisArg, mapFormatter) { + var result = {}; + mapFormatter = mapFormatter || _passThrought; + for( var key in o ) { + result[mapFormatter(key)] = iteratee.call(thisArg, o[key], key); + } + return result; +} + +function copy (src, mapFormatter) { + if( typeof mapFormatter === 'string' ) mapFormatter = case_formatters[mapFormatter]; + + if( isArray(src) ) { + return src.map(function (item) { + return copy(item, mapFormatter); + }); + } + + if( isObject(src) ) { + return mapObject(src, function (item) { + return copy(item, mapFormatter); + }, src, mapFormatter); + } + + return src; +} + +function extend (dest, src) { + dest = dest || {}; + for( var key in src ) dest[key] = src[key]; + return dest; +} + +function _mergeArrays(dest, src, concatArrays) { + if( !concatArrays ) return src.map(function (item) { return copy(item); }); + [].push.apply(dest, src); + for( var i = 0, n = src.length ; i < n ; i++ ) { + dest.push( dest[i] ? merge(dest[i], src[i]) : copy(src[i]) ); + } + return dest; +} + +function merge (dest, src, concatArrays) { + if( typeof dest !== typeof src ) { + if( isArray(src) ) dest = []; + else if( typeof src === 'object' ) dest = {}; + else return src; + } + if( isArray(src) ) return _mergeArrays(dest, src, concatArrays); + if( typeof src === 'object' ) { + for( var key in src ) { + dest[key] = merge(dest[key], src[key]); + } + return dest; + } + return src; +} + +function resolveFunctions (o, args, this_arg) { + for( var key in o ) { + if( isFunction(o[key]) ) { + o[key] = o[key].apply(this_arg, args); + } else if( isObject(o[key]) ) { + o[key] = resolveFunctions(o[key], args, this_arg); + } + } + return o; +} + + + + +var arrayPush = Array.prototype.push; +var arraySlice = Array.prototype.slice; + +function _sanitizePath(path, i, last) { + if( i > 0 ) path = path.replace(/^\.*\//, ''); + if( !last ) path = path.replace(/\/$/, ''); + return path.split(/\/+/); +} + +function _joinPaths (paths) { + var last = paths.length - 1; + return paths.reduce(function (result, path, i) { + if( path === '.' ) return result; + if( /^[a-z]+:\/\//.test(path) ) return [i === last ? path : path.replace(/\/$/, '')]; + if( /^\//.test(path) ) return _sanitizePath(path, 0, i === last ); + + path = path.replace(/\.\.\//g, function () { + result = result.slice(0, -1); + return ''; + }).replace(/\.\//, ''); + + arrayPush.apply( result, _sanitizePath(path, i, i === last) ); + + return result; + + }, []).join('/'); +} + +function _unraise (paths) { + var result = []; + + paths.forEach(function (path) { + if( !path ) return; + + // https://jsperf.com/array-prototype-push-apply-vs-concat/17 + if( path instanceof Array ) arrayPush.apply(result, _unraise(path) ); + else if( typeof path === 'string' ) result.push(path); + else throw new Error('paths parts should be Array or String'); + }); + + return result; +} + +function joinPaths () { + return _joinPaths( _unraise(arraySlice.call(arguments)) ); +} + +function keysTobrackets (keys) { + return keys.reduce(function (result, key, i) { + return result + (i ? ( '[' + key + ']' ) : key); + }, ''); +} + +function _serialize (data, params, keys) { + + if( typeof data === 'object' ) { + if( Array.isArray(data) ) { + for( var i = 0, n = data.length; i < n ; i++ ) { + _serialize( data[i], params, keys.concat( typeof data[i] === 'object' ? i : '' ) ); + } + } else { + for( var k in data ) { + _serialize( data[k], params, keys.concat(k) ); + } + } + } else { + params.push( keysTobrackets(keys) + '=' + encodeURIComponent('' + data) ); + // params.push( keysTobrackets(keys) + '=' + '' + data ); + } + + return params; +} + +function serializeQS (data) { + // eslint-disable-next-line + // console.log('serialize', data, _serialize(data, [], []) ); + return _serialize(data, [], []).join('&'); +} + +var http_defaults = {}; +var makeRequest = function () {}; +var Parole = typeof Promise !== 'undefined' ? Promise : function () {}; + +function _plainOptions (_options_pile, method) { + var options_pile = _options_pile ? copy(_options_pile) : []; + + var plain_options = {}, + options = options_pile.shift(); + + while( options ) { + merge(plain_options, options); + options = options_pile.shift(); + } + + if(method) plain_options.method = method; + + plain_options.url = joinPaths( _options_pile.reduce(function (paths, options) { + if( !options.url ) return paths; + + if( options.url instanceof Function ) return paths.concat( options.url(plain_options) ); + + return paths.concat(options.url); + }, []) ); + + return plain_options; +} + +function http (url, _config, body) { + + var config = _plainOptions([http_defaults, _config || {}]); + + config = copy( isObject(url) ? url : config || {} ); + config.url = url === config ? config.url : url; + config.method = config.method ? config.method.toUpperCase() : 'GET'; + config.timestamp = new Date().getTime(); + config.body = body || config.body; + + if( !isString(config.url) ) throw new Error('url must be a string'); + + config = resolveFunctions(config, [config]); + + if( config.params ) { + config.url += ( /\?/.test(config.url) ? '&' : '?' ) + serializeQS( config.params ).join('&'); + } + + var headers = copy(config.headers || {}, 'underscore'); + + if( config.json && !config.body ) { + headers.content_type = headers.content_type || 'application/json'; + config.body = JSON.stringify(config.json); + } else if( headers.content_type === 'application/json' && typeof config.body === 'object' ) { + config.body = JSON.stringify(config.body); + } else if( typeof config.body === 'object' && + !Blob.prototype.isPrototypeOf(config.body) && + !FormData.prototype.isPrototypeOf(config.body) ) { + config.body = JSON.stringify(config.body); + headers.content_type = headers.content_type || 'application/json'; + } else if( !headers.content_type ) headers.content_type || 'application/json'; + + headers.accept = headers.accept || headers.content_type || 'application/json'; + + config.headers = copy(headers, 'header'); + + var request = new Parole(function (resolve, reject) { + makeRequest(config, resolve, reject); + }); + + request.config = config; + + return request; +} + +http.responseData = function (response) { + return response.data; +}; + +function httpBase (target, options, options_pile) { + var requestMethod = function (method, hasData) { + return hasData ? function (url, data, _options) { + if( typeof url === 'object' ) { _options = data; data = url; url = null; } + _options = Object.create(_options || {}); + if( url ) _options.url = url; + _options = _plainOptions( _options ? options_pile.concat(_options) : options_pile, method ); + return http( _options.url, _options, data ); + } : function (url, _options, params) { + if( typeof url === 'object' ) { params = _options; _options = url; url = null; } + _options = Object.create(_options || {}); + if( url ) _options.url = url; + if( params ) _options.params = params; + _options = _plainOptions( _options ? options_pile.concat(_options) : options_pile, method ); + return http( _options.url, _options ); + }; + }; + + return extend(target, { + head: requestMethod('head'), + get: requestMethod('get'), + post: requestMethod('post', true), + put: requestMethod('put', true), + patch: requestMethod('patch', true), + delete: requestMethod('delete'), + base: function (url, _options) { + var options = _options ? Object.create(_options) :{}; + options.url = url; + return httpBase( requestMethod('get'), options, options_pile.concat(options) ); + }, + config: function (_options) { + if( options === undefined ) return _plainOptions( [http_defaults].concat(this.options_pile).concat(options) ); + merge( options, _options ); + }, + responseData: http.responseData, + }); +} + +http.base = httpBase; +httpBase(http, http_defaults, []); + +http.usePromise = function (P) { Parole = P; return http; }; +http.useRequest = function (request) { + if( !isFunction(request) ) throw new Error('request should be a function'); + else makeRequest = request; + return http; +}; + +http.config = function (options) { + merge( http_defaults, options ); + return http; +}; + +module.exports = http;