diff --git a/src/adapter.ts b/src/adapter.ts index d6d62b5..03bb2d3 100644 --- a/src/adapter.ts +++ b/src/adapter.ts @@ -4,8 +4,8 @@ import { isPlainObject, isString, isUndefined, -} from './helpers/is'; -import { assert, throwError } from './helpers/utils'; +} from './helpers/isTypes'; +import { assert, throwError } from './helpers/error'; import { AxiosProgressCallback, AxiosRequestFormData, @@ -53,7 +53,11 @@ export interface AxiosAdapterRequestConfig extends AnyObject { */ method: AxiosAdapterRequestMethod; /** - * 请求的数据 + * 请求参数 + */ + params?: AnyObject; + /** + * 请求数据 */ data?: AnyObject; /** diff --git a/src/axios.ts b/src/axios.ts index 3b0a13c..9874aa5 100644 --- a/src/axios.ts +++ b/src/axios.ts @@ -7,7 +7,7 @@ import Axios, { } from './core/Axios'; import { CancelToken, CancelTokenConstructor, isCancel } from './core/cancel'; import { mergeConfig } from './core/mergeConfig'; -import { isString } from './helpers/is'; +import { isString } from './helpers/isTypes'; import defaults from './defaults'; export interface AxiosInstance extends Axios { @@ -19,7 +19,9 @@ export interface AxiosInstance extends Axios { export interface AxiosStatic extends AxiosInstance { Axios: AxiosConstructor; - defaults: AxiosRequestConfig & { headers: Required }; + defaults: AxiosRequestConfig & { + headers: Required & { common?: AnyObject }; + }; CancelToken: CancelTokenConstructor; create(defaults?: AxiosRequestConfig): AxiosInstance; createAdapter(platform: AxiosPlatform): AxiosAdapter; diff --git a/src/core/Axios.ts b/src/core/Axios.ts index 4a8a208..b8ec38c 100644 --- a/src/core/Axios.ts +++ b/src/core/Axios.ts @@ -1,4 +1,4 @@ -import { buildURL } from '../helpers/url'; +import { buildURL } from '../helpers/buildURL'; import { mergeConfig } from './mergeConfig'; import { AxiosAdapter, diff --git a/src/core/dispatchRequest.ts b/src/core/dispatchRequest.ts index 6c7fd64..20ac484 100644 --- a/src/core/dispatchRequest.ts +++ b/src/core/dispatchRequest.ts @@ -1,4 +1,4 @@ -import { isPlainObject } from '../helpers/is'; +import { isPlainObject } from '../helpers/isTypes'; import { isCancel } from './cancel'; import { flattenHeaders } from './flattenHeaders'; import { transformData } from './transformData'; diff --git a/src/core/flattenHeaders.ts b/src/core/flattenHeaders.ts index 2b1f6e2..74a7f1b 100644 --- a/src/core/flattenHeaders.ts +++ b/src/core/flattenHeaders.ts @@ -1,5 +1,5 @@ -import { isPlainObject } from '../helpers/is'; -import { omit } from '../helpers/utils'; +import { isPlainObject } from '../helpers/isTypes'; +import { omit } from '../helpers/omit'; import { AxiosRequestConfig, AxiosRequestHeaders } from './Axios'; export function flattenHeaders( diff --git a/src/core/mergeConfig.ts b/src/core/mergeConfig.ts index 5d47d32..fd814d1 100644 --- a/src/core/mergeConfig.ts +++ b/src/core/mergeConfig.ts @@ -1,5 +1,5 @@ -import { isUndefined, isPlainObject } from '../helpers/is'; -import { deepMerge } from '../helpers/utils'; +import { isUndefined, isPlainObject } from '../helpers/isTypes'; +import { deepMerge } from '../helpers/deepMerge'; import { AxiosRequestConfig } from './Axios'; type AxiosRequestConfigKey = keyof AxiosRequestConfig; diff --git a/src/core/request.ts b/src/core/request.ts index fe4bf29..7209264 100644 --- a/src/core/request.ts +++ b/src/core/request.ts @@ -1,5 +1,5 @@ -import { isFunction, isPlainObject } from '../helpers/is'; -import { assert } from '../helpers/utils'; +import { isFunction, isPlainObject } from '../helpers/isTypes'; +import { assert } from '../helpers/error'; import { AxiosAdapterRequestConfig, AxiosAdapterRequestMethod, @@ -19,16 +19,17 @@ function tryToggleProgressUpdate( adapterConfig: AxiosAdapterRequestConfig, progressUpdate?: (callback: AxiosProgressCallback) => void, ) { + const { onUploadProgress, onDownloadProgress } = adapterConfig; if (isFunction(progressUpdate)) { switch (adapterConfig.type) { case 'upload': - if (isFunction(adapterConfig.onUploadProgress)) { - progressUpdate(adapterConfig.onUploadProgress); + if (isFunction(onUploadProgress)) { + progressUpdate(onUploadProgress); } break; case 'download': - if (isFunction(adapterConfig.onDownloadProgress)) { - progressUpdate(adapterConfig.onDownloadProgress); + if (isFunction(onDownloadProgress)) { + progressUpdate(onDownloadProgress); } break; default: diff --git a/src/core/transformData.ts b/src/core/transformData.ts index ba0d85c..0091ddd 100644 --- a/src/core/transformData.ts +++ b/src/core/transformData.ts @@ -1,4 +1,4 @@ -import { isArray, isUndefined } from '../helpers/is'; +import { isArray, isUndefined } from '../helpers/isTypes'; import { AxiosRequestFormData } from './Axios'; export interface AxiosTransformer { diff --git a/src/core/transformURL.ts b/src/core/transformURL.ts index 0354846..b3c8bcd 100644 --- a/src/core/transformURL.ts +++ b/src/core/transformURL.ts @@ -1,18 +1,13 @@ -import { - buildURL, - combineURL, - dynamicInterpolation, - isAbsoluteURL, - isDynamicURL, -} from '../helpers/url'; +import { buildURL } from '../helpers/buildURL'; +import { combineURL } from '../helpers/combineURL'; +import { dynamicInterpolation, isDynamicURL } from '../helpers/dynamicURL'; +import { isAbsoluteURL } from '../helpers/isAbsoluteURL'; import { AxiosRequestConfig } from './Axios'; export function transformURL(config: AxiosRequestConfig): string { let url = config.url ?? ''; - if (!isAbsoluteURL(url)) { - url = combineURL(config.baseURL, url); - } + if (!isAbsoluteURL(url)) url = combineURL(config.baseURL, url); if (isDynamicURL(url)) { const sourceData = Object.assign({}, config.params, config.data); diff --git a/src/helpers/url.ts b/src/helpers/buildURL.ts similarity index 67% rename from src/helpers/url.ts rename to src/helpers/buildURL.ts index e7be263..be8378b 100644 --- a/src/helpers/url.ts +++ b/src/helpers/buildURL.ts @@ -1,15 +1,4 @@ -import { isDate, isNull, isPlainObject, isUndefined } from './is'; - -function encode(str: string): string { - return encodeURIComponent(str) - .replace(/%40/gi, '@') - .replace(/%3A/gi, ':') - .replace(/%24/g, '$') - .replace(/%2C/gi, ',') - .replace(/%20/g, '+') - .replace(/%5B/gi, '[') - .replace(/%5D/gi, ']'); -} +import { isDate, isNull, isPlainObject, isUndefined } from './isTypes'; export function buildURL( url = '', @@ -23,38 +12,6 @@ export function buildURL( return generateURL(url, paramsSerializer(params)); } -const combineREG = /([^:])\/{2,}/g; -export function combineURL(baseURL = '', url: string): string { - const separator = '/'; - const replaceStr = `$1${separator}`; - - return `${baseURL}${separator}${url}`.replace(combineREG, replaceStr); -} - -const dynamicREG = /\/?(:([a-zA-Z_$][\w-$]*))\/??/g; -export function dynamicInterpolation( - url: string, - sourceData?: unknown, -): string { - if (!isPlainObject(sourceData)) { - return url; - } - - return url.replace(dynamicREG, ($1, $2, $3) => - $1.replace($2, sourceData[$3]), - ); -} - -const absoluteREG = /^([a-z][a-z\d+\-.]*:)?\/\//i; -export function isAbsoluteURL(url: string): boolean { - return absoluteREG.test(url); -} - -export function isDynamicURL(url: string): boolean { - dynamicREG.lastIndex = 0; - return dynamicREG.test(url); -} - function generateURL(url: string, serializedParams: string): string { const hashIndex = url.indexOf('#'); @@ -106,3 +63,14 @@ function paramsSerialization(params?: AnyObject): string { return parts.join('&'); } + +function encode(str: string): string { + return encodeURIComponent(str) + .replace(/%40/gi, '@') + .replace(/%3A/gi, ':') + .replace(/%24/g, '$') + .replace(/%2C/gi, ',') + .replace(/%20/g, '+') + .replace(/%5B/gi, '[') + .replace(/%5D/gi, ']'); +} diff --git a/src/helpers/combineURL.ts b/src/helpers/combineURL.ts new file mode 100644 index 0000000..5ebeb68 --- /dev/null +++ b/src/helpers/combineURL.ts @@ -0,0 +1,7 @@ +const combineREG = /([^:])\/{2,}/g; +export function combineURL(baseURL = '', url: string): string { + const separator = '/'; + const replaceStr = `$1${separator}`; + + return `${baseURL}${separator}${url}`.replace(combineREG, replaceStr); +} diff --git a/src/helpers/deepMerge.ts b/src/helpers/deepMerge.ts new file mode 100644 index 0000000..4ecd4f3 --- /dev/null +++ b/src/helpers/deepMerge.ts @@ -0,0 +1,22 @@ +import { isPlainObject } from './isTypes'; + +export function deepMerge(...objs: T[]): T { + const result: AnyObject = {}; + + objs.forEach((obj: AnyObject) => + Object.keys(obj).forEach((key) => { + const val = obj[key]; + const resultVal = result[key]; + + if (isPlainObject(resultVal) && isPlainObject(val)) { + result[key] = deepMerge(resultVal, val); + } else if (isPlainObject(val)) { + result[key] = deepMerge(val); + } else { + result[key] = val; + } + }), + ); + + return result as T; +} diff --git a/src/helpers/dynamicURL.ts b/src/helpers/dynamicURL.ts new file mode 100644 index 0000000..dec0166 --- /dev/null +++ b/src/helpers/dynamicURL.ts @@ -0,0 +1,21 @@ +import { isPlainObject } from './isTypes'; + +const dynamicREG = /\/?(:([a-zA-Z_$][\w-$]*))\/??/g; + +export function dynamicInterpolation( + url: string, + sourceData?: unknown, +): string { + if (!isPlainObject(sourceData)) { + return url; + } + + return url.replace(dynamicREG, ($1, $2, $3) => + $1.replace($2, sourceData[$3]), + ); +} + +export function isDynamicURL(url: string): boolean { + dynamicREG.lastIndex = 0; + return dynamicREG.test(url); +} diff --git a/src/helpers/error.ts b/src/helpers/error.ts new file mode 100644 index 0000000..f8ba1ff --- /dev/null +++ b/src/helpers/error.ts @@ -0,0 +1,9 @@ +export function assert(condition: boolean, msg: string) { + if (!condition) { + throwError(msg); + } +} + +export function throwError(msg: string): void { + throw new Error(`[axios-miniprogram]: ${msg}`); +} diff --git a/src/helpers/isAbsoluteURL.ts b/src/helpers/isAbsoluteURL.ts new file mode 100644 index 0000000..b244389 --- /dev/null +++ b/src/helpers/isAbsoluteURL.ts @@ -0,0 +1,4 @@ +const absoluteREG = /^([a-z][a-z\d+\-.]*:)?\/\//i; +export function isAbsoluteURL(url: string): boolean { + return absoluteREG.test(url); +} diff --git a/src/helpers/is.ts b/src/helpers/isTypes.ts similarity index 100% rename from src/helpers/is.ts rename to src/helpers/isTypes.ts diff --git a/src/helpers/omit.ts b/src/helpers/omit.ts new file mode 100644 index 0000000..5f18be6 --- /dev/null +++ b/src/helpers/omit.ts @@ -0,0 +1,8 @@ +export function omit( + obj: T, + ...keys: K[] +): Omit { + const res = { ...obj }; + keys.forEach((key: K) => delete res[key]); + return res; +} diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts deleted file mode 100644 index debc9cf..0000000 --- a/src/helpers/utils.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { isPlainObject } from './is'; - -export function deepMerge(...objs: T[]): T { - const result: AnyObject = {}; - - objs.forEach((obj: AnyObject) => - Object.keys(obj).forEach((key) => { - const val = obj[key]; - const resultVal = result[key]; - - if (isPlainObject(resultVal) && isPlainObject(val)) { - result[key] = deepMerge(resultVal, val); - } else if (isPlainObject(val)) { - result[key] = deepMerge(val); - } else { - result[key] = val; - } - }), - ); - - return result as T; -} - -export function pick( - obj: T, - ...keys: K[] -): Pick { - const _pick: Partial = {}; - - keys.forEach((key: K) => (_pick[key] = obj[key])); - - return _pick as Pick; -} - -export function omit( - obj: T, - ...keys: K[] -): Omit { - const _omit = Object.assign({}, obj); - - keys.forEach((key: K) => delete _omit[key]); - - return _omit; -} - -export function assert(condition: boolean, msg: string) { - if (!condition) { - throwError(msg); - } -} - -export function throwError(msg: string): void { - throw new Error(`[axios-miniprogram]: ${msg}`); -} diff --git a/test/helpers/error.test.ts b/test/helpers/error.test.ts new file mode 100644 index 0000000..6a6f30d --- /dev/null +++ b/test/helpers/error.test.ts @@ -0,0 +1,19 @@ +import { describe, test, expect } from 'vitest'; +import { assert, throwError } from '../../src/helpers/error'; + +describe('测试 src/helpers/error.ts', () => { + test('第一个参数为 true 时应该无事发生', () => { + expect(assert(true, '')).toBeUndefined(); + }); + + test('第一个参数为 false 时应该抛出异常', () => { + expect(() => assert(false, '')).toThrowError(); + }); + + test('应该抛出异常', () => { + expect(() => throwError('')).toThrowError('[axios-miniprogram]: '); + expect(() => throwError('error')).toThrowError( + '[axios-miniprogram]: error', + ); + }); +}); diff --git a/test/helpers/is.test.ts b/test/helpers/is.test.ts deleted file mode 100644 index 549c91b..0000000 --- a/test/helpers/is.test.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { describe, test, expect } from 'vitest'; -import { - isArray, - isDate, - isEmptyArray, - isEmptyObject, - isFunction, - isNull, - isPlainObject, - isString, - isUndefined, -} from '../../src/helpers/is'; - -describe('对 src/helpers/is.ts 进行测试', () => { - test('传入数组应该返回 true,其他参数应该返回 fasle', () => { - expect(isArray([0])).toBe(true); - expect(isArray([])).toBe(true); - expect(isArray({})).toBe(false); - expect(isArray(0)).toBe(false); - expect(isArray('')).toBe(false); - expect(isArray(undefined)).toBe(false); - expect(isArray(null)).toBe(false); - }); - - test('传入 Date 实例应该返回 true,其他参数应该返回 fasle', () => { - expect(isDate(new Date())).toBe(true); - expect(isDate({})).toBe(false); - expect(isDate([])).toBe(false); - expect(isDate(0)).toBe(false); - expect(isDate('')).toBe(false); - expect(isDate(undefined)).toBe(false); - expect(isDate(null)).toBe(false); - }); - - test('传入空数组应该返回 true,其他参数应该返回 fasle', () => { - expect(isEmptyArray([])).toBe(true); - expect(isEmptyArray([0])).toBe(false); - expect(isEmptyArray({})).toBe(false); - expect(isEmptyArray(0)).toBe(false); - expect(isEmptyArray('')).toBe(false); - expect(isEmptyArray(undefined)).toBe(false); - expect(isEmptyArray(null)).toBe(false); - }); - - test('传入空对象应该返回 true,其他参数应该返回 fasle', () => { - expect(isEmptyObject({})).toBe(true); - expect(isEmptyObject({ a: 0 })).toBe(false); - expect(isEmptyObject([0])).toBe(false); - expect(isEmptyObject([])).toBe(false); - expect(isEmptyObject(0)).toBe(false); - expect(isEmptyObject('')).toBe(false); - expect(isEmptyObject(undefined)).toBe(false); - expect(isEmptyObject(null)).toBe(false); - }); - - test('传入空函数应该返回 true,其他参数应该返回 fasle', () => { - expect( - isFunction(() => { - return; - }), - ).toBe(true); - expect( - isFunction(function () { - return; - }), - ).toBe(true); - expect(isFunction({})).toBe(false); - expect(isFunction([])).toBe(false); - expect(isFunction(0)).toBe(false); - expect(isFunction('')).toBe(false); - expect(isFunction(undefined)).toBe(false); - expect(isFunction(null)).toBe(false); - }); - - test('传入空 null 应该返回 true,其他参数应该返回 fasle', () => { - expect(isNull(null)).toBe(true); - expect(isNull({ a: 0 })).toBe(false); - expect(isNull([0])).toBe(false); - expect(isNull([])).toBe(false); - expect(isNull(0)).toBe(false); - expect(isNull('')).toBe(false); - expect(isNull(undefined)).toBe(false); - }); - - test('传入普通对象应该返回 true,其他参数应该返回 fasle', () => { - expect(isPlainObject({})).toBe(true); - expect(isPlainObject({ a: 0 })).toBe(true); - expect(isPlainObject([0])).toBe(false); - expect(isPlainObject([])).toBe(false); - expect(isPlainObject(0)).toBe(false); - expect(isPlainObject('')).toBe(false); - expect(isPlainObject(undefined)).toBe(false); - expect(isPlainObject(null)).toBe(false); - }); - - test('传入字符串应该返回 true,其他参数应该返回 fasle', () => { - expect(isString('')).toBe(true); - expect(isString({})).toBe(false); - expect(isString({ a: 0 })).toBe(false); - expect(isString([0])).toBe(false); - expect(isString([])).toBe(false); - expect(isString(0)).toBe(false); - expect(isString(undefined)).toBe(false); - expect(isString(null)).toBe(false); - }); - - test('传入 undefined 应该返回 true,其他参数应该返回 fasle', () => { - expect(isUndefined(undefined)).toBe(true); - expect(isUndefined('')).toBe(false); - expect(isUndefined({})).toBe(false); - expect(isUndefined({ a: 0 })).toBe(false); - expect(isUndefined([0])).toBe(false); - expect(isUndefined([])).toBe(false); - expect(isUndefined(0)).toBe(false); - expect(isUndefined(null)).toBe(false); - }); -}); diff --git a/test/helpers/utils.test.ts b/test/helpers/utils.test.ts deleted file mode 100644 index 8f6f183..0000000 --- a/test/helpers/utils.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { describe, test, expect } from 'vitest'; -import { - assert, - deepMerge, - omit, - pick, - throwError, -} from '../../src/helpers/utils'; - -describe('对 src/helpers/utils.ts 进行测试', () => { - test('测试 assert() 是否符合预期', () => { - expect(assert(true, '')).toBeUndefined(); - expect(() => assert(false, '')).toThrow(); - expect(() => assert(false, 'msg')).toThrowError('[axios-miniprogram]: msg'); - }); - - test('测试 deepMerge() 是否符合预期', () => { - expect(deepMerge({})).toEqual({}); - expect(deepMerge({ a: 1 }, { b: 2 })).toEqual({ a: 1, b: 2 }); - expect(deepMerge({ a: { a: 1 } }, { a: { b: 2 } })).toEqual({ - a: { a: 1, b: 2 }, - }); - expect(deepMerge({ a: { a: 1, b: 1 } }, { a: { a: 2, b: 2 } })).toEqual({ - a: { a: 2, b: 2 }, - }); - expect(deepMerge({ a: { a: 1 } }, { a: 2 })).toEqual({ - a: 2, - }); - }); - - test('测试 omit() 是否符合预期', () => { - expect(omit({})).toEqual({}); - expect(omit({ a: 1, b: 1 }, 'a')).toEqual({ b: 1 }); - expect(omit({ a: 1, b: 1 }, 'a', 'b')).toEqual({}); - }); - - test('测试 pick() 是否符合预期', () => { - expect(pick({})).toEqual({}); - expect(pick({ a: 1, b: 1 }, 'a')).toEqual({ a: 1 }); - expect(pick({ a: 1, b: 1 }, 'a', 'b')).toEqual({ a: 1, b: 1 }); - }); - - test('测试 throwError() 是否符合预期', () => { - expect(() => throwError('')).toThrowError('[axios-miniprogram]: '); - expect(() => throwError('msg')).toThrowError('[axios-miniprogram]: msg'); - expect(() => throwError(' msg ')).toThrowError( - '[axios-miniprogram]: msg ', - ); - }); -});