docs: 初始化示例项目

pull/49/head
zjx0905 2023-05-05 10:59:37 +08:00
parent 74856f7fde
commit 359b09172e
36 changed files with 8834 additions and 1159 deletions

View File

@ -1,15 +1,16 @@
{
"env": {
"es2022": true,
"node": true
},
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"root": true,
"rules": {
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-non-null-assertion": 0,
"@typescript-eslint/ban-ts-comment": 0
}
"root": true,
"env": {
"es2022": true,
"node": true
},
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"rules": {
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-non-null-assertion": 0,
"@typescript-eslint/ban-ts-comment": 0,
"no-mixed-spaces-and-tabs": 0
}
}

View File

@ -44,7 +44,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
name: Release ${{ github.ref }}
name: Release ${{ github.ref_name }}
prerelease: ${{ steps.prerelease.outputs.result }}
body_path: 'RELEASELOG.md'
files: 'dist/**.zip'

View File

@ -1 +1,2 @@
CHANGELOG.md
dist/

View File

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

11
example/.babelrc Normal file
View File

@ -0,0 +1,11 @@
{
"presets": [
[
"taro",
{
"framework": "vue3",
"ts": true
}
]
]
}

11
example/.eslintrc Normal file
View File

@ -0,0 +1,11 @@
{
"extends": ["plugin:vue/vue3-essential"],
"parser": "vue-eslint-parser",
"parserOptions": {
"parser": "@typescript-eslint/parser",
"sourceType": "module"
},
"rules": {
"vue/multi-word-component-names": "off"
}
}

8
example/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
dist/
deploy_versions/
.temp/
.rn_temp/
node_modules/
.DS_Store
.swc
config/**.js

2
example/.prettierignore Normal file
View File

@ -0,0 +1,2 @@
dist/
config/**.js

View File

@ -0,0 +1,8 @@
export default {
env: {
NODE_ENV: '"development"',
},
defineConstants: {},
mini: {},
h5: {},
};

View File

@ -0,0 +1,79 @@
import dev from './dev';
import prod from './prod';
export default (merge) => {
if (process.env.NODE_ENV === 'development') {
return merge({}, config, dev);
}
return merge({}, config, prod);
};
const config = {
projectName: 'axios-miniprogram',
date: '2023-5-5',
designWidth: 750,
deviceRatio: {
640: 2.34 / 2,
750: 1,
828: 1.81 / 2,
},
sourceRoot: 'src',
outputRoot: 'dist',
plugins: [],
defineConstants: {},
copy: {
patterns: [],
options: {},
},
framework: 'vue3',
compiler: 'webpack5',
cache: {
enable: false, // Webpack 持久化缓存配置建议开启。默认配置请参考https://docs.taro.zone/docs/config-detail#cache
},
mini: {
postcss: {
pxtransform: {
enable: true,
config: {},
},
url: {
enable: true,
config: {
limit: 1024, // 设定转换尺寸上限
},
},
cssModules: {
enable: false, // 默认为 false如需使用 css modules 功能,则设为 true
config: {
namingPattern: 'module', // 转换模式,取值为 global/module
generateScopedName: '[name]__[local]___[hash:base64:5]',
},
},
},
},
h5: {
publicPath: '/',
staticDirectory: 'static',
postcss: {
autoprefixer: {
enable: true,
config: {},
},
cssModules: {
enable: false, // 默认为 false如需使用 css modules 功能,则设为 true
config: {
namingPattern: 'module', // 转换模式,取值为 global/module
generateScopedName: '[name]__[local]___[hash:base64:5]',
},
},
},
},
rn: {
appName: 'taroDemo',
postcss: {
cssModules: {
enable: false, // 默认为 false如需使用 css modules 功能,则设为 true
},
},
},
};

View File

@ -0,0 +1,35 @@
export default {
env: {
NODE_ENV: '"production"',
},
defineConstants: {},
mini: {},
h5: {
/**
* WebpackChain
* @docs https://github.com/neutrinojs/webpack-chain
*/
// webpackChain (chain) {
// /**
// * 如果 h5 端编译后体积过大,可以使用 webpack-bundle-analyzer 插件对打包体积进行分析。
// * @docs https://github.com/webpack-contrib/webpack-bundle-analyzer
// */
// chain.plugin('analyzer')
// .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin, [])
// /**
// * 如果 h5 端首屏加载时间过长,可以使用 prerender-spa-plugin 插件预加载首页。
// * @docs https://github.com/chrisvfritz/prerender-spa-plugin
// */
// const path = require('path')
// const Prerender = require('prerender-spa-plugin')
// const staticDir = path.join(__dirname, '..', 'dist')
// chain
// .plugin('prerender')
// .use(new Prerender({
// staticDir,
// routes: [ '/pages/index/index' ],
// postProcess: (context) => ({ ...context, outputPath: path.join(staticDir, 'index.html') })
// }))
// }
},
};

