Skip to content

Commit 4409a57

Browse files
committed
feat: 支持合并自定义配置
#38
1 parent ce12a83 commit 4409a57

27 files changed

+823
-378
lines changed

docs/config/adapter.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ axios.defaults.adapter = function adapter(adapterConfig) {
1313
url,
1414
// 请求方法
1515
method,
16+
// 请求参数
17+
params,
1618
// 请求数据
1719
data,
1820
// 请求头 同 headers
@@ -53,7 +55,7 @@ axios.defaults.adapter = function adapter(adapterConfig) {
5355
return wx.downloadFile({
5456
url,
5557
method,
56-
filePath: data.filePath,
58+
filePath: params.filePath,
5759
header: headers,
5860
success,
5961
fail,

global.d.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1 @@
1-
declare const uni: unknown;
2-
declare const wx: unknown;
3-
declare const my: unknown;
4-
declare const swan: unknown;
5-
declare const tt: unknown;
6-
declare const qq: unknown;
7-
declare const qh: unknown;
8-
declare const ks: unknown;
9-
declare const dd: unknown;
10-
declare const jd: unknown;
11-
121
type AnyObject<T = any> = Record<string, T>;

global.variables.d.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
declare const uni: unknown;
2+
declare const wx: unknown;
3+
declare const my: unknown;
4+
declare const swan: unknown;
5+
declare const tt: unknown;
6+
declare const qq: unknown;
7+
declare const qh: unknown;
8+
declare const ks: unknown;
9+
declare const dd: unknown;
10+
declare const jd: unknown;

rollup.config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ function main() {
2323
function buildConfig(format) {
2424
const isDts = format === 'dts';
2525
const output = {
26-
file: resolvePath(format, isDts),
26+
file: resolveOutput(format, isDts),
2727
format: isDts ? 'es' : format,
2828
name: pkg.name,
2929
exports: 'default',
@@ -51,7 +51,7 @@ function buildConfig(format) {
5151
};
5252
}
5353

54-
function resolvePath(format, isDts) {
54+
function resolveOutput(format, isDts) {
5555
return path.resolve(
5656
distPath,
5757
`${pkg.name}${isDts ? '.d.ts' : `.${format}.js`}`,

scripts/test.utils.ts

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export function asyncTimeout(delay = 0) {
88
return new Promise((resolve) => setTimeout(resolve, delay));
99
}
1010

11-
export function captureError<T = any>(fn: () => void): T {
11+
export function captureError<T = any>(fn: () => void) {
1212
try {
1313
fn();
1414
throw new Error('without Error');
@@ -17,7 +17,7 @@ export function captureError<T = any>(fn: () => void): T {
1717
}
1818
}
1919

20-
export function cleanedStack(error: Error) {
20+
export function checkStack(error: Error) {
2121
if (error.stack) {
2222
return error.stack.indexOf('at') === error.stack.indexOf('at /');
2323
}
@@ -28,7 +28,7 @@ export function noop() {
2828
return;
2929
}
3030

31-
export function mockResponse(
31+
export function mockResponseBase(
3232
status: number,
3333
statusText: string,
3434
headers: AnyObject,
@@ -42,12 +42,15 @@ export function mockResponse(
4242
};
4343
}
4444

45-
export function mockSuccess(headers: AnyObject = {}, data: AnyObject = {}) {
46-
return mockResponse(200, 'OK', headers, data);
45+
export function mockResponse(headers: AnyObject = {}, data: AnyObject = {}) {
46+
return mockResponseBase(200, 'OK', headers, data);
4747
}
4848

49-
export function mockFail(headers: AnyObject = {}, data: AnyObject = {}) {
50-
return mockResponse(400, 'FAIL', headers, data);
49+
export function mockResponseError(
50+
headers: AnyObject = {},
51+
data: AnyObject = {},
52+
) {
53+
return mockResponseBase(400, 'FAIL', headers, data);
5154
}
5255

5356
export interface MockAdapterOptions {
@@ -58,29 +61,39 @@ export interface MockAdapterOptions {
5861
after?: () => void;
5962
}
6063

61-
export function mockAdapter(
62-
type: 'success' | 'fail',
64+
export function mockAdapterBase(
65+
type: 'success' | 'error' | 'fail' = 'success',
6366
options: MockAdapterOptions = {},
6467
) {
6568
const { headers = {}, data = {}, delay = 0, before, after } = options;
6669

6770
return (config: AxiosAdapterRequestConfig) => {
6871
before?.(config);
6972
setTimeout(() => {
70-
if (type === 'success') {
71-
config.success(mockSuccess(headers, data));
72-
} else {
73-
config.fail(mockFail(headers, data));
73+
switch (type) {
74+
case 'success':
75+
config.success(mockResponse(headers, data));
76+
break;
77+
case 'error':
78+
config.success(mockResponseError(headers, data));
79+
break;
80+
case 'fail':
81+
config.fail(mockResponseError(headers));
82+
break;
7483
}
7584
after?.();
7685
}, delay);
7786
};
7887
}
7988

80-
export function mockAdapterSuccess(options: MockAdapterOptions = {}) {
81-
return mockAdapter('success', options);
89+
export function mockAdapter(options: MockAdapterOptions = {}) {
90+
return mockAdapterBase('success', options);
91+
}
92+
93+
export function mockAdapterError(options: MockAdapterOptions = {}) {
94+
return mockAdapterBase('error', options);
8295
}
8396

8497
export function mockAdapterFail(options: MockAdapterOptions = {}) {
85-
return mockAdapter('fail', options);
98+
return mockAdapterBase('fail', options);
8699
}

src/core/Axios.ts

Lines changed: 19 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -198,20 +198,34 @@ export default class Axios {
198198
this.defaults = defaults;
199199

200200
for (const alias of Axios.as) {
201-
this[alias] = (url, config) => {
202-
return this._req(alias, url, undefined, config);
201+
this[alias] = (url, config = {}) => {
202+
return this.request({
203+
...config,
204+
method: alias,
205+
url,
206+
});
203207
};
204208
}
205209

206210
for (const alias of Axios.pas) {
207-
this[alias] = (url, params, config) => {
208-
return this._req(alias, url, params, config);
211+
this[alias] = (url, params, config = {}) => {
212+
return this.request({
213+
...config,
214+
method: alias,
215+
params,
216+
url,
217+
});
209218
};
210219
}
211220

212221
for (const alias of Axios.das) {
213222
this[alias] = (url, data, config) => {
214-
return this._reqWithData(alias, url, data, config);
223+
return this.request({
224+
...config,
225+
method: alias,
226+
data,
227+
url,
228+
});
215229
};
216230
}
217231
}
@@ -249,32 +263,4 @@ export default class Axios {
249263

250264
return promiseResponse as Promise<AxiosResponse<TData>>;
251265
}
252-
253-
private _req<TData = unknown>(
254-
method: AxiosRequestMethod,
255-
url: string,
256-
params?: AnyObject,
257-
config?: AxiosRequestConfig,
258-
): Promise<AxiosResponse<TData>> {
259-
return this.request<TData>({
260-
...(config ?? {}),
261-
method,
262-
url,
263-
params,
264-
});
265-
}
266-
267-
private _reqWithData<TData = unknown>(
268-
method: AxiosRequestMethod,
269-
url: string,
270-
data?: AnyObject | AxiosRequestFormData,
271-
config?: AxiosRequestConfig,
272-
): Promise<AxiosResponse<TData>> {
273-
return this.request<TData>({
274-
...(config ?? {}),
275-
method,
276-
url,
277-
data,
278-
});
279-
}
280266
}

src/core/dispatchRequest.ts

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,32 +27,28 @@ export default function dispatchRequest<TData = unknown>(
2727
config.transformRequest,
2828
);
2929

30-
return request<TData>(config).then(
31-
(response: AxiosResponse<TData>) => {
32-
throwIfCancellationRequested(config);
33-
34-
response.data = transformData(
35-
response.data as AnyObject,
36-
response.headers,
37-
config.transformResponse,
38-
) as TData;
30+
function transformer(response: AxiosResponse<TData>) {
31+
response.data = transformData(
32+
response.data as AnyObject,
33+
response.headers,
34+
config.transformResponse,
35+
) as TData;
36+
}
3937

38+
return request<TData>(config)
39+
.then((response: AxiosResponse<TData>) => {
40+
throwIfCancellationRequested(config);
41+
transformer(response);
4042
return response;
41-
},
42-
(reason: unknown) => {
43+
})
44+
.catch((reason: unknown) => {
4345
if (!isCancel(reason)) {
4446
throwIfCancellationRequested(config);
45-
46-
if (isPlainObject(reason) && isPlainObject(reason.response)) {
47-
reason.response.data = transformData(
48-
reason.response.data,
49-
reason.response.headers,
50-
config.transformResponse,
51-
);
47+
const response = (reason as AnyObject)?.response;
48+
if (isPlainObject(response)) {
49+
transformer(response as AxiosResponse<TData>);
5250
}
5351
}
54-
5552
throw config.errorHandler?.(reason) ?? reason;
56-
},
57-
);
53+
});
5854
}

src/core/mergeConfig.ts

Lines changed: 38 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2,69 +2,54 @@ import { isUndefined, isPlainObject } from '../helpers/isTypes';
22
import { deepMerge } from '../helpers/deepMerge';
33
import { AxiosRequestConfig } from './Axios';
44

5-
type AxiosRequestConfigKey = keyof AxiosRequestConfig;
6-
7-
const onlyFromConfig2Keys: AxiosRequestConfigKey[] = [
8-
'url',
9-
'method',
10-
'data',
11-
'upload',
12-
'download',
13-
];
14-
const priorityFromConfig2Keys: AxiosRequestConfigKey[] = [
15-
'adapter',
16-
'baseURL',
17-
'paramsSerializer',
18-
'transformRequest',
19-
'transformResponse',
20-
'errorHandler',
21-
'cancelToken',
22-
'dataType',
23-
'responseType',
24-
'timeout',
25-
'enableHttp2',
26-
'enableQuic',
27-
'enableCache',
28-
'sslVerify',
29-
'validateStatus',
30-
'onUploadProgress',
31-
'onDownloadProgress',
32-
];
33-
const deepMergeConfigKeys: AxiosRequestConfigKey[] = ['headers', 'params'];
5+
const fromConfig2Map: Record<string, boolean> = {
6+
url: true,
7+
method: true,
8+
data: true,
9+
upload: true,
10+
download: true,
11+
};
12+
const deepMergeConfigMap: Record<string, boolean> = {
13+
headers: true,
14+
params: true,
15+
};
3416

3517
export function mergeConfig(
3618
config1: AxiosRequestConfig = {},
3719
config2: AxiosRequestConfig = {},
3820
): AxiosRequestConfig {
3921
const config: AxiosRequestConfig = {};
4022

41-
for (const key of onlyFromConfig2Keys) {
42-
const value = config2[key];
43-
44-
if (!isUndefined(value)) {
45-
config[key] = value as any;
46-
}
47-
}
23+
// 所有已知键名
24+
const keysSet = Array.from(
25+
new Set([...Object.keys(config1), ...Object.keys(config2)]),
26+
);
4827

49-
for (const key of priorityFromConfig2Keys) {
50-
const value1 = config1[key];
51-
const value2 = config2[key];
28+
for (const key of keysSet) {
29+
const val1 = config1[key] as any;
30+
const val2 = config2[key] as any;
5231

53-
if (!isUndefined(value2)) {
54-
config[key] = value2 as any;
55-
} else if (!isUndefined(value1)) {
56-
config[key] = value1 as any;
32+
// 只从 config2 中取值
33+
if (fromConfig2Map[key]) {
34+
if (!isUndefined(val2)) config[key] = val2;
5735
}
58-
}
59-
60-
for (const key of deepMergeConfigKeys) {
61-
const value1 = config1[key];
62-
const value2 = config2[key];
63-
64-
if (isPlainObject(value2)) {
65-
config[key] = deepMerge(value1 ?? {}, value2) as any;
66-
} else if (isPlainObject(value1)) {
67-
config[key] = deepMerge(value1) as any;
36+
// 深度合并 config1 和 config2 中的对象
37+
else if (deepMergeConfigMap[key]) {
38+
if (isPlainObject(val1) && isPlainObject(val2)) {
39+
config[key] = deepMerge(val1, val2);
40+
} else if (isPlainObject(val1)) {
41+
config[key] = deepMerge(val1);
42+
} else if (isPlainObject(val2)) {
43+
config[key] = deepMerge(val2);
44+
}
45+
}
46+
// 优先从 config2 中取值,如果没有值就从 config1 中取值
47+
else {
48+
if (!isUndefined(val2)) {
49+
config[key] = val2;
50+
} else if (!isUndefined(val1)) {
51+
config[key] = val1;
52+
}
6853
}
6954
}
7055

0 commit comments

Comments
 (0)