chore: 修改部分内容

pull/49/head
zjx0905 2023-05-04 10:39:52 +08:00
parent 52037b8794
commit cea4be518c
15 changed files with 1475 additions and 1477 deletions

View File

@ -1,50 +1,52 @@
const { execSync } = require('child_process'); const { execSync } = require('child_process')
const metas = [ const metas = [
{ type: 'feat', section: '✨ Features | 新功能' }, { type: 'feat', section: '✨ Features | 新功能' },
{ type: 'fix', section: '🐛 Bug Fixes | Bug 修复' }, { type: 'fix', section: '🐛 Bug Fixes | Bug 修复' },
{ type: 'test', section: '✅ Tests | 测试' }, { type: 'test', section: '✅ Tests | 测试' },
{ type: 'docs', section: '📝 Documentation | 文档' }, { type: 'docs', section: '📝 Documentation | 文档' },
{ type: 'build', section: '👷‍ Build System | 构建' }, { type: 'build', section: '👷‍ Build System | 构建' },
{ type: 'ci', section: '🔧 Continuous Integration | CI 配置' }, { type: 'ci', section: '🔧 Continuous Integration | CI 配置' },
{ type: 'perf', section: '⚡ Performance Improvements | 性能优化' }, { type: 'perf', section: '⚡ Performance Improvements | 性能优化' },
{ type: 'revert', section: '⏪ Reverts | 回退' }, { type: 'revert', section: '⏪ Reverts | 回退' },
{ type: 'chore', section: '📦 Chores | 其他更新' }, { type: 'chore', section: '📦 Chores | 其他更新' },
{ type: 'style', section: '💄 Styles | 风格', hidden: true }, { type: 'style', section: '💄 Styles | 风格', hidden: true },
{ type: 'refactor', section: '♻ Code Refactoring | 代码重构' }, { type: 'refactor', section: '♻ Code Refactoring | 代码重构' },
]; ]
/** @type {import('cz-git').UserConfig} */ /** @type {import('cz-git').UserConfig} */
module.exports = { module.exports = {
rules: { rules: {
// @see: https://commitlint.js.org/#/reference-rules // @see: https://commitlint.js.org/#/reference-rules
'subject-min-length': [0, 'always', 3], 'subject-min-length': [0, 'always', 3],
'subject-max-length': [0, 'always', 80], 'subject-max-length': [0, 'always', 80],
'type-enum': [0, 'always', metas.map((meta) => meta.type)], 'type-enum': [0, 'always', metas.map((meta) => meta.type)],
}, },
prompt: { prompt: {
messages: { messages: {
type: '请选择提交类型', type: '请选择提交类型',
subject: '请输入变更描述', subject: '请输入变更描述',
breaking: '列举非兼容性重大的变更,如果有多行,使用 "|" 换行(选填项)\n', breaking: '列举非兼容性重大的变更,如果有多行,使用 "|" 换行(选填项)\n',
footer: '列举关联的 issue例如#31,#I3244选填项\n', footer: '列举关联的 issue例如#31,#I3244选填项\n',
confirmCommit: '确定提交', confirmCommit: '确定提交',
}, },
types: metas.map((meta) => ({ types: metas.map((meta) => ({
value: meta.type, value: meta.type,
name: `${`${meta.type}:`.padEnd(10, ' ')}${meta.section}`, name: `${`${meta.type}:`.padEnd(10, ' ')}${meta.section}`,
})), })),
allowBreakingChanges: ['feat', 'fix'], allowBreakingChanges: ['feat', 'fix'],
skipQuestions: ['scope', 'body', 'footerPrefix'], skipQuestions: ['scope', 'body', 'footerPrefix'],
formatMessageCB: (commit) => formatMessageCB: (commit) =>
`${commit?.defaultMessage}\n\nCo-authored-by: ${readGitUser( `${commit?.defaultMessage}\n\nCo-authored-by: ${readGitUser(
'name', 'name',
)} <${readGitUser('email')}>`, )} <${readGitUser('email')}>`,
}, },
}; }
function readGitUser(key) { function readGitUser(key) {
return execSync(`git config user.${key}`) return execSync(`git config user.${key}`, {
.toString() stdio: 'pipe',
.replace(/(\r\n\t|\n|\r\t)/g, ''); })
.toString()
.replace(/(\r\n\t|\n|\r\t)/g, '')
} }

View File

