forked from maple3142/GDIndex
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathxfetch.js
116 lines (112 loc) · 3.85 KB
/
xfetch.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/*
* XFetch.js modified
* A extremely simple fetch extension inspired by sindresorhus/ky.
*/
const xf = (() => {
const METHODS = ['get', 'post', 'put', 'patch', 'delete', 'head']
class HTTPError extends Error {
constructor(res) {
super(res.statusText)
this.name = 'HTTPError'
this.response = res
}
}
class XResponsePromise extends Promise {}
for (const alias of ['arrayBuffer', 'blob', 'formData', 'json', 'text']) {
// alias for .json() .text() etc...
XResponsePromise.prototype[alias] = function(fn) {
return this.then(res => res[alias]()).then(fn || (x => x))
}
}
const { assign } = Object
function mergeDeep(target, source) {
const isObject = obj => obj && typeof obj === 'object'
if (!isObject(target) || !isObject(source)) {
return source
}
Object.keys(source).forEach(key => {
const targetValue = target[key]
const sourceValue = source[key]
if (Array.isArray(targetValue) && Array.isArray(sourceValue)) {
target[key] = targetValue.concat(sourceValue)
} else if (isObject(targetValue) && isObject(sourceValue)) {
target[key] = mergeDeep(Object.assign({}, targetValue), sourceValue)
} else {
target[key] = sourceValue
}
})
return target
}
const fromEntries = ent => ent.reduce((acc, [k, v]) => ((acc[k] = v), acc), {})
const typeis = (...types) => val =>
types.some(type => (typeof type === 'string' ? typeof val === type : val instanceof type))
const isstr = typeis('string')
const isobj = typeis('object')
const isstrorobj = v => isstr(v) || isobj(v)
const responseErrorThrower = res => {
if (!res.ok) throw new HTTPError(res)
return res
}
const extend = (defaultInit = {}) => {
const xfetch = (input, init = {}) => {
mergeDeep(init, defaultInit)
const createQueryString = o => new init.URLSearchParams(o).toString()
const parseQueryString = s => fromEntries([...new init.URLSearchParams(s).entries()])
const url = new init.URL(input, init.baseURI || undefined)
if (!init.headers) {
init.headers = {}
} else if (typeis(init.Headers)(init.headers)) {
// Transform into object if it is `Headers`
init.headers = fromEntries([...init.headers.entries()])
}
// Add json or form on body
if (init.json) {
init.body = JSON.stringify(init.json)
init.headers['Content-Type'] = 'application/json'
} else if (isstrorobj(init.urlencoded)) {
init.body = isstr(init.urlencoded) ? init.urlencoded : createQueryString(init.urlencoded)
init.headers['Content-Type'] = 'application/x-www-form-urlencoded'
} else if (typeis(init.FormData, 'object')(init.formData)) {
// init.formData is data passed by user, init.FormData is FormData constructor
if (!typeis(init.FormData)(init.formData)) {
const fd = new init.FormData()
for (const [k, v] of Object.entries(init.formData)) {
fd.append(k, v)
}
init.formData = fd
}
init.body = init.formData
}
// Querystring
if (init.qs) {
if (isstr(init.qs)) init.qs = parseQueryString(init.qs)
url.search = createQueryString(assign(fromEntries([...url.searchParams.entries()]), init.qs))
}
return XResponsePromise.resolve(init.fetch(url, init).then(responseErrorThrower))
}
for (const method of METHODS) {
xfetch[method] = (input, init = {}) => {
init.method = method.toUpperCase()
return xfetch(input, init)
}
}
// Extra methods and classes
xfetch.extend = newDefaultInit => extend(assign({}, defaultInit, newDefaultInit))
xfetch.HTTPError = HTTPError
return xfetch
}
const isWindow = typeof document !== 'undefined'
const isBrowser = typeof self !== 'undefined' // works in both window & worker scope
return isBrowser
? extend({
fetch: fetch.bind(self),
URL,
Response,
URLSearchParams,
Headers,
FormData,
baseURI: isWindow ? document.baseURI : '' // since there is no document in webworkers
})
: extend()
})()
export default xf