31
example/global.d.ts vendored Normal file
View File

@ -0,0 +1,31 @@
/// <reference types="@tarojs/taro" />
declare module '*.png';
declare module '*.gif';
declare module '*.jpg';
declare module '*.jpeg';
declare module '*.svg';
declare module '*.css';
declare module '*.less';
declare module '*.scss';
declare module '*.sass';
declare module '*.styl';
declare namespace NodeJS {
interface ProcessEnv {
TARO_ENV:
| 'weapp'
| 'swan'
| 'alipay'
| 'h5'
| 'rn'
| 'tt'
| 'quickapp'
| 'qq'
| 'jd';
}
}
declare module '@tarojs/components' {
export * from '@tarojs/components/types/index.vue3';
}

58
example/package.json Normal file
View File

@ -0,0 +1,58 @@
{
"name": "example",
"private": true,
"scripts": {
"build:weapp": "taro build --type weapp",
"build:swan": "taro build --type swan",
"build:alipay": "taro build --type alipay",
"build:tt": "taro build --type tt",
"build:h5": "taro build --type h5",
"build:rn": "taro build --type rn",
"build:qq": "taro build --type qq",
"build:jd": "taro build --type jd",
"build:quickapp": "taro build --type quickapp",
"dev:weapp": "npm run build:weapp -- --watch",
"dev:swan": "npm run build:swan -- --watch",
"dev:alipay": "npm run build:alipay -- --watch",
"dev:tt": "npm run build:tt -- --watch",
"dev:h5": "npm run build:h5 -- --watch",
"dev:rn": "npm run build:rn -- --watch",
"dev:qq": "npm run build:qq -- --watch",
"dev:jd": "npm run build:jd -- --watch",
"dev:quickapp": "npm run build:quickapp -- --watch"
},
"dependencies": {
"@babel/runtime": "^7.7.7",
"@tarojs/components": "3.6.6",
"@tarojs/helper": "3.6.6",
"@tarojs/plugin-framework-vue3": "3.6.6",
"@tarojs/plugin-platform-alipay": "3.6.6",
"@tarojs/plugin-platform-h5": "3.6.6",
"@tarojs/plugin-platform-jd": "3.6.6",
"@tarojs/plugin-platform-qq": "3.6.6",
"@tarojs/plugin-platform-swan": "3.6.6",
"@tarojs/plugin-platform-tt": "3.6.6",
"@tarojs/plugin-platform-weapp": "3.6.6",
"@tarojs/runtime": "3.6.6",
"@tarojs/shared": "3.6.6",
"@tarojs/taro": "3.6.6",
"vue": "^3.0.0"
},
"devDependencies": {
"@babel/core": "^7.8.0",
"@tarojs/cli": "3.6.6",
"@tarojs/webpack5-runner": "3.6.6",
"@types/webpack-env": "^1.13.6",
"@vue/babel-plugin-jsx": "^1.0.6",
"@vue/compiler-sfc": "^3.0.0",
"babel-preset-taro": "3.6.6",
"css-loader": "3.4.2",
"eslint-plugin-vue": "^8.0.0",
"postcss": "^8.4.18",
"style-loader": "1.3.0",
"stylelint": "^14.4.0",
"vue-eslint-parser": "^9.2.0",
"vue-loader": "^17.0.0",
"webpack": "5.78.0"
}
}

View File

