import {
|
isFn,
|
isPlainObject
|
} from 'uni-shared'
|
|
const HOOKS = [
|
'invoke',
|
'success',
|
'fail',
|
'complete',
|
'returnValue'
|
]
|
|
const globalInterceptors = {}
|
const scopedInterceptors = {}
|
|
function mergeHook (parentVal, childVal) {
|
const res = childVal
|
? parentVal
|
? parentVal.concat(childVal)
|
: Array.isArray(childVal)
|
? childVal : [childVal]
|
: parentVal
|
return res
|
? dedupeHooks(res)
|
: res
|
}
|
|
function dedupeHooks (hooks) {
|
const res = []
|
for (let i = 0; i < hooks.length; i++) {
|
if (res.indexOf(hooks[i]) === -1) {
|
res.push(hooks[i])
|
}
|
}
|
return res
|
}
|
|
function removeHook (hooks, hook) {
|
const index = hooks.indexOf(hook)
|
if (index !== -1) {
|
hooks.splice(index, 1)
|
}
|
}
|
|
function mergeInterceptorHook (interceptor, option) {
|
Object.keys(option).forEach(hook => {
|
if (HOOKS.indexOf(hook) !== -1 && isFn(option[hook])) {
|
interceptor[hook] = mergeHook(interceptor[hook], option[hook])
|
}
|
})
|
}
|
|
function removeInterceptorHook (interceptor, option) {
|
if (!interceptor || !option) {
|
return
|
}
|
Object.keys(option).forEach(hook => {
|
if (HOOKS.indexOf(hook) !== -1 && isFn(option[hook])) {
|
removeHook(interceptor[hook], option[hook])
|
}
|
})
|
}
|
|
export function addInterceptor (method, option) {
|
if (typeof method === 'string' && isPlainObject(option)) {
|
mergeInterceptorHook(scopedInterceptors[method] || (scopedInterceptors[method] = {}), option)
|
} else if (isPlainObject(method)) {
|
mergeInterceptorHook(globalInterceptors, method)
|
}
|
}
|
|
export function removeInterceptor (method, option) {
|
if (typeof method === 'string') {
|
if (isPlainObject(option)) {
|
removeInterceptorHook(scopedInterceptors[method], option)
|
} else {
|
delete scopedInterceptors[method]
|
}
|
} else if (isPlainObject(method)) {
|
removeInterceptorHook(globalInterceptors, method)
|
}
|
}
|
|
function wrapperHook (hook, params) {
|
return function (data) {
|
return hook(data, params) || data
|
}
|
}
|
|
function isPromise (obj) {
|
return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'
|
}
|
|
function queue (hooks, data, params) {
|
let promise = false
|
for (let i = 0; i < hooks.length; i++) {
|
const hook = hooks[i]
|
if (promise) {
|
promise = Promise.resolve(wrapperHook(hook, params))
|
} else {
|
const res = hook(data, params)
|
if (isPromise(res)) {
|
promise = Promise.resolve(res)
|
}
|
if (res === false) {
|
return {
|
then () { }
|
}
|
}
|
}
|
}
|
return promise || {
|
then (callback) {
|
return callback(data)
|
}
|
}
|
}
|
|
function wrapperOptions (interceptor, options = {}) {
|
['success', 'fail', 'complete'].forEach(name => {
|
if (Array.isArray(interceptor[name])) {
|
const oldCallback = options[name]
|
options[name] = function callbackInterceptor (res) {
|
queue(interceptor[name], res, options).then((res) => {
|
/* eslint-disable no-mixed-operators */
|
return isFn(oldCallback) && oldCallback(res) || res
|
})
|
}
|
}
|
})
|
return options
|
}
|
|
export function wrapperReturnValue (method, returnValue) {
|
const returnValueHooks = []
|
if (Array.isArray(globalInterceptors.returnValue)) {
|
returnValueHooks.push(...globalInterceptors.returnValue)
|
}
|
const interceptor = scopedInterceptors[method]
|
if (interceptor && Array.isArray(interceptor.returnValue)) {
|
returnValueHooks.push(...interceptor.returnValue)
|
}
|
returnValueHooks.forEach(hook => {
|
returnValue = hook(returnValue) || returnValue
|
})
|
return returnValue
|
}
|
|
function getApiInterceptorHooks (method) {
|
const interceptor = Object.create(null)
|
Object.keys(globalInterceptors).forEach(hook => {
|
if (hook !== 'returnValue') {
|
interceptor[hook] = globalInterceptors[hook].slice()
|
}
|
})
|
const scopedInterceptor = scopedInterceptors[method]
|
if (scopedInterceptor) {
|
Object.keys(scopedInterceptor).forEach(hook => {
|
if (hook !== 'returnValue') {
|
interceptor[hook] = (interceptor[hook] || []).concat(scopedInterceptor[hook])
|
}
|
})
|
}
|
return interceptor
|
}
|
|
export function invokeApi (method, api, options, ...params) {
|
const interceptor = getApiInterceptorHooks(method)
|
if (interceptor && Object.keys(interceptor).length) {
|
if (Array.isArray(interceptor.invoke)) {
|
const res = queue(interceptor.invoke, options)
|
return res.then((options) => {
|
// 重新访问 getApiInterceptorHooks, 允许 invoke 中再次调用 addInterceptor,removeInterceptor
|
return api(
|
wrapperOptions(getApiInterceptorHooks(method), options),
|
...params
|
)
|
})
|
} else {
|
return api(wrapperOptions(interceptor, options), ...params)
|
}
|
}
|
return api(options, ...params)
|
}
|
|
export const promiseInterceptor = {
|
returnValue (res) {
|
if (!isPromise(res)) {
|
return res
|
}
|
return new Promise((resolve, reject) => {
|
res.then(res => {
|
if (res[0]) {
|
reject(res[0])
|
} else {
|
resolve(res[1])
|
}
|
})
|
})
|
}
|
}
|