@ -1,10 +1,11 @@
{ {
"printWidth": 80, "printWidth": 80,
"tabWidth": 2, "tabWidth": 2,
"useTabs": false, "useTabs": true,
"semi": true, "semi": false,
"singleQuote": true, "singleQuote": true,
"trailingComma": "all", "trailingComma": "all",
"bracketSpacing": true, "bracketSpacing": true,
"arrowParens": "always" "arrowParens": "always",
"jsxSingleQuote": true
} }

View File

@ -50,30 +50,7 @@ import axios, {
createAdapter, createAdapter,
} from 'axios-miniprogram'; } from 'axios-miniprogram';
const { axios('/test');
// 取消令牌
CancelToken,
// 判断取消请求错误
isCancel,
// 原始 Axios 类
Axios,
// 判断请求响应错误
isAxiosError,
// 创建平台适配器
createAdapter,
// 创建实例
create,
// 获取系列化后的 URL
getUri,
} = axios;
axios('test');
``` ```
```ts [CommonJS] ```ts [CommonJS]
@ -98,28 +75,7 @@ const {
createAdapter, createAdapter,
} = require('axios-miniprogram'); } = require('axios-miniprogram');
const { axios('/test');
// 取消令牌
CancelToken,
// 判断取消请求错误
isCancel,
// 原始 Axios 类
Axios,
// 判断请求响应错误
isAxiosError,
// 创建平台适配器
createAdapter,
// 创建实例
create,
// 获取系列化后的 URL
getUri,
} = axios;
``` ```
:::: ::::

View File

@ -1,7 +0,0 @@
{
"name": "example",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
}
}

View File