@ -0,0 +1,14 @@
{
"miniprogramRoot": "./dist",
"projectname": "axios-miniprogram",
"appid": "wx48e277051b32f95b",
"setting": {
"urlCheck": true,
"es6": false,
"enhance": false,
"compileHotReLoad": false,
"postcss": false,
"minified": false
},
"compileType": "miniprogram"
}

9
example/project.tt.json Normal file
View File

@ -0,0 +1,9 @@
{
"miniprogramRoot": "./",
"projectname": "axios-miniprogram",
"appid": "testAppId",
"setting": {
"es6": false,
"minified": false
}
}

View File

@ -0,0 +1,9 @@
export default defineAppConfig({
pages: ['pages/index/index'],
window: {
backgroundTextStyle: 'light',
navigationBarBackgroundColor: '#fff',
navigationBarTitleText: 'axios-miniprogram',
navigationBarTextStyle: 'black',
},
});

0
example/src/app.css Normal file
View File

4
example/src/app.ts Normal file
View File

@ -0,0 +1,4 @@
import { createApp } from 'vue';
import './app.css';
export default createApp({});

17
example/src/index.html Normal file
View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta content="width=device-width,initial-scale=1,user-scalable=no" name="viewport">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-touch-fullscreen" content="yes">
<meta name="format-detection" content="telephone=no,address=no">
<meta name="apple-mobile-web-app-status-bar-style" content="white">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" >
<title>example</title>
<script><%= htmlWebpackPlugin.options.script %></script>
</head>
<body>
<div id="app"></div>
</body>
</html>

View File

@ -0,0 +1,3 @@
export default definePageConfig({
navigationBarTitleText: '首页',
});

View File

View File

@ -0,0 +1,16 @@
<template>
<view class="index">
<text>{{ msg }}</text>
</view>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import './index.css'
const msg = ref('Hello world')
defineExpose({
msg,
})
</script>

18
example/tsconfig.json Normal file
View File

@ -0,0 +1,18 @@
{
"extends": ["../tsconfig.json"],
"compilerOptions": {
"removeComments": false,
"preserveConstEnums": true,
"experimentalDecorators": true,
"noImplicitAny": false,
"outDir": "lib",
"noUnusedLocals": true,
"noUnusedParameters": true,
"strictNullChecks": true,
"sourceMap": true,
"jsx": "preserve",
"allowJs": true,
"resolveJsonModule": true
},
"include": ["./src", "global.d.ts"]
}

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -1,29 +1,36 @@
import enquirer from 'enquirer'
import { exec } from './utils'
import { safeExit } from './utils'
import enquirer from 'enquirer';
import { exec, resolve } 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' },
]
const configPath = resolve('example/config');
const configTempPath = resolve('example/config/temp');
safeExit(main)
safeExit(main);
async function main() {
const { platform } = await enquirer.prompt<{ platform: string }>({
type: 'select',
name: 'platform',
message: '请选择启动平台',
choices: metas,
})
const { platform } = await enquirer.prompt<{ platform: string }>({
type: 'select',
name: 'platform',
message: '请选择启动平台',
choices: metas(),
});
exec(`pnpm -C example dev:${platform}`)
exec(`tsc ${configTempPath}/**.ts --outDir ${configPath}`);
exec(`pnpm -C example dev:${platform}`);
}
function metas() {
return [
{ 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' },
];
}

View File

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

View File

@ -1,561 +1,561 @@
import {
PLAIN_METHODS,
WITH_DATA_METHODS,
WITH_PARAMS_METHODS,
} from '../constants/methods'
import { isString } from '../helpers/isTypes'
import { dispatchRequest } from '../request/dispatchRequest'
import { CancelToken } from '../request/cancel'
import { AxiosTransformer } from '../request/transformData'
import { deepMerge } from '../helpers/deepMerge'
PLAIN_METHODS,
WITH_DATA_METHODS,
WITH_PARAMS_METHODS,
} from '../constants/methods';
import { isString } from '../helpers/isTypes';
import { dispatchRequest } from '../request/dispatchRequest';
import { CancelToken } from '../request/cancel';
import { AxiosTransformer } from '../request/transformData';
import { deepMerge } from '../helpers/deepMerge';
import {
AxiosAdapter,
AxiosAdapterRequestMethod,
AxiosAdapterPlatformTask,
AxiosAdapterRequestConfig,
AxiosAdapterResponseData,
} from '../adpater/createAdapter'
AxiosAdapter,
AxiosAdapterRequestMethod,
AxiosAdapterPlatformTask,
AxiosAdapterRequestConfig,
AxiosAdapterResponseData,
} from '../adpater/createAdapter';
import InterceptorManager, {
Interceptor,
InterceptorExecutor,
} from './InterceptorManager'
Interceptor,
InterceptorExecutor,
} from './InterceptorManager';
import MiddlewareManager, {
MiddlewareCallback,
MiddlewareContext,
} from './MiddlewareManager'
import { mergeConfig } from './mergeConfig'
MiddlewareCallback,
MiddlewareContext,
} from './MiddlewareManager';
import { mergeConfig } from './mergeConfig';
/**
*
*/
export type AxiosRequestMethod =
| AxiosAdapterRequestMethod
| 'options'
| 'get'
| 'head'
| 'post'
| 'put'
| 'patch'
| 'delete'
| 'trace'
| 'connect'
| AxiosAdapterRequestMethod
| 'options'
| 'get'
| 'head'
| 'post'
| 'put'
| 'patch'
| 'delete'
| 'trace'
| 'connect';
/**
*
*/
export interface AxiosRequestHeaders extends AnyObject {
/**
*
*/
common?: AnyObject
/**
* options
*/
options?: AnyObject
/**
* get
*/
get?: AnyObject
/**
* head
*/
head?: AnyObject
/**
* post
*/
post?: AnyObject
/**
* put
*/
put?: AnyObject
/**
* delete
*/
delete?: AnyObject
/**
* trace
*/
trace?: AnyObject
/**
* connect
*/
connect?: AnyObject
/**
*
*/
common?: AnyObject;
/**
* options
*/
options?: AnyObject;
/**
* get
*/
get?: AnyObject;
/**
* head
*/
head?: AnyObject;
/**
* post
*/
post?: AnyObject;
/**
* put
*/
put?: AnyObject;
/**
* delete
*/
delete?: AnyObject;
/**
* trace
*/
trace?: AnyObject;
/**
* connect
*/
connect?: AnyObject;
}
/**
*
*/
export interface AxiosRequestFormData extends AnyObject {
/**
*
*/
name: string
/**
*
*/
filePath: string
/**
*
*/
name: string;
/**
*
*/
filePath: string;
}
/**
*
*/
export type AxiosRequestData =
| string
| AnyObject
| ArrayBuffer
| AxiosRequestFormData
| string
| AnyObject
| ArrayBuffer
| AxiosRequestFormData;
/**
*
*/
export type AxiosResponseData = number | AxiosAdapterResponseData
export type AxiosResponseData = number | AxiosAdapterResponseData;
/**
*
*/
export interface AxiosProgressEvent extends AnyObject {
/**
*
*/
progress: number
/**
*
*/
progress: number;
}
/**
*
*/
export interface AxiosDownloadProgressEvent extends AxiosProgressEvent {
/**
* Bytes
*/
totalBytesWritten: number
/**
* Bytes
*/
totalBytesExpectedToWrite: number
/**
* Bytes
*/
totalBytesWritten: number;
/**
* Bytes
*/
totalBytesExpectedToWrite: number;
}
/**
*
*/
export interface AxiosDownloadProgressCallback {
(event: AxiosDownloadProgressEvent): void
(event: AxiosDownloadProgressEvent): void;
}
/**
*
*/
export interface AxiosUploadProgressEvent extends AxiosProgressEvent {
/**
* Bytes
*/
totalBytesSent: number
/**
* Bytes
*/
totalBytesExpectedToSend: number
/**
* Bytes
*/
totalBytesSent: number;
/**
* Bytes
*/
totalBytesExpectedToSend: number;
}
/**
*
*/
export interface AxiosUploadProgressCallback {
(event: AxiosUploadProgressEvent): void
(event: AxiosUploadProgressEvent): void;
}
/**
*
*/
export interface AxiosRequestConfig
extends Partial<
Omit<AxiosAdapterRequestConfig, 'type' | 'success' | 'fail'>
> {
/**
*
*/
adapter?: AxiosAdapter
/**
*
*/
baseURL?: string
/**
* URL
*/
url?: string
/**
*
*/
params?: AnyObject
/**
*
*/
data?: AxiosRequestData
/**
*
*/
headers?: AxiosRequestHeaders
/**
*
*/
method?: AxiosRequestMethod
/**
*
*/
cancelToken?: CancelToken
/**
*
*/
download?: boolean
/**
*
*/
upload?: boolean
/**
*
*/
paramsSerializer?: (params?: AnyObject) => string
/**
*
*/
validateStatus?: (status: number) => boolean
/**
*
*/
transformRequest?: AxiosTransformer<AxiosRequestData>
/**
*
*/
transformResponse?: AxiosTransformer<AxiosResponseData>
/**
*
*/
errorHandler?: (error: unknown) => Promise<AxiosResponse>
/**
*
*/
onDownloadProgress?: AxiosUploadProgressCallback
/**
*
*/
onUploadProgress?: AxiosUploadProgressCallback
extends Partial<
Omit<AxiosAdapterRequestConfig, 'type' | 'success' | 'fail'>
> {
/**
*
*/
adapter?: AxiosAdapter;
/**
*
*/
baseURL?: string;
/**
* URL
*/
url?: string;
/**
*
*/
params?: AnyObject;
/**
*
*/
data?: AxiosRequestData;
/**
*
*/
headers?: AxiosRequestHeaders;
/**
*
*/
method?: AxiosRequestMethod;
/**
*
*/
cancelToken?: CancelToken;
/**
*
*/
download?: boolean;
/**
*
*/
upload?: boolean;
/**
*
*/
paramsSerializer?: (params?: AnyObject) => string;
/**
*
*/
validateStatus?: (status: number) => boolean;
/**
*
*/
transformRequest?: AxiosTransformer<AxiosRequestData>;
/**
*
*/
transformResponse?: AxiosTransformer<AxiosResponseData>;
/**
*
*/
errorHandler?: (error: unknown) => Promise<AxiosResponse>;
/**
*
*/
onDownloadProgress?: AxiosUploadProgressCallback;
/**
*
*/
onUploadProgress?: AxiosUploadProgressCallback;
}
/**
*
*/
export interface AxiosResponse<
TData extends AxiosResponseData = AxiosResponseData,
TData extends AxiosResponseData = AxiosResponseData,
> extends AnyObject {
/**
*
*/
status: number
/**
*
*/
statusText: string
/**
*
*/
headers: AnyObject
/**
*
*/
data: TData
/**
*
*/
config: AxiosRequestConfig
/**
*
*/
request?: AxiosAdapterPlatformTask
/**
*
*/
status: number;
/**
*
*/
statusText: string;
/**
*
*/
headers: AnyObject;
/**
*
*/
data: TData;
/**
*
*/
config: AxiosRequestConfig;
/**
*
*/
request?: AxiosAdapterPlatformTask;
}
/**
*
*/
export interface AxiosResponseError extends AnyObject {
/**
*
*/
status: number
/**
*
*/
statusText: string
/**
*
*/
headers: AnyObject
/**
*
*/
data: AnyObject
/**
*
*/
isFail: true
/**
*
*/
config: AxiosRequestConfig
/**
*
*/
request?: AxiosAdapterPlatformTask
/**
*
*/
status: number;
/**
*
*/
statusText: string;
/**
*
*/
headers: AnyObject;
/**
*
*/
data: AnyObject;
/**
*
*/
isFail: true;
/**
*
*/
config: AxiosRequestConfig;
/**
*
*/
request?: AxiosAdapterPlatformTask;
}
export interface AxiosRequest {
<TData extends AxiosResponseData>(config: AxiosRequestConfig): Promise<
AxiosResponse<TData>
>
<TData extends AxiosResponseData>(
url: string,
config?: AxiosRequestConfig,
): Promise<AxiosResponse<TData>>
<TData extends AxiosResponseData>(config: AxiosRequestConfig): Promise<
AxiosResponse<TData>
>;
<TData extends AxiosResponseData>(
url: string,
config?: AxiosRequestConfig,
): Promise<AxiosResponse<TData>>;
}
/**
*
*/
export type AxiosRequestMethodFn = <TData extends AxiosResponseData>(
url: string,
config?: AxiosRequestConfig,
) => Promise<AxiosResponse<TData>>
url: string,
config?: AxiosRequestConfig,
) => Promise<AxiosResponse<TData>>;
/**
*
*/
export type AxiosRequestMethodFnWithParams = <TData extends AxiosResponseData>(
url: string,
params?: AnyObject,
config?: AxiosRequestConfig,
) => Promise<AxiosResponse<TData>>
url: string,
params?: AnyObject,
config?: AxiosRequestConfig,
) => Promise<AxiosResponse<TData>>;
/**
*
*/
export type AxiosRequestMethodFnWithData = <TData extends AxiosResponseData>(
url: string,
data?: AxiosRequestData,
config?: AxiosRequestConfig,
) => Promise<AxiosResponse<TData>>
url: string,
data?: AxiosRequestData,
config?: AxiosRequestConfig,
) => Promise<AxiosResponse<TData>>;
export interface AxiosDomainRequestHandler {
(config: AxiosRequestConfig): Promise<AxiosResponse>
(config: AxiosRequestConfig): Promise<AxiosResponse>;
}
/**
* Axios
*/
export interface AxiosConstructor {
new (config: AxiosRequestConfig): Axios
new (config: AxiosRequestConfig): Axios;
}
export default class Axios {
/**
*
*/
#parent?: Axios
/**
*
*/
#parent?: Axios;
/**
*
*/
defaults: AxiosRequestConfig
/**
*
*/
defaults: AxiosRequestConfig;
/**
*
*/
interceptors = {
/**
*
*/
request: new InterceptorManager<AxiosRequestConfig>(),
/**
*
*/
response: new InterceptorManager<AxiosResponse>(),
}
/**
*
*/
interceptors = {
/**
*
*/
request: new InterceptorManager<AxiosRequestConfig>(),
/**
*
*/
response: new InterceptorManager<AxiosResponse>(),
};
/**
*
*/
#middleware = new MiddlewareManager()
/**
*
*/
#middleware = new MiddlewareManager();
/**
* options
*/
options!: AxiosRequestMethodFn
/**
* options
*/
options!: AxiosRequestMethodFn;
/**
* get
*/
get!: AxiosRequestMethodFnWithParams
/**
* get
*/
get!: AxiosRequestMethodFnWithParams;
/**
* head
*/
head!: AxiosRequestMethodFnWithParams
/**
* head
*/
head!: AxiosRequestMethodFnWithParams;
/**
* post
*/
post!: AxiosRequestMethodFnWithData
/**
* post
*/
post!: AxiosRequestMethodFnWithData;
/**
* put
*/
put!: AxiosRequestMethodFnWithData
/**
* put
*/
put!: AxiosRequestMethodFnWithData;
/**
* patch
*/
patch!: AxiosRequestMethodFnWithData
/**
* patch
*/
patch!: AxiosRequestMethodFnWithData;
/**
* delete
*/
delete!: AxiosRequestMethodFnWithParams
/**
* delete
*/
delete!: AxiosRequestMethodFnWithParams;
/**
* trace
*/
trace!: AxiosRequestMethodFn
/**
* trace
*/
trace!: AxiosRequestMethodFn;
/**
* connect
*/
connect!: AxiosRequestMethodFn
/**
* connect
*/
connect!: AxiosRequestMethodFn;
/**
*
* @param config
* @param parent
*/
constructor(config: AxiosRequestConfig, parent?: Axios) {
this.defaults = config
this.#parent = parent
}
/**
*
* @param config
* @param parent
*/
constructor(config: AxiosRequestConfig, parent?: Axios) {
this.defaults = config;
this.#parent = parent;
}
/**
*
*/
request: AxiosRequest = (
urlOrConfig: string | AxiosRequestConfig,
config: AxiosRequestConfig = {},
) => {
if (isString(urlOrConfig)) {
config.url = urlOrConfig
} else {
config = urlOrConfig
}
config = mergeConfig(this.defaults, config)
config.method = (config.method?.toLowerCase() ??
'get') as AxiosRequestMethod
/**
*
*/
request: AxiosRequest = (
urlOrConfig: string | AxiosRequestConfig,
config: AxiosRequestConfig = {},
) => {
if (isString(urlOrConfig)) {
config.url = urlOrConfig;
} else {
config = urlOrConfig;
}
config = mergeConfig(this.defaults, config);
config.method = (config.method?.toLowerCase() ??
'get') as AxiosRequestMethod;
const requestHandler = {
resolved: this.#handleRequest,
}
const errorHandler = {
rejected: config.errorHandler,
}
const chain: (
| Partial<Interceptor<AxiosRequestConfig>>
| Partial<Interceptor<AxiosResponse>>
)[] = []
const requestHandler = {
resolved: this.#handleRequest,
};
const errorHandler = {
rejected: config.errorHandler,
};
const chain: (
| Partial<Interceptor<AxiosRequestConfig>>
| Partial<Interceptor<AxiosResponse>>
)[] = [];
this.#eachRequestInterceptors((requestInterceptor) => {
chain.unshift(requestInterceptor)
})
chain.push(requestHandler)
this.#eachResponseInterceptors((responseInterceptor) => {
chain.push(responseInterceptor)
})
chain.push(errorHandler)
this.#eachRequestInterceptors((requestInterceptor) => {
chain.unshift(requestInterceptor);
});
chain.push(requestHandler);
this.#eachResponseInterceptors((responseInterceptor) => {
chain.push(responseInterceptor);
});
chain.push(errorHandler);
return chain.reduce(
(next, { resolved, rejected }) =>
next.then(
// @ts-ignore
resolved,
rejected,
),
Promise.resolve(config),
) as Promise<AxiosResponse>
}
return chain.reduce(
(next, { resolved, rejected }) =>
next.then(
// @ts-ignore
resolved,
rejected,
),
Promise.resolve(config),
) as Promise<AxiosResponse>;
};
#eachRequestInterceptors(executor: InterceptorExecutor<AxiosRequestConfig>) {
this.interceptors.request.forEach(executor)
if (this.#parent) {
this.#parent.#eachRequestInterceptors(executor)
}
}
#eachRequestInterceptors(executor: InterceptorExecutor<AxiosRequestConfig>) {
this.interceptors.request.forEach(executor);
if (this.#parent) {
this.#parent.#eachRequestInterceptors(executor);
}
}
#eachResponseInterceptors(executor: InterceptorExecutor<AxiosResponse>) {
this.interceptors.response.forEach(executor)
if (this.#parent) {
this.#parent.#eachResponseInterceptors(executor)
}
}
#eachResponseInterceptors(executor: InterceptorExecutor<AxiosResponse>) {
this.interceptors.response.forEach(executor);
if (this.#parent) {
this.#parent.#eachResponseInterceptors(executor);
}
}
/**
*
*
* @param middleware
*/
use = (middleware: MiddlewareCallback) => {
this.#middleware.use(middleware)
return this
}
/**
*
*
* @param middleware
*/
use = (middleware: MiddlewareCallback) => {
this.#middleware.use(middleware);
return this;
};
#handleRequest = async (config: AxiosRequestConfig) => {
const ctx = this.#middleware.createContext(config)
await this.#run(ctx, this.#handleResponse)
return ctx.res as AxiosResponse
}
#handleRequest = async (config: AxiosRequestConfig) => {
const ctx = this.#middleware.createContext(config);
await this.#run(ctx, this.#handleResponse);
return ctx.res as AxiosResponse;
};
#handleResponse = async (ctx: MiddlewareContext) => {
ctx.res = await dispatchRequest(ctx.req)
}
#handleResponse = async (ctx: MiddlewareContext) => {
ctx.res = await dispatchRequest(ctx.req);
};
#run = (
ctx: MiddlewareContext,
respond: MiddlewareCallback,
): Promise<void> => {
if (!this.#parent) {
return this.#middleware.run(ctx, respond)
}
return this.#middleware.enhanceRun(this.#parent.#run)(ctx, respond)
}
#run = (
ctx: MiddlewareContext,
respond: MiddlewareCallback,
): Promise<void> => {
if (!this.#parent) {
return this.#middleware.run(ctx, respond);
}
return this.#middleware.enhanceRun(this.#parent.#run)(ctx, respond);
};
}
for (const method of PLAIN_METHODS) {
Axios.prototype[method] = function processRequestMethod(url, config = {}) {
config.method = method
return this.request(url, config)
}
Axios.prototype[method] = function processRequestMethod(url, config = {}) {
config.method = method;
return this.request(url, config);
};
}
for (const method of WITH_PARAMS_METHODS) {
Axios.prototype[method] = function processRequestMethodWithParams(
url,
params = {},
config = {},
) {
config.method = method
config.params = deepMerge(params, config.params ?? {})
return this.request(url, config)
}
Axios.prototype[method] = function processRequestMethodWithParams(
url,
params,
config = {},
) {
config.method = method;
config.params = deepMerge(params, config.params);
return this.request(url, config);
};
}
for (const method of WITH_DATA_METHODS) {
Axios.prototype[method] = function processRequestMethodWithData(
url,
data,
config = {},
) {
config.method = method
config.data = data
return this.request(url, config)
}
Axios.prototype[method] = function processRequestMethodWithData(
url,
data,
config = {},
) {
config.method = method;
config.data = data;
return this.request(url, config);
};
}