@ -1,110 +1,110 @@
{ {
"name": "axios-miniprogram", "name": "axios-miniprogram",
"version": "2.4.0", "version": "2.4.0",
"description": "基于 Promise 的 HTTP 请求库,适用于各大小程序平台。", "description": "基于 Promise 的 HTTP 请求库,适用于各大小程序平台。",
"main": "dist/axios-miniprogram.cjs.js", "main": "dist/axios-miniprogram.cjs.js",
"module": "dist/axios-miniprogram.esm.js", "module": "dist/axios-miniprogram.esm.js",
"types": "dist/axios-miniprogram.d.ts", "types": "dist/axios-miniprogram.d.ts",
"files": [ "files": [
"dist" "dist"
], ],
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/zjx0905/axios-miniprogram.git" "url": "git+https://github.com/zjx0905/axios-miniprogram.git"
}, },
"keywords": [ "keywords": [
"axios", "axios",
"request", "request",
"mini", "mini",
"miniprogram" "miniprogram"
], ],
"author": "zjx0905 <954270063@qq.com>", "author": "zjx0905 <954270063@qq.com>",
"bugs": { "bugs": {
"url": "https://github.com/zjx0905/axios-miniprogram/issues" "url": "https://github.com/zjx0905/axios-miniprogram/issues"
}, },
"homepage": "https://axios-miniprogram.com", "homepage": "https://axios-miniprogram.com",
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
"engines": { "engines": {
"node": ">=16", "node": ">=16",
"pnpm": ">=7" "pnpm": ">=7"
}, },
"scripts": { "scripts": {
"cz": "simple-git-hooks && czg", "cz": "simple-git-hooks && czg",
"build": "esno scripts/build.ts", "build": "esno scripts/build.ts",
"build:assets": "esno scripts/build.assets.ts", "build:assets": "esno scripts/build.assets.ts",
"watch": "pnpm build -a -w", "watch": "pnpm build -a -w",
"release": "esno scripts/release.ts", "release": "esno scripts/release.ts",
"publish:ci": "esno scripts/publish.ts", "publish:ci": "esno scripts/publish.ts",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s", "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
"releaselog": "esno scripts/releaselog.ts", "releaselog": "esno scripts/releaselog.ts",
"test": "vitest run", "test": "vitest run",
"test:watch": "vitest", "test:watch": "vitest",
"test:cov": "vitest run --coverage", "test:cov": "vitest run --coverage",
"typecheck": "tsc --noEmit", "typecheck": "tsc --noEmit",
"lint": "eslint --cache .", "lint": "eslint --cache . --fix",
"lint:fix": "pnpm lint --fix", "docs:dev": "pnpm -C docs dev",
"docs:dev": "pnpm -C docs dev", "docs:build": "pnpm -C docs build",
"docs:build": "pnpm -C docs build", "docs:preview": "pnpm -C docs preview",
"docs:preview": "pnpm -C docs preview", "docs:deploy": "esno scripts/docs.deploy.ts",
"docs:deploy": "esno scripts/docs.deploy.ts" "start": "esno scripts/start.ts"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "^17.4.4", "@commitlint/cli": "^17.4.4",
"@commitlint/config-conventional": "^17.4.4", "@commitlint/config-conventional": "^17.4.4",
"@rollup/plugin-typescript": "^11.1.0", "@rollup/plugin-typescript": "^11.1.0",
"@types/node": "^18.15.5", "@types/node": "^18.15.5",
"@typescript-eslint/eslint-plugin": "^5.55.0", "@typescript-eslint/eslint-plugin": "^5.55.0",
"@typescript-eslint/parser": "^5.55.0", "@typescript-eslint/parser": "^5.55.0",
"@vitest/coverage-istanbul": "^0.30.0", "@vitest/coverage-istanbul": "^0.30.0",
"chalk": "^5.2.0", "chalk": "^5.2.0",
"consola": "^2.15.3", "consola": "^2.15.3",
"conventional-changelog-cli": "^2.2.2", "conventional-changelog-cli": "^2.2.2",
"cz-git": "1.3.8", "cz-git": "1.3.8",
"czg": "1.3.8", "czg": "1.3.8",
"enquirer": "^2.3.6", "enquirer": "^2.3.6",
"eslint": "^8.36.0", "eslint": "^8.36.0",
"esno": "^0.16.3", "esno": "^0.16.3",
"fast-glob": "^3.2.12", "fast-glob": "^3.2.12",
"jszip": "^3.10.1", "jszip": "^3.10.1",
"lint-staged": "13.2.0", "lint-staged": "13.2.0",
"minimist": "^1.2.8", "minimist": "^1.2.8",
"prettier": "2.8.5", "prettier": "2.8.5",
"rimraf": "^4.4.0", "rimraf": "^4.4.0",
"rollup": "^3.20.0", "rollup": "^3.20.0",
"rollup-plugin-dts": "^5.3.0", "rollup-plugin-dts": "^5.3.0",
"rollup-plugin-esbuild": "^5.0.0", "rollup-plugin-esbuild": "^5.0.0",
"semver": "^7.3.8", "semver": "^7.3.8",
"simple-git-hooks": "^2.8.1", "simple-git-hooks": "^2.8.1",
"tslib": "^2.5.0", "tslib": "^2.5.0",
"typescript": "^5.0.2", "typescript": "^5.0.2",
"vitest": "^0.30.0" "vitest": "^0.30.0"
}, },
"simple-git-hooks": { "simple-git-hooks": {
"pre-commit": "pnpm lint-staged && pnpm test && pnpm build -a", "pre-commit": "pnpm lint-staged && pnpm test && pnpm build -a",
"commit-msg": "pnpm commitlint --edit $1" "commit-msg": "pnpm commitlint --edit $1"
}, },
"config": { "config": {
"commitizen": { "commitizen": {
"path": "node_modules/cz-git" "path": "node_modules/cz-git"
} }
}, },
"lint-staged": { "lint-staged": {
"*.{js,json}": [ "*.{mjs,json}": [
"prettier --write" "prettier --write"
], ],
"*.ts?(x)": [ "*.ts?(x)": [
"eslint", "eslint",
"prettier --parser=typescript --write" "prettier --parser=typescript --write"
] ]
}, },
"pnpm": { "pnpm": {
"peerDependencyRules": { "peerDependencyRules": {
"ignoreMissing": [ "ignoreMissing": [
"@algolia/client-search", "@algolia/client-search",
"esbuild", "esbuild",
"vite" "vite"
] ]
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,2 @@
packages: packages:
- docs - docs
- example

View File

@ -1,33 +1,34 @@
import minimist from 'minimist'; import minimist from 'minimist'
import consola from 'consola'; import consola from 'consola'
import { distPath, exec } from './utils'; import { distPath, exec } from './utils'
import { checkSize } from './checkSize'; import { checkSize } from './checkSize'
import { safeExit } from './utils'
const args = minimist(process.argv.slice(2)); const args = minimist(process.argv.slice(2))
const watch = Boolean(args.watch || args.w); const watch = Boolean(args.watch || args.w)
const all = Boolean(args.all || args.a); const all = Boolean(args.all || args.a)
const sourceMap = all || Boolean(args.sourceMap || args.s); const sourceMap = all || Boolean(args.sourceMap || args.s)
const dts = all || Boolean(args.dts || args.d); const dts = all || Boolean(args.dts || args.d)
main(); main()
function main() { function main() {
exec('rimraf dist'); exec('rimraf dist')
consola.info('Rollup'); consola.info('Rollup')
try {
exec(
`rollup -c rollup.config.ts --configPlugin typescript ${
watch ? '-w' : ''
} --environment SOURCE_MAP:${sourceMap},DTS:${dts}`,
);
checkSize(`${distPath}/**.js`); safeExit(() => {
} catch { exec(
consola.error('已退出'); `rollup -c rollup.config.ts --configPlugin typescript ${
process.exit(); watch ? '-w' : ''
} } --environment SOURCE_MAP:${sourceMap},DTS:${dts}`,
)
})
console.info('\n'); if (!watch) {
checkSize(`${distPath}/**.js`)
}
console.info('\n')
} }

29
scripts/start.ts Normal file
View File

@ -0,0 +1,29 @@
import enquirer from 'enquirer'
import { exec } from './utils'
import { safeExit } from './utils'
const metas = [
{ name: 'weapp', message: '微信小程序' },
{ name: 'swan', message: '百度小程序' },
{ name: 'alipay', message: '支付宝小程序' },
{ name: 'tt', message: '抖音小程序' },
{ name: 'qq', message: 'QQ 小程序' },
{ name: 'jd', message: '京东小程序' },
{ name: 'dd', message: '钉钉小程序' },
{ name: 'lark', message: '飞书小程序' },
{ name: 'kwai', message: '快手小程序' },
{ name: 'h5', message: 'H5' },
]
safeExit(main)
async function main() {
const { platform } = await enquirer.prompt<{ platform: string }>({
type: 'select',
name: 'platform',
message: '请选择启动平台',
choices: metas,
})
exec(`pnpm -C example dev:${platform}`)
}

View File

@ -1,21 +1,39 @@
import path from 'node:path'; import { isPromise } from 'node:util/types'
import { createRequire } from 'node:module'; import path from 'node:path'
import { fileURLToPath } from 'node:url'; import { createRequire } from 'node:module'
import { ExecSyncOptions, execSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'
import { ExecSyncOptions, execSync } from 'node:child_process'
import consola from 'consola'
export const __dirname = fileURLToPath(new URL('../', import.meta.url)); export const __dirname = fileURLToPath(new URL('../', import.meta.url))
export const require = createRequire(import.meta.url); export const require = createRequire(import.meta.url)
export const pkgPath = path.resolve(__dirname, 'package.json'); export const pkgPath = path.resolve(__dirname, 'package.json')
export const distPath = path.resolve(__dirname, 'dist'); export const distPath = path.resolve(__dirname, 'dist')
export const resolve = (...paths: string[]) => export const resolve = (...paths: string[]) => path.resolve(__dirname, ...paths)
path.resolve(__dirname, ...paths);
export const exec = (command: string, options: ExecSyncOptions = {}) => export const exec = (command: string, options: ExecSyncOptions = {}) =>
execSync(command, { execSync(command, {
stdio: 'inherit', stdio: 'inherit',
encoding: 'utf-8', encoding: 'utf-8',
...options, ...options,
}); })
export const getPkgJSON = () => require(pkgPath); export const getPkgJSON = () => require(pkgPath)
export function safeExit(run: () => unknown) {
try {
const p = run()
if (isPromise(p)) {
return p.catch(exit)
}
} catch {
exit()
}
}
function exit() {
consola.error('已退出')
process.exit()
}

View File

@ -1,16 +1,15 @@
import { AxiosRequestConfig } from '../core/Axios'; import { AxiosRequestConfig } from '../core/Axios'
import { isPlainObject } from './isTypes'; import { isPlainObject } from './isTypes'
import { buildURL } from './buildURL'; import { buildURL } from './buildURL'
import { combineURL } from './combineURL'; import { combineURL } from './combineURL'
import { dynamicURL } from './dynamicURL'; import { dynamicURL } from './dynamicURL'
export function transformURL(config: AxiosRequestConfig) { export function transformURL(config: AxiosRequestConfig) {
let url = combineURL(config.baseURL, config.url); const fullPath = dynamicURL(
url = dynamicURL( combineURL(config.baseURL, config.url),
url, config.params,
config.params, isPlainObject(config.data) ? config.data : {},
isPlainObject(config.data) ? config.data : {}, )
);
url = buildURL(url, config.params, config.paramsSerializer); return buildURL(fullPath, config.params, config.paramsSerializer)
return url;
} }

View File

@ -1,12 +1,12 @@
import { WITH_DATA_RE } from '../constants/methods'; import { WITH_DATA_RE } from '../constants/methods'
import { isFunction, isString } from '../helpers/isTypes'; import { isFunction, isString } from '../helpers/isTypes'
import { assert } from '../helpers/error'; import { assert } from '../helpers/error'
import { AxiosRequestConfig, AxiosResponse } from '../core/Axios'; import { AxiosRequestConfig, AxiosResponse } from '../core/Axios'
import { Cancel, isCancel, isCancelToken } from './cancel'; import { Cancel, isCancel, isCancelToken } from './cancel'
import { flattenHeaders } from './flattenHeaders'; import { flattenHeaders } from './flattenHeaders'
import { AxiosTransformer, transformData } from './transformData'; import { AxiosTransformer, transformData } from './transformData'
import { request } from './request'; import { request } from './request'
import { AxiosErrorResponse } from './createError'; import { AxiosErrorResponse } from './createError'
/** /**
* *
@ -16,51 +16,51 @@ import { AxiosErrorResponse } from './createError';
* @param config * @param config
*/ */
export function dispatchRequest(config: AxiosRequestConfig) { export function dispatchRequest(config: AxiosRequestConfig) {
throwIfCancellationRequested(config); throwIfCancellationRequested(config)
assert(isFunction(config.adapter), 'adapter 不是一个 function'); assert(isFunction(config.adapter), 'adapter 不是一个 function')
assert(isString(config.url), 'url 不是一个 string'); assert(isString(config.url), 'url 不是一个 string')
assert(isString(config.method), 'method 不是一个 string'); assert(isString(config.method), 'method 不是一个 string')
config.headers = flattenHeaders(config); config.headers = flattenHeaders(config)
// 可以携带 data 的请求方法,转换 data // 可以携带 data 的请求方法,转换 data
// 否则,删除 data // 否则,删除 data
if (WITH_DATA_RE.test(config.method!)) { if (WITH_DATA_RE.test(config.method!)) {
dataTransformer(config, config.transformRequest); dataTransformer(config, config.transformRequest)
} else { } else {
delete config.data; delete config.data
} }
function onSuccess(response: AxiosResponse) { function onSuccess(response: AxiosResponse) {
throwIfCancellationRequested(config); throwIfCancellationRequested(config)
dataTransformer(response, config.transformResponse); dataTransformer(response, config.transformResponse)
return response; return response
} }
function onError(error: Cancel | AxiosErrorResponse) { function onError(error: Cancel | AxiosErrorResponse) {
if (!isCancel(error)) { if (!isCancel(error)) {
throwIfCancellationRequested(config); throwIfCancellationRequested(config)
dataTransformer(error.response, config.transformResponse); dataTransformer(error.response, config.transformResponse)
} }
return Promise.reject(error); return Promise.reject(error)
} }
function dataTransformer<TData = unknown>( function dataTransformer<TData = unknown>(
target: { data?: TData; headers?: AnyObject }, obj: { data?: TData; headers?: AnyObject },
fn?: AxiosTransformer<TData>, fn?: AxiosTransformer<TData>,
) { ) {
target.data = transformData(target.data, target.headers, fn); obj.data = transformData(obj.data, obj.headers, fn)
} }
return request(config).then(onSuccess, onError); return request(config).then(onSuccess, onError)
} }
function throwIfCancellationRequested(config: AxiosRequestConfig) { function throwIfCancellationRequested(config: AxiosRequestConfig) {
const { cancelToken } = config; const { cancelToken } = config
if (isCancelToken(cancelToken)) { if (isCancelToken(cancelToken)) {
cancelToken.throwIfRequested(); cancelToken.throwIfRequested()
} }
} }

View File

@ -1,20 +1,20 @@
import { isFunction, isPlainObject } from '../helpers/isTypes'; import { isFunction, isPlainObject } from '../helpers/isTypes'
import { transformURL } from '../helpers/transformURL'; import { transformURL } from '../helpers/transformURL'
import { import {
AxiosRequestConfig, AxiosRequestConfig,
AxiosResponse, AxiosResponse,
AxiosResponseError, AxiosResponseError,
} from '../core/Axios'; } from '../core/Axios'
import { import {
AxiosAdapterRequestConfig, AxiosAdapterRequestConfig,
AxiosAdapterResponse, AxiosAdapterResponse,
AxiosAdapterResponseError, AxiosAdapterResponseError,
AxiosAdapterPlatformTask, AxiosAdapterPlatformTask,
AxiosAdapterRequestMethod, AxiosAdapterRequestMethod,
} from '../adpater/createAdapter'; } from '../adpater/createAdapter'
import { isCancelToken } from './cancel'; import { isCancelToken } from './cancel'
import { AxiosErrorResponse, createError } from './createError'; import { AxiosErrorResponse, createError } from './createError'
import { generateType } from './generateType'; import { generateType } from './generateType'
/** /**
* *
@ -24,99 +24,99 @@ import { generateType } from './generateType';
* @param config * @param config
*/ */
export function request(config: AxiosRequestConfig) { export function request(config: AxiosRequestConfig) {
return new Promise<AxiosResponse>((resolve, reject) => { return new Promise<AxiosResponse>((resolve, reject) => {
const adapterConfig: AxiosAdapterRequestConfig = { const adapterConfig: AxiosAdapterRequestConfig = {
...(config as AxiosAdapterRequestConfig), ...(config as AxiosAdapterRequestConfig),
type: generateType(config), type: generateType(config),
url: transformURL(config), url: transformURL(config),
method: config.method!.toUpperCase() as AxiosAdapterRequestMethod, method: config.method!.toUpperCase() as AxiosAdapterRequestMethod,
success, success,
fail, fail,
}; }
let adapterTask: AxiosAdapterPlatformTask; let adapterTask: AxiosAdapterPlatformTask
try { try {
adapterTask = config.adapter!(adapterConfig); adapterTask = config.adapter!(adapterConfig)
} catch (err) { } catch (err) {
fail({ fail({
status: 400, status: 400,
statusText: 'Bad Adapter', statusText: 'Bad Adapter',
}); })
console.error(err); console.error(err)
} }
function success(baseResponse: AxiosAdapterResponse): void { function success(baseResponse: AxiosAdapterResponse): void {
const response = baseResponse as AxiosResponse; const response = baseResponse as AxiosResponse
response.status = response.status ?? 200; response.status = response.status ?? 200
response.statusText = response.statusText ?? 'OK'; response.statusText = response.statusText ?? 'OK'
response.headers = response.headers ?? {}; response.headers = response.headers ?? {}
response.config = config; response.config = config
response.request = adapterTask; response.request = adapterTask
const { validateStatus } = config; const { validateStatus } = config
if (!isFunction(validateStatus) || validateStatus(response.status)) { if (!isFunction(validateStatus) || validateStatus(response.status)) {
resolve(response); resolve(response)
} else { } else {
catchError('validate status error', response); catchError('validate status error', response)
} }
} }
function fail(baseResponseError: AxiosAdapterResponseError): void { function fail(baseResponseError: AxiosAdapterResponseError): void {
const responseError = baseResponseError as AxiosResponseError; const responseError = baseResponseError as AxiosResponseError
responseError.isFail = true; responseError.isFail = true
responseError.status = responseError.status ?? 400; responseError.status = responseError.status ?? 400
responseError.statusText = responseError.statusText ?? 'Fail'; responseError.statusText = responseError.statusText ?? 'Fail'
responseError.headers = responseError.headers ?? {}; responseError.headers = responseError.headers ?? {}
responseError.config = config; responseError.config = config
responseError.request = adapterTask; responseError.request = adapterTask
catchError('request fail', responseError); catchError('request fail', responseError)
} }
function catchError( function catchError(
message: string, message: string,
errorResponse: AxiosErrorResponse, errorResponse: AxiosErrorResponse,
): void { ): void {
reject(createError(message, config, errorResponse, adapterTask)); reject(createError(message, config, errorResponse, adapterTask))
} }
if (isPlainObject(adapterTask)) { if (isPlainObject(adapterTask)) {
tryToggleProgressUpdate(adapterConfig, adapterTask.onProgressUpdate); tryToggleProgressUpdate(adapterConfig, adapterTask.onProgressUpdate)
} }
const { cancelToken } = config; const { cancelToken } = config
if (isCancelToken(cancelToken)) { if (isCancelToken(cancelToken)) {
cancelToken.onCancel((reason) => { cancelToken.onCancel((reason) => {
if (isPlainObject(adapterTask)) { if (isPlainObject(adapterTask)) {
tryToggleProgressUpdate(adapterConfig, adapterTask.offProgressUpdate); tryToggleProgressUpdate(adapterConfig, adapterTask.offProgressUpdate)
adapterTask?.abort?.(); adapterTask?.abort?.()
} }
reject(reason); reject(reason)
}); })
} }
}); })
} }
function tryToggleProgressUpdate( function tryToggleProgressUpdate(
adapterConfig: AxiosAdapterRequestConfig, config: AxiosAdapterRequestConfig,
adapterProgress?: (cb: (event: AnyObject) => void) => void, progress?: (cb: (event: AnyObject) => void) => void,
) { ) {
const { onUploadProgress, onDownloadProgress } = adapterConfig; const { type, onUploadProgress, onDownloadProgress } = config
if (isFunction(adapterProgress)) { if (isFunction(progress)) {
switch (adapterConfig.type) { switch (type) {
case 'upload': case 'upload':
if (isFunction(onUploadProgress)) { if (isFunction(onUploadProgress)) {
adapterProgress(onUploadProgress); progress(onUploadProgress)
} }
break; break
case 'download': case 'download':
if (isFunction(onDownloadProgress)) { if (isFunction(onDownloadProgress)) {
adapterProgress(onDownloadProgress); progress(onDownloadProgress)
} }
break; break
} }
} }
} }

View File

@ -1,53 +1,53 @@
import { describe, test, expect, vi } from 'vitest'; import { describe, test, expect, vi } from 'vitest'
import { asyncNext, mockAdapter, testEachMethods } from 'scripts/test.utils'; import { asyncNext, mockAdapter } from 'scripts/test.utils'
import { import {
PLAIN_METHODS, PLAIN_METHODS,
WITH_DATA_METHODS, WITH_DATA_METHODS,
WITH_PARAMS_METHODS, WITH_PARAMS_METHODS,
} from '@/constants/methods'; } from '@/constants/methods'
import { dispatchRequest } from '@/request/dispatchRequest'; import { dispatchRequest } from '@/request/dispatchRequest'
import axios from '@/axios'; import axios from '@/axios'
import _defaults from '@/defaults'; import _defaults from '@/defaults'
describe('src/request/dispatchRequest.ts', () => { describe('src/request/dispatchRequest.ts', () => {
const defaults = { const defaults = {
..._defaults, ..._defaults,
adapter: mockAdapter(), adapter: mockAdapter(),
baseURL: 'http://api.com', baseURL: 'http://api.com',
method: 'get' as const, method: 'get' as const,
headers: {}, headers: {},
}; }
test('应该抛出异常', () => { test('应该抛出异常', () => {
expect(() => dispatchRequest({})).toThrowErrorMatchingInlineSnapshot( expect(() => dispatchRequest({})).toThrowErrorMatchingInlineSnapshot(
'"[axios-miniprogram]: adapter 不是一个 function"', '"[axios-miniprogram]: adapter 不是一个 function"',
); )
expect(() => expect(() =>
dispatchRequest({ adapter: mockAdapter() }), dispatchRequest({ adapter: mockAdapter() }),
).toThrowErrorMatchingInlineSnapshot( ).toThrowErrorMatchingInlineSnapshot(
'"[axios-miniprogram]: url 不是一个 string"', '"[axios-miniprogram]: url 不是一个 string"',
); )
expect(() => expect(() =>
dispatchRequest({ adapter: mockAdapter(), url: '/' }), dispatchRequest({ adapter: mockAdapter(), url: '/' }),
).toThrowErrorMatchingInlineSnapshot( ).toThrowErrorMatchingInlineSnapshot(
'"[axios-miniprogram]: method 不是一个 string"', '"[axios-miniprogram]: method 不是一个 string"',
); )
expect(() => expect(() =>
dispatchRequest({ adapter: mockAdapter(), url: '/', method: 'get' }), dispatchRequest({ adapter: mockAdapter(), url: '/', method: 'get' }),
).not.toThrowError(); ).not.toThrowError()
}); })
test('坏的适配器应该抛出异常', () => { test('坏的适配器应该抛出异常', () => {
expect( expect(
dispatchRequest({ dispatchRequest({
adapter: () => { adapter: () => {
throw 'bad adapter'; throw 'bad adapter'
}, },
url: '/', url: '/',
method: 'get', method: 'get',
}).catch((e) => ({ ...e })), }).catch((e) => ({ ...e })),
).resolves.toMatchInlineSnapshot(` ).resolves.toMatchInlineSnapshot(`
{ {
"config": { "config": {
"adapter": [Function], "adapter": [Function],
@ -71,113 +71,113 @@ describe('src/request/dispatchRequest.ts', () => {
"statusText": "Bad Adapter", "statusText": "Bad Adapter",
}, },
} }
`); `)
}); })
test('应该支持拉平请求头', () => { test('应该支持拉平请求头', () => {
const c = { const c = {
...defaults, ...defaults,
url: 'test', url: 'test',
headers: { headers: {
common: { common: {
h1: 1, h1: 1,
}, },
get: { get: {
h2: 2, h2: 2,
}, },
h3: 3, h3: 3,
}, },
}; }
dispatchRequest(c); dispatchRequest(c)
expect(c.headers).toEqual({ expect(c.headers).toEqual({
h1: 1, h1: 1,
h2: 2, h2: 2,
h3: 3, h3: 3,
}); })
}); })
test.each(WITH_DATA_METHODS)('%s 方法应该支持转换请求数据', (k) => { test.each(WITH_DATA_METHODS)('%s 方法应该支持转换请求数据', (k) => {
const c = { const c = {
...defaults, ...defaults,
url: 'test', url: 'test',
method: k, method: k,
data: {}, data: {},
transformRequest: () => ({ id: 1 }), transformRequest: () => ({ id: 1 }),
}; }
dispatchRequest(c); dispatchRequest(c)
expect(c.data).toEqual({ id: 1 }); expect(c.data).toEqual({ id: 1 })
}); })
test('不能带数据的请求方法应该删除数据', () => { test('不能带数据的请求方法应该删除数据', () => {
const c = { const c = {
...defaults, ...defaults,
url: 'test', url: 'test',
data: {}, data: {},
transformRequest: () => ({ id: 1 }), transformRequest: () => ({ id: 1 }),
}; }
[...PLAIN_METHODS, ...WITH_PARAMS_METHODS].forEach((k) => { ;[...PLAIN_METHODS, ...WITH_PARAMS_METHODS].forEach((k) => {
const s = { ...c, method: k }; const s = { ...c, method: k }
dispatchRequest(s); dispatchRequest(s)
expect(s.data).toBeUndefined(); expect(s.data).toBeUndefined()
}); })
}); })
test('应该支持转换响应数据', async () => { test('应该支持转换响应数据', async () => {
const c = { const c = {
...defaults, ...defaults,
url: 'test', url: 'test',
transformResponse: () => ({ result: 1 }), transformResponse: () => ({ result: 1 }),
}; }
const r = await dispatchRequest(c); const r = await dispatchRequest(c)
expect(r.data).toEqual({ result: 1 }); expect(r.data).toEqual({ result: 1 })
}); })
test('请求发送前取消请求应该抛出异常', async () => { test('请求发送前取消请求应该抛出异常', async () => {
const cb = vi.fn(); const cb = vi.fn()
const { cancel, token } = axios.CancelToken.source(); const { cancel, token } = axios.CancelToken.source()
const c = { const c = {
...defaults, ...defaults,
url: 'test', url: 'test',
cancelToken: token, cancelToken: token,
}; }
cancel(); cancel()
try { try {
dispatchRequest(c); dispatchRequest(c)
} catch (err) { } catch (err) {
cb(err); cb(err)
} }
expect(cb).toBeCalled(); expect(cb).toBeCalled()
expect(axios.isCancel(cb.mock.calls[0][0])).toBeTruthy(); expect(axios.isCancel(cb.mock.calls[0][0])).toBeTruthy()
}); })
test('请求发送后取消请求应该抛出异常', async () => { test('请求发送后取消请求应该抛出异常', async () => {
const cb = vi.fn(); const cb = vi.fn()
const { cancel, token } = axios.CancelToken.source(); const { cancel, token } = axios.CancelToken.source()
const c = { const c = {
...defaults, ...defaults,
url: 'test', url: 'test',
cancelToken: token, cancelToken: token,
}; }
const p = dispatchRequest(c).catch(cb); const p = dispatchRequest(c).catch(cb)
await asyncNext(); await asyncNext()
expect(cb).not.toBeCalled(); expect(cb).not.toBeCalled()
cancel(); cancel()
await p; await p
expect(cb).toBeCalled(); expect(cb).toBeCalled()
expect(axios.isCancel(cb.mock.calls[0][0])).toBeTruthy(); expect(axios.isCancel(cb.mock.calls[0][0])).toBeTruthy()
}); })
}); })