View File

@ -1,85 +1,85 @@
import { assert } from '../helpers/error'
import { isFunction } from '../helpers/isTypes'
import { AxiosRequestConfig, AxiosResponse } from './Axios'
import { assert } from '../helpers/error';
import { isFunction } from '../helpers/isTypes';
import { AxiosRequestConfig, AxiosResponse } from './Axios';
export interface MiddlewareNext {
(): Promise<void>
(): Promise<void>;
}
/**
*
*/
export interface MiddlewareContext {
/**
*
*
*
*/
req: AxiosRequestConfig
/**
*
*/
res: null | AxiosResponse
/**
*
*
*
*/
req: AxiosRequestConfig;
/**
*
*/
res: null | AxiosResponse;
}
/**
*
*/
export interface MiddlewareCallback {
(ctx: MiddlewareContext, next: MiddlewareNext): Promise<void>
(ctx: MiddlewareContext, next: MiddlewareNext): Promise<void>;
}
/**
*
*/
export default class MiddlewareManager {
/**
*
*/
#middlewares: MiddlewareCallback[] = []
/**
*
*/
#middlewares: MiddlewareCallback[] = [];
/**
*
*
* @param middleware
*/
use(middleware: MiddlewareCallback) {
assert(isFunction(middleware), 'middleware 不是一个 function')
this.#middlewares.push(middleware)
}
/**
*
*
* @param middleware
*/
use(middleware: MiddlewareCallback) {
assert(isFunction(middleware), 'middleware 不是一个 function');
this.#middlewares.push(middleware);
}
/**
*
*/
createContext(config: AxiosRequestConfig): MiddlewareContext {
return {
req: config,
res: null,
}
}
/**
*
*/
createContext(config: AxiosRequestConfig): MiddlewareContext {
return {
req: config,
res: null,
};
}
/**
*
*
* @param ctx
* @param respond
*/
run(ctx: MiddlewareContext, respond: MiddlewareCallback) {
const middlewares = [...this.#middlewares, respond]
async function next() {
await middlewares.shift()!(ctx, next)
}
return next()
}
/**
*
*
* @param ctx
* @param respond
*/
run(ctx: MiddlewareContext, respond: MiddlewareCallback) {
const middlewares = [...this.#middlewares, respond];
async function next() {
await middlewares.shift()!(ctx, next);
}
return next();
}
/**
*
*
* @param enhancer
*/
enhanceRun(enhancer: MiddlewareManager['run']): MiddlewareManager['run'] {
return (ctx, respond) => {
return enhancer(ctx, () => this.run(ctx, respond))
}
}
/**
*
*
* @param enhancer
*/
enhanceRun(enhancer: MiddlewareManager['run']): MiddlewareManager['run'] {
return (ctx, respond) => {
return enhancer(ctx, () => this.run(ctx, respond));
};
}
}

View File

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

View File

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

View File

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

View File

@ -1 +1 @@
export const version = '2.4.1'
export const version = '2.4.1';

View File

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