更新各班级出勤登记与课评汇总,新增教学日程查询技能与CSP03枚举算法教案

This commit is contained in:
chengzi
2026-05-05 18:53:11 +08:00
parent 1f276f874b
commit b7cd74392c
447 changed files with 57291 additions and 148 deletions

View File

@@ -0,0 +1,580 @@
# CSP03-08 枚举算法
## 一、课程简介5分钟
### 🎯 课程目标
1. 理解算法的三种描述方式:自然语言、流程图、伪代码
2. 掌握枚举法(穷举法)的核心思想
3. 理解枚举法的边界设计原则
4. 能够用枚举法解决常见的穷举搜索类问题
### 📚 核心知识点
- 算法的描述方式:自然语言(文字说明)、流程图(图形表示)、伪代码(接近代码的文字)
- 枚举法的定义:逐一列举所有可能的解,逐个验证
- 枚举的范围(边界):如何确定起点和终点
- 枚举的验证条件:什么样的值满足要求
- 枚举的优化:剪枝、缩小枚举范围
- 枚举法的时间复杂度分析
---
## 二、知识回顾10分钟
### 👩‍🏫 教师引导
> 同学们,我们在 CSP03 前几节学了数组和字符串。从这节课开始,我们进入**算法**的世界!
>
> 什么是算法?就是解决问题的**方法和步骤**。
>
> 今天先从最简单的算法思想开始——**枚举法**,也叫穷举法:用最"笨"的方法,把所有可能的答案都试一遍!
>
> 虽然"笨",但是有效!很多竞赛题用枚举就能解决!
**互动复习:**
> - for 循环可以控制变量从 a 到 b 遍历,这不就是在"枚举" a 到 b 的所有值吗?
> - 学了枚举法,就相当于给 for 循环赋予了"算法内涵"
---
## 三、新知讲解45分钟
### 1. 新知导入 🎬
> **猜数游戏:** 我脑子里想了一个 1~100 之间的整数,你能猜出来吗?
>
> 最"笨"的方法:从 1 猜到 100总能猜到——这就是枚举法
>
> 实际上,枚举法是很多算法的基础。很多看似复杂的问题,暴力枚举都能解决——只要数据规模不太大。
>
> 信奥比赛中,枚举法写得好,可以得到部分分甚至满分!
---
### 2. 知识点讲解
#### 2.1 算法的三种描述方式
**① 自然语言**(文字描述):
> 找出 1~100 中所有能被 3 整除的数:
> 从 1 遍历到 100对每个数判断能否被 3 整除,若能则输出。
**② 流程图**(图形表示关键节点和流向):
```
开始
i = 1
i <= 100? → 否 → 结束
↓ 是
i % 3 == 0? → 否 → i++
↓ 是
输出 i
i++
(返回判断)
```
**③ 伪代码**(介于自然语言和代码之间):
```
FOR i FROM 1 TO 100:
IF i MOD 3 == 0:
OUTPUT i
```
**代码实现:**
```cpp
for (int i = 1; i <= 100; i++) {
if (i % 3 == 0) cout << i << " ";
}
```
---
#### 2.2 枚举法的核心思想
**枚举法 = 确定范围 + 逐一验证**
**三要素:**
1. **枚举的对象**:什么是我们要找的"候选答案"
2. **枚举的范围(边界)**:候选答案的取值范围?
3. **验证的条件**:候选答案满足什么条件才算正确答案?
---
#### 2.3 枚举的边界设计
**原则:宁可多枚举,不要漏掉正确答案!**
但也要避免枚举太多导致超时。
**示例:百钱百鸡问题**
100 文钱买 100 只鸡,鸡翁 5 文/只,鸡母 3 文/只,鸡雏 1 文/3只三种都要买各买几只
**枚举分析:**
- 设公鸡 x 只范围0 到 20因为 5×20=100
- 设母鸡 y 只范围0 到 33因为 3×33=99<100
- 小鸡 z = 100 - x - y
**验证条件:**
- `z >= 0`(鸡的数量不为负)
- `z % 3 == 0`(小鸡必须是 3 的倍数)
- `5*x + 3*y + z/3 == 100`(总价格等于 100
```cpp
for (int x = 0; x <= 20; x++) {
for (int y = 0; y <= 33; y++) {
int z = 100 - x - y;
if (z >= 0 && z % 3 == 0 && 5*x + 3*y + z/3 == 100) {
cout << "公鸡:" << x << " 母鸡:" << y << " 小鸡:" << z << endl;
}
}
}
```
> 📌 黑板推演:两层循环,每次组合验证一种可能。虽然最多循环 21×34=714 次,但逻辑清晰,代码简洁。
---
#### 2.4 枚举法的时间复杂度
| 枚举层数 | 时间复杂度 | 适用规模n |
|---------|-----------|------------|
| 单层枚举 | O(n) | n ≤ 10⁸ |
| 双层枚举 | O(n²) | n ≤ 10⁴ |
| 三层枚举 | O(n³) | n ≤ 500 |
> ⚠️ 竞赛中,一般 10⁸ 次操作是 1 秒的上限,超过则可能超时!
---
#### 2.5 枚举法的优化(剪枝)
**剪枝**:在枚举过程中,提前跳过不可能是答案的情况。
**示例:** 找满足 a + b + c = 100 的正整数组合a≤b≤c
```cpp
// 优化前三层循环O(n³)
for (int a = 1; a <= 100; a++)
for (int b = 1; b <= 100; b++)
for (int c = 1; c <= 100; c++)
if (a + b + c == 100) ...
// 优化后剪枝c = 100 - a - b直接计算
for (int a = 1; a <= 100; a++)
for (int b = a; b <= 100; b++) { // b >= a
int c = 100 - a - b;
if (c >= b) ... // 满足 c >= b 才输出
}
```
**效率对比:** 三层循环 100³ = 10⁶ 次;优化后约 10⁴/2 次!
---
### 3. GESP 真题演练 ⚡
**抢答题 1选择题**
> 使用枚举法求 1 到 1000 中所有完全平方数(即某个整数的平方),最合理的枚举方式是(
>
> A. 枚举 1~1000 的所有数,判断其是否是某整数的平方
> B. 枚举 1~31 的所有整数 i计算 i² 加入结果
> C. 枚举 1~1000 的所有数对 (i, j),判断 i×j 是否满足
> D. 随机猜测
>
> **答案B**
> 解析√1000 ≈ 31.6,所以枚举 i 从 1 到 31计算 i² 即可找到 1~1000 内所有完全平方数,效率最高。
**判断题 2**
> 枚举法的核心思想是:逐一检验所有候选答案,找出满足条件的解。(
>
> **答案:✓(正确)**
**抢答题 3**
> 以下哪种问题**不适合**用枚举法解决?
>
> A. 在 1~100 中找满足某条件的整数
> B. 在 n=10⁹ 的数组中找出所有满足条件的下标对
> C. 在一个 4×4 的棋盘上找所有放置方式
> D. 在 1~1000 中找所有质数
>
> **答案B**
> 解析n=10⁹ 时,二层枚举需要 10¹⁸ 次,严重超时,需要更高效的算法。
---
### 4. 进阶扩展
**枚举法的经典模板:**
```cpp
// 模板1单变量枚举
for (int x = ; x <= ; x++) {
if ((x)) {
;
}
}
// 模板2双变量枚举
for (int x = 1; x <= 1; x++) {
for (int y = 2; y <= 2; y++) {
if ((x, y)) {
;
}
}
}
```
**枚举法的应用领域:**
- 数字问题(整数分解、质因数)
- 组合问题(选 k 个数的方案)
- 棋盘问题(八皇后、数独)
- 密码暴力破解(有限字符集)
---
## 四、课堂练习45分钟🎈
### 练习 1基础找因数
**题目描述:**
输入一个正整数 n输出 n 的所有因数(包括 1 和 n 本身),从小到大排列。
**输入格式:**
- 一个正整数 n1 ≤ n ≤ 10000
**输出格式:**
- 所有因数,空格分隔
**样例输入:**
```
12
```
**样例输出:**
```
1 2 3 4 6 12
```
**题解代码:**
```cpp
#include <iostream>
using namespace std;
int main() {
int n; cin >> n;
for (int i = 1; i <= n; i++) {
if (n % i == 0) cout << i << " ";
}
cout << endl;
return 0;
}
```
---
### 练习 2基础判断质数
**题目描述:**
输入一个正整数 n判断它是否是质数素数
**输入格式:**
- 一个正整数 n2 ≤ n ≤ 10000
**输出格式:**
- `YES``NO`
**样例输入:**
```
17
```
**样例输出:**
```
YES
```
**题解代码:**
```cpp
#include <iostream>
#include <cmath>
using namespace std;
int main() {
int n; cin >> n;
bool isPrime = true;
for (int i = 2; i <= sqrt(n); i++) {
if (n % i == 0) { isPrime = false; break; }
}
cout << (isPrime ? "YES" : "NO") << endl;
return 0;
}
```
---
### 练习 3综合百钱百鸡
**题目描述:**
100 文钱买 100 只鸡:公鸡 5 文/只,母鸡 3 文/只,小鸡 1 文/3只每种至少一只找出所有购买方案。
**输入格式:**(无输入)
**输出格式:**
- 每行输出一种方案:`公鸡x只 母鸡y只 小鸡z只`
**样例输出:**
```
公鸡4只 母鸡18只 小鸡78只
公鸡8只 母鸡11只 小鸡81只
公鸡12只 母鸡4只 小鸡84只
```
**题解代码:**
```cpp
#include <iostream>
using namespace std;
int main() {
for (int x = 1; x <= 19; x++) {
for (int y = 1; y <= 32; y++) {
int z = 100 - x - y;
if (z > 0 && z % 3 == 0 && 5*x + 3*y + z/3 == 100) {
cout << "公鸡" << x << "只 母鸡" << y << "只 小鸡" << z << "" << endl;
}
}
}
return 0;
}
```
---
### 练习 4综合找出所有三位水仙花数
**题目描述:**
水仙花数是这样的三位数:每一位数字的立方之和等于本身(如 153 = 1³+5³+3³。输出所有水仙花数。
**输入格式:**(无)
**输出格式:**
- 每行一个水仙花数
**样例输出:**(部分)
```
153
370
371
407
```
**题解代码:**
```cpp
#include <iostream>
using namespace std;
int main() {
for (int n = 100; n <= 999; n++) {
int a = n / 100; // 百位
int b = n / 10 % 10; // 十位
int c = n % 10; // 个位
if (a*a*a + b*b*b + c*c*c == n) {
cout << n << endl;
}
}
return 0;
}
```
---
### 练习 5进阶两数之和
**题目描述:**
输入 n 个不同整数和目标值 target从数组中找出两个数使它们的和等于 target输出这两个数先小后大。保证有且只有一组解。
**输入格式:**
- 第一行 n 和 target
- 第二行 n 个整数
**输出格式:**
- 两个整数,空格分隔
**样例输入:**
```
5 9
2 7 11 15 4
```
**样例输出:**
```
2 7
```
**题解代码:**
```cpp
#include <iostream>
using namespace std;
int a[1005];
int main() {
int n, target;
cin >> n >> target;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
if (a[i] + a[j] == target) {
int x = min(a[i], a[j]);
int y = max(a[i], a[j]);
cout << x << " " << y << endl;
return 0;
}
}
}
return 0;
}
```
---
## 五、课堂总结5分钟🌟
> 今天我们学习了算法世界的入门——**枚举法**
>
> 枚举法三要素:
> 1. **枚举对象**:谁是候选答案?
> 2. **枚举范围(边界)**:从哪里到哪里?
> 3. **验证条件**:判断当前候选是否正确
>
> 算法描述方式:自然语言、流程图、伪代码——三种说同一件事,理解即可。
>
> 下节课我们学"模拟算法"——让计算机按照现实逻辑一步步执行,解决更复杂的问题!
---
## 六、课后作业与拓展10分钟
### 📝 课后作业3道
#### 作业 1输出 n 以内所有质数
输入正整数 n输出 2 到 n 之间所有质数,每行一个。
**样例:** n=10 → 2 3 5 7
```cpp
#include <iostream>
#include <cmath>
using namespace std;
bool isPrime(int x) {
if (x < 2) return false;
for (int i = 2; i <= sqrt(x); i++) if (x%i==0) return false;
return true;
}
int main() {
int n; cin>>n;
for (int i=2;i<=n;i++) if(isPrime(i)) cout<<i<<endl;
return 0;
}
```
---
#### 作业 2找完全数
正整数中,"完全数"是所有真因子(不包含本身)之和等于自身的数(如 6 = 1+2+3。输出 1~1000 内的所有完全数。
**样例输出:** 6 28 496
```cpp
#include <iostream>
using namespace std;
int main() {
for (int n=1;n<=1000;n++) {
int sum=0;
for (int i=1;i<n;i++) if(n%i==0) sum+=i;
if (sum==n) cout<<n<<endl;
}
return 0;
}
```
---
#### 作业 3找满足条件的三位数
找出所有三位整数 n满足n 是 3 的倍数,且 n 的各位数字之积也是 3 的倍数。
**样例输出(部分):** 111 123 ...
```cpp
#include <iostream>
using namespace std;
int main() {
for (int n=100;n<=999;n++) {
int a=n/100, b=n/10%10, c=n%10;
if (n%3==0 && (a*b*c)%3==0) cout<<n<<endl;
}
return 0;
}
```
---
### 🔥 拓展习题尖子生挑战7道
#### 挑战 1四平方和定理
任意正整数都可以表示为最多4个完全平方数之和。对于给定的 n找出使用最少个完全平方数表示 n 的方案最少2个输出具体方案中数量最少的一种
**提示:** 枚举所有 ≤ √n 的完全平方数组合。
#### 挑战 2火柴棍数字
用 n 根火柴棍可以摆出多少种不同的数字0-91种数字可以由多根火柴棍组成请枚举找出可以用恰好 n 根火柴摆出的最大数。火柴数0→6,1→2,2→5,3→5,4→4,5→5,6→6,7→3,8→7,9→6
**提示:** 动态规划或枚举,但对于简单情况可用枚举。
#### 挑战 3扑克牌 24 点
给定 4 张牌1~13判断能否通过加减乘除允许括号得到 24。
**提示:** 枚举 4 个数的所有排列4! = 24 种和运算符的所有组合4³ = 64 种以及括号方式5种共约 7680 种情况。
#### 挑战 4最小覆盖矩形
给定平面上 n 个点,找出面积最小的轴对齐矩形,能包含所有点(枚举法:找 x 和 y 方向上的最小最大值)。
**提示:** 找 min_x, max_x, min_y, max_y面积即 (max_x-min_x)*(max_y-min_y)。
#### 挑战 5质因数分解
输入正整数 n输出其质因数分解结果如 12 = 2² × 3
**提示:** 从 2 开始枚举,能整除就统计个数并除去,直到 n == 1 或当前枚举数的平方大于 n。
#### 挑战 6最小公倍数与最大公因数
枚举法求两个整数 a、b 的最大公因数GCD枚举 1~min(a,b),找最大的能同时整除两者的数。
**提示:** 理解辗转相除法Euclid算法其实更优但枚举在数值小时完全可行。
#### 挑战 7找所有满足条件的数组
给定 n1≤n≤10找出所有满足长度为 n、元素均为 1 到 9、所有元素之积等于给定值 M 的严格递增序列。
**提示:** 递归枚举,每次选一个比上一个大的数,在乘积不超过 M 的情况下继续。

View File

@@ -9,3 +9,4 @@
| 2026-04-11 | AI大作家 | 第5课 | ✅ 出勤 | |
| 2026-04-17 | AI大作家 | 第6课 | ✅ 出勤 | |
| 2026-04-18 | 我是大作家-2 | 第6课 | ⏸ 请假 | |
| 2026-05-02 | 个人网页完善 | 第8课 | ⏸ 请假 | |

View File

@@ -10,3 +10,4 @@
| 2026-04-12 | 我是大作家(完结篇) | 第6课 | ✅ 出勤 | |
| 2026-04-18 | AI大作家插图生成 | 第7课 | ✅ 出勤 | |
| 2026-04-25 | 我的个人主页 | 第8课 | ✅ 出勤 | |
| 2026-05-03 | 我的个人主页(下) | 第9课 | ⏸ 请假 | |

View File

@@ -10,3 +10,4 @@
| 2026-04-12 | 我是大作家(完结篇) | 第6课 | ✅ 出勤 | |
| 2026-04-18 | AI大作家插图生成 | 第7课 | ✅ 出勤 | |
| 2026-04-25 | 我的个人主页 | 第8课 | ✅ 出勤 | |
| 2026-04-26 | 个人网页完善 | 第9课 | ✅ 出勤 | |

View File

@@ -94,3 +94,26 @@
老师会继续关注子墨的表现,期待看到更多精彩!🌟💡
---
## 第8条个人网页完善
**授课日期**2026-04-26
**课评内容**
子墨今天表现超棒~对个人网页完善的知识点掌握得很不错~能够把自己的头像引入到网页中,还锲而不舍地成功添加了自己喜欢的背景音乐,这种坚持达成目标的精神特别好!以你的机灵程度,把学到的知识灵活运用起来的能力真的很厉害~要是上课的时候能再专注一点,少被周围的事情分散注意力,你一定会做出更有创意的作品哦~
老师会继续关注子墨的表现,期待看到更多精彩!🌟💡
---
## 第9条我的个人主页
**授课日期**2026-05-03
**课评内容**
子墨今天表现超棒不仅完成了个人网页的完善任务还成功把自己的头像加入到了网页中最值得表扬的是你锲而不舍地反复尝试最终成功把自己喜欢的音乐也添加到了网页里这种坚持达成目标的精神特别厉害你对AI工具的灵活运用能力一直都很强要是上课的时候能再专注一点少被周围的事情分散注意力一定会做出更有创意的作品哦
老师会继续关注子墨的表现,期待看到更多精彩!🌟💡
---

View File

@@ -10,3 +10,4 @@
| 2026-04-12 | 我是大作家(完结篇) | 第6课 | ✅ 出勤 | |
| 2026-04-18 | AI大作家插图生成 | 第7课 | ✅ 出勤 | |
| 2026-04-25 | 我的个人主页 | 第8课 | ✅ 出勤 | |
| 2026-04-26 | 个人网页完善 | 第9课 | ✅ 出勤 | |

View File

@@ -94,3 +94,26 @@
老师会继续关注俊研的进步,期待看到更多精彩!🌸😊
---
## 第8条个人网页完善
**授课日期**2026-04-26
**课评内容**
俊研今天表现超棒~对个人网页完善的知识点掌握得很不错~上课一直安静专注,不仅完成了网页生成,还通过自己的方法把网页设计成喜欢的样式,还添加了自己喜欢的变形金刚电影元素,很有自己的想法~你踏实认真的学习态度一直都很棒,要是课后多练习一下打字,创作的效率会更高哦~
老师会继续关注俊研的进步,期待看到更多精彩!🌸😊
---
## 第9条我的个人主页
**授课日期**2026-05-03
**课评内容**
俊研今天表现超棒!对个人网页完善的知识点掌握得很不错,上课一直安静专注,不仅完成了网页生成,还通过自己的方法把网页设计成喜欢的样式,还添加了自己喜欢的变形金刚电影元素,很有自己的想法~你踏实认真的学习态度一直都很棒,要是课后多练习一下打字,创作的效率会更高哦~
老师会继续关注俊研的进步,期待看到更多精彩!🌸😊
---

View File

@@ -8,4 +8,5 @@
| 2026-03-29 | 我是大作家-1 | 第4课 | ✅ 出勤 | |
| 2026-04-06 | 我是大作家-2 | 第5课 | ✅ 出勤 | |
| 2026-04-12 | 我是大作家(完结篇) | 第6课 | ⏸ 请假 |
| 2026-04-18 | AI大作家插图生成 | 第7课 | ⏸ 请假 | | |
| 2026-04-18 | AI大作家插图生成 | 第7课 | ⏸ 请假 | |
| 2026-04-26 | 个人网页完善 | 第8课 | ✅ 出勤 | |

View File

@@ -82,3 +82,26 @@
嘉博本周请假未上课。请嘉博家长安排好时间督促嘉博在家了解本周小说插图生成的相关知识点包括使用trea生成插图提示词、使用豆包生成图片并插入文章的方法。如有疑问欢迎随时联系老师。
---
## 第7条个人网页完善
**授课日期**2026-04-26
**课评内容**
嘉博今天表现超棒对个人网页完善的知识点有很好的掌握上课一直很专注对自己创建的个人网页特别感兴趣能够详细描述自己的兴趣爱好、梦想给AI还能主动修改卡片颜色、给背景添加小花很有自己的创意虽然打字速度还是需要慢慢提升但你一直在认真坚持这份细致的态度特别珍贵要是课后可以多练习一下打字你创作的效率会更高哦
老师会继续关注嘉博的表现,期待看到更多精彩!🌟💡
---
## 第8条我的个人主页
**授课日期**2026-05-03
**课评内容**
嘉博今天对自己的个人网页特别用心上课很开心能够详细地把自己的兴趣爱好、梦想告诉AI表达得很清楚看到页面觉得颜色不太好看就主动修改卡片颜色还给背景添加了小花这种根据自己的审美进行优化的意识很棒你对网页细节的关注说明你很有设计眼光继续发挥创意你的网页会越来越精彩的
老师会继续关注嘉博的表现,期待看到更多精彩!🌟💡
---

View File

@@ -9,4 +9,5 @@
| 2026-04-05 | 我是大作家-2 | 第5课 | ⏸ 请假 | 已转班 |
| 2026-04-12 | 我是大作家(完结篇) | 第6课 | ⏸ 请假 | 已转班
| 2026-04-18 | AI大作家插图生成 | 第7课 | ✅ 出勤 | |
| 2026-04-25 | 我的个人主页 | 第8课 | ✅ 出勤 | | |
| 2026-04-25 | 我的个人主页 | 第8课 | ✅ 出勤 | |
| 2026-05-03 | 我的个人主页(下) | 第9课 | ✅ 出勤 | |

View File

@@ -92,3 +92,15 @@
老师会继续关注彦棋的表现,期待看到更多惊喜!🎯✨
---
## 第8条我的个人主页
**授课日期**2026-05-03
**课评内容**
彦棋今天状态超棒按照老师的要求顺利完成了个人网页的完善任务成功给自己的作品添加了头像和喜欢的音乐动手能力很强老师觉得你在AIGC创作方面很有天赋非常推荐你参加后续的AIGC比赛展示你的才华以你的能力只要更细心一点把作品的每个细节都打磨得更精致一定会有更惊艳的表现
老师会继续关注彦棋的表现,期待看到更多惊喜!🎯✨
---

View File

@@ -10,3 +10,4 @@
| 2026-04-12 | 我是大作家(完结篇) | 第6课 | ✅ 出勤 | |
| 2026-04-19 | AI大作家插图生成 | 第7课 | ✅ 出勤 | |
| 2026-04-26 | 我的个人主页 | 第8课 | ✅ 出勤 | |
| 2026-05-04 | 我的个人主页(下) | 第9课 | ✅ 出勤 | |

View File

@@ -92,3 +92,15 @@
要是能继续保持这种认真的学习态度,不被周围的事情吸引,效果会更好~老师会继续关注皓霖的学习状态,期待看到更多进步!🌟💪
---
## 第8条我的个人主页
**授课日期**2026-05-04
**课评内容**
皓霖今天表现很棒!对本节课的知识掌握得很好,个人主页作品也完成得很出色~特别让老师高兴的是,皓霖上课的状态特别好,能够在老师讲课的时候放下手上的任务,认真听老师的安排,这种能够自我管理的专注力比之前进步了很多!继续保持这种认真的学习态度,你的效率会越来越高的~
老师会继续关注皓霖的表现,期待看到更多进步!🌟💪
---

View File

@@ -10,3 +10,4 @@
| 2026-04-12 | 我是大作家(完结篇) | 第6课 | ✅ 出勤 | |
| 2026-04-19 | AI大作家插图生成 | 第7课 | ✅ 出勤 | |
| 2026-04-26 | 我的个人主页 | 第8课 | ✅ 出勤 | |
| 2026-05-04 | 我的个人主页(下) | 第9课 | ⏸ 请假 | |

View File

@@ -74,3 +74,15 @@
你的踏实认真让老师很省心,继续保持这份专注和独立完成任务的态度~老师会继续关注翊弘的表现,期待看到更多精彩!🌟💡
---
## 第7条我的个人主页
**授课日期**2026-05-04
**课评内容**
翊弘今天表现很棒!对本节课的知识掌握得很好,个人网页做得非常出色,上课状态也一直很稳定,能够踏踏实实地完成每个步骤,遇到问题也能自己思考解决~你一直都是个认真踏实的孩子,继续保持这份专注和独立完成任务的态度,一定会越来越优秀的!
老师会继续关注翊弘的表现,期待看到更多精彩!🌟💡
---

View File

@@ -92,3 +92,15 @@
老师会继续关注浩宸的学习状态,期待看到更多进步!🌟💪
---
## 第8条我的个人主页
**授课日期**2026-05-04
**课评内容**
浩宸今天整体表现不错,在老师的引导下完成了个人网页的完善任务,对网页添加元素的操作有了进一步的掌握~老师看到你一直在努力跟上节奏,这一点值得肯定。如果上课的时候能够更专注一点,主动跟着老师的思路走,遇到问题大胆提问,学习效果一定会更好。打字不熟练没关系,多练习就会越来越快的,四年级的男子汉,老师相信你一定可以做到的!
老师会继续关注浩宸的学习状态,期待看到更多进步!🌟💪
---

View File

@@ -78,3 +78,15 @@
你的学习状态一直很好,接受新知识又快又认真,继续保持这种积极好学的态度~老师会继续关注浩睿的表现,期待看到更多精彩!✨💡
---
## 第7条我的个人主页
**授课日期**2026-05-04
**课评内容**
浩睿今天表现超棒对本节课的知识点掌握得相当出色还能够举一反三灵活运用学到的方法来完善自己的个人网页这种学习能力特别厉害你一直都很有探索精神遇到问题会主动思考解决方法学习效率很高。继续保持这份积极好学的态度你一定可以在AIGC创作方面取得更多的成果
老师会继续关注浩睿的表现,期待看到更多创意!✨💡
---

View File

@@ -0,0 +1,18 @@
# 张玉辰 课评汇总2026春季
**班级**周日下午1400AI03班
**学生**:张玉辰
---
## 第1条我的个人主页
**授课日期**2026-05-04
**课评内容**
玉辰今天第一次上课表现就很不错成功完成了自己的个人网页还顺利给自己的网页添加了头像遇到问题会主动询问老师这种勤学好问的态度特别棒看得出来你对AIGC创作很感兴趣继续保持这份热情跟着老师的节奏一步步学习一定会越来越厉害的。
老师会继续关注玉辰的表现,期待看到更多精彩!🌟💡
---

View File

@@ -0,0 +1,5 @@
# 出勤登记 - 2026春季学期
| 日期 | 课程 | 课次 | 状态 | 备注 |
|------|------|------|------|------|
| 2026-05-04 | 我的个人主页(下) | 第9课 | ⏸ 请假 | |

View File

@@ -76,3 +76,15 @@
你的想象力和耐心一直都是你的优势,今天把它们都用在了网页创作上,作品完成得很出色~老师会继续关注俊宇的表现,期待看到更多惊喜!🎯✨
---
## 第7条我的个人主页
**授课日期**2026-05-04
**课评内容**
俊宇今天表现太棒了全程跟着老师的节奏走对自己的作品特别上心不仅积极完成了所有任务还主动和老师互动交流想法进步非常明显老师也发现你越来越出色了你在AIGC创作方面很有天赋老师特别推荐你参加后续的AIGC比赛相信你一定可以取得好成绩的。继续保持这份热情和专注你会越来越厉害的
老师会继续关注俊宇的表现,期待看到更多惊喜!🎯✨
---

View File

@@ -76,3 +76,15 @@
老师会继续关注楚悦的表现,期待看到更多精彩!🌟💡
---
## 第7条我的个人主页
**授课日期**2026-05-04
**课评内容**
楚悦今天表现很棒不仅补上了上节课请假落下的内容还成功给自己的个人网页添加了头像动手能力很强老师知道你看到很多字要打会有些害怕没关系打字是可以慢慢练习的回家之后可以下载一个金山打字软件每天练习10分钟坚持一段时间打字速度一定会越来越快的。你一直都很认真踏实继续保持这份学习态度一定会越来越优秀的
老师会继续关注楚悦的进步,期待看到更多精彩!🌸😊
---

View File

@@ -8,3 +8,5 @@
| 2026-03-29 | 连续性元素处理 | 第5课 | ⏸ 请假 | |
| 2026-04-05 | 字符数组 | 第6课 | ✅ 出勤 | |
| 2026-04-18 | 字符串处理 | 第7课 | ✅ 出勤 | |
| 2026-04-25 | 字符串小测与复习 | 第8课 | ✅ 出勤 | |
| 2026-05-02 | 枚举算法 | 第9课 | ✅ 出勤 | |

View File

@@ -101,3 +101,24 @@
加油呀!💪✨
---
## 第9条枚举算法
**授课日期**2026-05-02
**课评内容**
家长好,本周学习的内容是《枚举算法》:
1. 理解算法的三种描述方式:自然语言、流程图、伪代码
2. 掌握枚举法(穷举法)的核心思想:确定范围+逐一验证
3. 理解枚举法的边界设计原则,合理设置枚举范围
4. 掌握枚举法的优化策略(剪枝),减少不必要的枚举
5. 学会枚举法的代码实现,能够将枚举思想转化为程序代码
此外课前对上周string知识点进行了小测复习重点回顾了字符串长度函数(size()/length())、下标访问、substr()截取、find()查找、replace()替换、erase()删除等基础函数的用法。
林轩这节课表现得还不错,对枚举算法有所了解,能够掌握枚举的核心思想,求约数、判断素数等基础题目可以自己完成。上课时能合上电脑跟着老师学习,这一点有进步!不过在做"两数之和"时会有一点粗心回去可以重新写一次第五题巩固一下。从课前小测来看substr()截取、replace()替换和erase()删除这几个函数的用法还需要多复习,回去把这几个函数的参数含义整理到笔记本上,理解清楚就不会再丢分了。
加油呀!💪✨
---

View File

@@ -8,3 +8,5 @@
| 2026-03-29 | 连续性元素处理 | 第5课 | ⏸ 请假 | |
| 2026-04-05 | 字符数组 | 第6课 | ✅ 出勤 | |
| 2026-04-18 | 字符串处理 | 第7课 | ✅ 出勤 | |
| 2026-04-25 | 字符串小测与复习 | 第8课 | ✅ 出勤 | |
| 2026-05-02 | 枚举算法 | 第9课 | ✅ 出勤 | |

View File

@@ -99,3 +99,24 @@
加油呀!💪✨
---
## 第9条枚举算法
**授课日期**2026-05-02
**课评内容**
家长好,本周学习的内容是《枚举算法》:
1. 理解算法的三种描述方式:自然语言、流程图、伪代码
2. 掌握枚举法(穷举法)的核心思想:确定范围+逐一验证
3. 理解枚举法的边界设计原则,合理设置枚举范围
4. 掌握枚举法的优化策略(剪枝),减少不必要的枚举
5. 学会枚举法的代码实现,能够将枚举思想转化为程序代码
此外课前对上周string知识点进行了小测复习重点回顾了字符串长度函数(size()/length())、下标访问、substr()截取、find()查找、replace()替换、erase()删除等基础函数的用法。
俊宇本节课整体表现不错对枚举算法有所了解能够掌握相关内容题目也可以自己独立完成甚至还能发现一些优化方法做完优化之后又用传统方法再写一次这种对比学习的思维方式特别棒不过会有一点点吵会发出一些奇怪的声音被老师批评之后可以立刻改正继续完成自己的作业这个态度值得肯定。从课前小测来看substr()截取函数的参数含义和字符串比较的规则还需要再巩固一下,回去把这两个知识点理一理,记清楚就不会出错了。
加油呀!💪✨
---

View File

@@ -8,3 +8,5 @@
| 2026-03-29 | 连续性元素处理 | 第5课 | ⏸ 请假 | |
| 2026-04-05 | 字符数组 | 第6课 | ✅ 出勤 | |
| 2026-04-18 | 字符串处理 | 第7课 | ✅ 出勤 | |
| 2026-04-25 | 字符串小测与复习 | 第8课 | ✅ 出勤 | |
| 2026-05-02 | 枚举算法 | 第9课 | ✅ 出勤 | |

View File

@@ -99,3 +99,24 @@
加油呀!💪✨
---
## 第9条枚举算法
**授课日期**2026-05-02
**课评内容**
家长好,本周学习的内容是《枚举算法》:
1. 理解算法的三种描述方式:自然语言、流程图、伪代码
2. 掌握枚举法(穷举法)的核心思想:确定范围+逐一验证
3. 理解枚举法的边界设计原则,合理设置枚举范围
4. 掌握枚举法的优化策略(剪枝),减少不必要的枚举
5. 学会枚举法的代码实现,能够将枚举思想转化为程序代码
此外课前对上周string知识点进行了小测复习重点回顾了字符串长度函数(size()/length())、下标访问、substr()截取、find()查找、replace()替换、erase()删除等基础函数的用法。
子杰本节课表现整体不错,对枚举算法有所了解,能够掌握相关内容,基础题目可以自己完成。不过到后面的"百钱百鸡"、"水仙花数"等综合题目时会有一点点卡壳在老师的指导下能够重新理顺思路完成题目这种不放弃的精神很好。子杰这学期的态度进步非常大主动性也越来越强继续保持从课前小测来看find()查找函数的返回值含义和replace()替换函数的用法还需要多花点时间巩固,回去把这些函数整理到笔记本上,多练习几遍就熟练了。
加油呀!💪✨
---

View File

@@ -8,3 +8,4 @@
| 2026-03-29 | 连续性元素处理 | 第5课 | ⏸ 请假 | |
| 2026-04-05 | 字符数组 | 第6课 | ✅ 出勤 | |
| 2026-04-18 | 字符串处理 | 第7课 | ✅ 出勤 | |
| 2026-05-03 | 枚举算法 | 第9课 | ✅ 出勤 | |

View File

@@ -99,3 +99,22 @@
加油呀!💪✨
---
## 第9条枚举算法
**授课日期**2026-05-02
**课评内容**
家长好,本周学习的内容是《枚举算法》:
1. 掌握使用自然语言、流程图、伪代码描述算法的方法
2. 理解枚举法的概念与思想,掌握枚举法的基本实现方式
3. 学会枚举法的边界确定,能够合理设置枚举范围
4. 掌握枚举法的优化策略,能够减少不必要的枚举
5. 学会枚举法的代码实现,能够将枚举思想转化为程序代码
明泓课堂练习能够全部完成,对枚举算法的知识点也能够掌握,学习能力一如既往地在线!不过老师发现明泓偶尔会打开游戏进行游玩,虽然在老师的要求下能够及时关闭继续学习,但还是希望明泓上课时能够更加专注,把全部精力放在课堂上。六年级的知识点会越来越有难度,专注听课才能理解得更透彻。
加油呀!💪✨
---

View File

@@ -8,3 +8,5 @@
| 2026-03-29 | 连续性元素处理 | 第5课 | ⏸ 请假 | |
| 2026-04-05 | 字符数组 | 第6课 | ✅ 出勤 | |
| 2026-04-18 | 字符串处理 | 第7课 | ✅ 出勤 | |
| 2026-04-25 | 字符串小测与复习 | 第8课 | ✅ 出勤 | |
| 2026-05-02 | 枚举算法 | 第9课 | ✅ 出勤 | |

View File

@@ -101,3 +101,24 @@
加油呀!💪✨
---
## 第9条枚举算法
**授课日期**2026-05-02
**课评内容**
家长好,本周学习的内容是《枚举算法》:
1. 理解算法的三种描述方式:自然语言、流程图、伪代码
2. 掌握枚举法(穷举法)的核心思想:确定范围+逐一验证
3. 理解枚举法的边界设计原则,合理设置枚举范围
4. 掌握枚举法的优化策略(剪枝),减少不必要的枚举
5. 学会枚举法的代码实现,能够将枚举思想转化为程序代码
此外课前对上周string知识点进行了小测复习重点回顾了字符串长度函数(size()/length())、下标访问、substr()截取、find()查找、replace()替换、erase()删除等基础函数的用法。
锦程对本节课枚举算法有所了解,能够掌握相关的内容,整体表现不错,特别积极!对枚举法"确定范围、逐一验证、验证条件"三个要素理解得比较到位,求约数和判断素数的题目都能顺利完成。锦程的学习状态一直很稳定,基础也打得扎实。从课前小测来看,字符串比较的规则还需要再巩固一下,特别是"123"和"4"的比较结果容易搞混——字符串比较是逐位比ASCII码不是比数值大小这个细节注意一下就不会再丢分了。希望锦程在掌握基础的前提下尝试挑战更有深度的内容。
加油呀!💪✨
---

View File

@@ -8,3 +8,4 @@
| 2026-03-29 | 连续性元素处理 | 第5课 | ⏸ 请假 | |
| 2026-04-05 | 字符数组 | 第6课 | ✅ 出勤 | |
| 2026-04-18 | 字符串处理 | 第7课 | ✅ 出勤 | |
| 2026-05-03 | 枚举算法 | 第9课 | ⏸ 请假 | |

View File

@@ -8,3 +8,5 @@
| 2026-03-29 | 连续性元素处理 | 第5课 | ⏸ 请假 | |
| 2026-04-05 | 字符数组 | 第6课 | ✅ 出勤 | |
| 2026-04-18 | 字符串处理 | 第7课 | ✅ 出勤 | |
| 2026-04-25 | 字符串小测与复习 | 第8课 | ✅ 出勤 | |
| 2026-05-01 | 枚举算法 | 第9课 | ✅ 出勤 | |

View File

@@ -1,96 +1,70 @@
# 张雨禾 课评汇总2026春季
**班级**周六下午1400CSP03班
**学生**:张雨禾
---
## 第1条一二级知识回顾
**授课日期**2026-03-08
**课评内容**
家长好,我们本周复习的主题是《一二级知识回顾》
1. 复习数据类型
2. 复习循环结构
**课堂反馈**
开学第一节课,雨禾对上学期的知识还记忆犹新,解题游刃有余!但细节处理还不够好,容易失分,后续老师会引导雨禾改正,记得完成拓展练习喔~老师会继续关注雨禾的进步!🌟✨
---
## 第2条数组计数
**授课日期**2026-03-28
**课评内容**
家长好,本周学习的内容是《数组计数》:
1. 数组的定义与初始化
2. 数组遍历方法
3. 计数器原理
4. 数组下标运用
5. 算法思维培养
雨禾这节课比较认真,能跟上老师的节奏。不过老师发现雨禾做题的时候比较粗心,容易出现一些小错误。希望雨禾做题的时候能更细心一些,多检查几遍,减少粗心的失误~
加油呀!💪✨
---
## 第3条字符数组
**授课日期**2026-04-05
**课评内容**
雨禾每次都能在周六下午前把作业做完,时间管理能力和学习主动性让老师很欣慰~能够跟上老师的节奏上课,对本周字符数组的知识点有一定掌握。
不过老师发现,雨禾后续没有再继续做题练习,一个星期不做题会导致很多知识点遗忘。编程是需要持续练习的技能,希望雨禾回去之后能够每天抽出一些时间复习巩固,保持对代码的熟练度。理解为什么这么写,不只是做完就好~
加油呀!💪✨
---
## 第7条字符串处理
**授课日期**2026-04-18
**课评内容**
家长好,本周学习的内容是《字符串处理》:
1. 学习getline()函数的使用,掌握读取一整行字符串的方法
2. 学习substr()函数,理解字符串截取的方法和参数含义
3. 学习size() / length()函数,掌握获取字符串长度的方法
4. 学习find()函数,理解字符串查找的原理和返回值
5. 培养学生对字符串处理的综合应用能力和编程思维
张雨禾上课对知识掌握不错,下课也积极把作业完成,态度很认真。不过老师发现过去七天雨禾很多知识点都不太记得了,说明课后复习还需要加强。希望雨禾回去把本周的知识点手写记录到笔记本上,并且每天花一点时间复习。辛苦雨禾爸爸周一到周五进行监督,帮助雨禾养成好习惯。
加油呀!💪✨
---
## 第8条字符串小测与复习
**授课日期**2026-04-25
**课评内容**
家长好,本周我们进行了字符串知识点的小测与复习,主要内容包括:
1. 字符串函数的复习与巩固
2. 字符数组下标的使用规则
3. 大小写区分等基础知识点回顾
4. 代码填空练习巩固知识
5. 复习习惯的培养与强化
雨禾本周表现有惊喜也有需要加强的地方:惊喜的是在代码填空中,雨禾对之前的知识掌握得很不错,比如大小写区分的知识点能够准确写出来,说明基础打得很扎实;需要加强的是对上节课学过的字符串函数记忆不够牢固,容易忘记,字符数组下标的知识点也有所欠缺。
雨禾的学习态度一直很认真这是非常好的品质。老师建议你回去之后把笔记认真抄一遍重点记清楚每个函数的作用和用法每天花10-15分钟复习一下这些知识点多练习就能记牢了。以你的认真程度只要坚持复习一定能把这些知识点掌握得很扎实
加油呀!💪✨
---
## 第9条枚举算法
**授课日期**2026-05-01
**课评内容**
家长好,本周学习的内容是《枚举算法》:
1. 掌握使用自然语言、流程图、伪代码描述算法的方法
2. 理解枚举法的概念与思想,掌握枚举法的基本实现方式
3. 学会枚举法的边界确定,能够合理设置枚举范围
4. 掌握枚举法的优化策略,能够减少不必要的枚举
5. 学会枚举法的代码实现,能够将枚举思想转化为程序代码
雨禾对本节课的枚举算法掌握得很不错!本节课的难度相较于上节课有所放缓,雨禾学习得也更加从容,能够独立完成所有题目,表现非常好,老师为你感到骄傲!
希望雨禾回去之后继续保持认真的学习态度每天花10-15分钟复习巩固本节课的枚举算法知识点养成及时复习的好习惯减少知识点遗忘。做题的时候可以多检查几遍慢慢养成细心的习惯减少不必要的失误。继续加油你一定会越来越优秀的
加油呀!💪✨
---

View File

@@ -8,3 +8,5 @@
| 2026-03-29 | 连续性元素处理 | 第5课 | ⏸ 请假 | |
| 2026-04-05 | 字符数组 | 第6课 | ✅ 出勤 | |
| 2026-04-18 | 字符串处理 | 第7课 | ✅ 出勤 | |
| 2026-04-25 | 字符串小测与复习 | 第8课 | ✅ 出勤 | |
| 2026-05-01 | 枚举算法 | 第9课 | ✅ 出勤 | |

View File

@@ -1,96 +1,70 @@
# 苏俊宇 课评汇总2026春季
**班级**周六下午1400CSP03班
**学生**:苏俊宇
---
## 第1条一二级知识回顾
**授课日期**2026-03-08
**课评内容**
家长好,我们本周复习的主题是《一二级知识回顾》
1. 复习数据类型
2. 复习循环结构
**课堂反馈**
开学第一课俊宇状态回来啦!能沉下心学习,上学期有些漏洞,这学期老师会继续关注俊宇,一起把基础补扎实,跟上节奏!💪✨
---
## 第2条数组计数
**授课日期**2026-03-28
**课评内容**
家长好,本周学习的内容是《数组计数》:
1. 数组的定义与初始化
2. 数组遍历方法
3. 计数器原理
4. 数组下标运用
5. 算法思维培养
俊宇这节课上课比较认真,对以前的知识点能够有理解。并且能快速告诉老师自己的理解。但是如果是代码的话,他就根本做不出来,不知道该怎么做。希望俊宇回去多多练习,把理解和实践结合起来,多动手写代码才能真正掌握~
加油呀!💪✨
---
## 第3条字符数组
**授课日期**2026-04-05
**课评内容**
苏俊宇本周状态有所回暖,表现不错!在一些思维题上,能够告诉老师怎么写,说明对解题过程是有理解的,这份思考能力很可贵~上课态度也很积极,没有表现出不想写代码的情绪,让老师看到了你的进步!
不过目前在代码实现方面还有些欠缺,知道了思路但不太能够写出来。希望苏俊宇回去之后必须认真完成作业,多多练习,把思维能力和代码能力结合起来。理解为什么这么写,不只是知道思路就好~
加油呀!💪✨
---
## 第7条字符串处理
**授课日期**2026-04-18
**课评内容**
家长好,本周学习的内容是《字符串处理》:
1. 学习getline()函数的使用,掌握读取一整行字符串的方法
2. 学习substr()函数,理解字符串截取的方法和参数含义
3. 学习size() / length()函数,掌握获取字符串长度的方法
4. 学习find()函数,理解字符串查找的原理和返回值
5. 培养学生对字符串处理的综合应用能力和编程思维
苏俊宇状态在线,表现积极,能够了解本周字符串语法,上课也很认真,紧跟老师节奏,对于一些思路能很清楚地记录,态度端正。希望俊宇在完成速度上再多加练习,让写代码的能力也跟上理解的速度,多多练习会更熟练的。
加油呀!💪✨
---
## 第8条字符串小测与复习
**授课日期**2026-04-25
**课评内容**
家长好,本周我们进行了字符串知识点的小测与复习,主要内容包括:
1. 字符数组与字符串的声明方法
2. 字符串相关函数的使用与区别
3. 字符串基本操作的实践
4. 笔记研读与知识点巩固方法
5. 动手练习习惯的培养
从课堂小测结果来看,俊宇对字符数组的声明掌握得不错,这部分基础打得很扎实!但是对于字符串的一些相关函数记忆还不够牢固,需要回去把笔记认真研读,反复尝试运用,才能真正掌握。
俊宇的数学基础很好,逻辑思维能力很强,这对于学习编程是很大的优势。编程和数学其实是相通的,都是用逻辑来解决问题,只要你多花点时间动手练习,把这些函数的用法记牢,写代码的能力一定会越来越强的。老师相信你有这个能力,加油!
加油呀!💪✨
---
## 第9条枚举算法
**授课日期**2026-05-01
**课评内容**
家长好,本周学习的内容是《枚举算法》:
1. 掌握使用自然语言、流程图、伪代码描述算法的方法
2. 理解枚举法的概念与思想,掌握枚举法的基本实现方式
3. 学会枚举法的边界确定,能够合理设置枚举范围
4. 掌握枚举法的优化策略,能够减少不必要的枚举
5. 学会枚举法的代码实现,能够将枚举思想转化为程序代码
俊宇本节课表现很好!本节课的难度较上节课有所放缓,俊宇学习也变得更加自信,能够自己尝试着把这些代码通过自己的理解表达出来,这点进步非常大,老师为你感到高兴!
你的数学基础很好,逻辑思维能力很强,这对学习编程是非常大的优势。希望你继续保持这种积极的学习状态,课后多花点时间动手练习,把理解的思路转化为实际的代码,慢慢提升代码实现能力。只要坚持练习,你的编程能力一定会越来越强的!
加油呀!💪✨
---

View File

@@ -8,3 +8,4 @@
| 2026-03-29 | 连续性元素处理 | 第5课 | ⏸ 请假 | |
| 2026-04-05 | 字符数组 | 第6课 | ✅ 出勤 | |
| 2026-04-18 | 字符串处理 | 第7课 | ⏸ 请假 | 请假 |
| 2026-05-01 | 枚举算法 | 第9课 | ✅ 出勤 | |

View File

@@ -1,66 +1,50 @@
# 郑子煜 课评汇总2026春季
**班级**周六下午1400CSP03班
**学生**:郑子煜
---
## 第1条一二级知识回顾
**授课日期**2026-03-08
**课评内容**
家长好,我们本周复习的主题是《一二级知识回顾》
1. 复习数据类型
2. 复习循环结构
**课堂反馈**
第1节课暂无具体评语
---
## 第2条数组计数
**授课日期**2026-03-28
**课评内容**
家长好,本周学习的内容是《数组计数》:
1. 数组的定义与初始化
2. 数组遍历方法
3. 计数器原理
4. 数组下标运用
5. 算法思维培养
子煜这节课能跟上节奏,但老师发现很多知识点可能还不太记得,有时候会不知道自己在做什么,脑子容易乱。希望子煜回去好好复习一下以前的知识点,把基础打扎实,上课才能更清楚自己在做什么~
加油呀!💪✨
---
## 第3条字符数组
**授课日期**2026-04-05
**课评内容**
子煜上课认真,能够跟上老师的节奏,对本周字符数组的知识点有一定掌握~课堂表现积极,状态在线!
希望子煜回去之后认真完成作业,多多练习巩固所学知识。理解字符数组的使用原理,不只是听懂就好~持续练习才能让知识更加牢固,编程能力更上一层楼。
加油呀!💪✨
---
## 第7条字符串处理
**授课日期**2026-04-18
**课评内容**
郑子煜本周请假未上课。请子煜家长安排好时间督促子煜在家复习本周字符串相关知识点包括getline()、substr()、size()、find()函数的用法,并及时补做课后练习。如有疑问,欢迎随时联系老师。
---
## 第8条枚举算法
**授课日期**2026-05-01
**课评内容**
家长好,本周学习的内容是《枚举算法》:
1. 掌握使用自然语言、流程图、伪代码描述算法的方法
2. 理解枚举法的概念与思想,掌握枚举法的基本实现方式
3. 学会枚举法的边界确定,能够合理设置枚举范围
4. 掌握枚举法的优化策略,能够减少不必要的枚举
5. 学会枚举法的代码实现,能够将枚举思想转化为程序代码
子煜本节课上课很积极,能够一直跟着老师进行互动,答题正确率很高!对质数、因数这些数学概念了解得很清楚,能够将相关思路转换成代码编写出来,状态非常棒,进步很明显。
希望子煜回去之后继续巩固本节课的枚举算法知识点,多做相关练习,把基础打扎实,遇到不懂的地方及时和老师沟通。继续保持这种积极的学习状态,相信你会越来越棒的!
加油呀!💪✨
---

View File

@@ -8,3 +8,5 @@
| 2026-03-29 | 连续性元素处理 | 第5课 | ⏸ 请假 | |
| 2026-04-05 | 字符数组 | 第6课 | ✅ 出勤 | |
| 2026-04-18 | 字符串处理 | 第7课 | ✅ 出勤 | |
| 2026-04-25 | 字符串小测与复习 | 第8课 | ✅ 出勤 | |
| 2026-05-01 | 枚举算法 | 第9课 | ✅ 出勤 | |

View File

@@ -1,94 +1,69 @@
# 魏铭轩 课评汇总2026春季
**班级**周六下午1400CSP03班
**学生**:魏铭轩
---
## 第1条一二级知识回顾
**授课日期**2026-03-08
**课评内容**
家长好,我们本周复习的主题是《一二级知识回顾》
1. 复习数据类型
2. 复习循环结构
**课堂反馈**
铭轩第一节课能跟上节奏积极互动,但下课后容易分心,老师关游戏还会赌气~希望铭轩能调整状态,把专注延续到整节课!💪🌈
---
## 第2条数组计数
**授课日期**2026-03-28
**课评内容**
家长好,本周学习的内容是《数组计数》:
1. 数组的定义与初始化
2. 数组遍历方法
3. 计数器原理
4. 数组下标运用
5. 算法思维培养
铭轩这节课表现很棒!看得出来上个星期是有好好完成作业的,对知识点掌握的还不错。这个星期也比较认真,偷偷玩游戏的次数明显减少了,值得表扬!希望铭轩继续保持这种好状态,越来越棒~
加油呀!💪✨
---
## 第3条字符数组
**授课日期**2026-04-05
**课评内容**
铭轩状态在线,表现积极!能够跟着老师的节奏上课,对本节课字符数组的知识点掌握不错,老师看到了你的进步~
不过编程是需要持续练习的,为了防止遗忘,希望铭轩回去之后一定要多多练习。理解字符数组的使用原理,不只是完成作业就好~期待看到铭轩把所学知识转化为熟练的编程能力,加油呀!💪✨
---
## 第7条字符串处理
**授课日期**2026-04-18
**课评内容**
家长好,本周学习的内容是《字符串处理》:
1. 学习getline()函数的使用,掌握读取一整行字符串的方法
2. 学习substr()函数,理解字符串截取的方法和参数含义
3. 学习size() / length()函数,掌握获取字符串长度的方法
4. 学习find()函数,理解字符串查找的原理和返回值
5. 培养学生对字符串处理的综合应用能力和编程思维
魏铭轩状态在线,表现积极,对本周字符串知识掌握很棒,课堂分神次数明显下降,是一个很大的进步,上课特别积极!希望铭轩继续保持,好记性不如烂笔头,一定要多多练习,熟能生巧,把掌握的知识巩固得更扎实。
加油呀!💪✨
---
## 第8条字符串小测与复习
**授课日期**2026-04-25
**课评内容**
家长好,本周我们进行了字符串知识点的小测与复习,主要内容包括:
1. 字符串的声明方法
2. 字符串长度获取与输入输出
3. substr()截取函数和find()查找函数的使用
4. 字符串函数的综合运用
5. 课后复习习惯的培养
从课堂小测结果来看铭轩能够掌握字符串的声明、长度获取和读取等基础知识点这部分做得不错但是对于substr()截取函数、find()查找函数这些稍微复杂一点的函数记得还不够牢固,需要回去认真复习。
老师看到铭轩这学期进步非常大,上课分神的次数明显减少,学习积极性也很高,这点特别值得表扬!以你的聪明程度,只要回去把笔记认真看一看、抄一抄,多花点时间复习,这些函数很快就能记牢。记得"好记性不如烂笔头",多练习才能把知识掌握得更扎实!
加油呀!💪✨
---
## 第9条枚举算法
**授课日期**2026-05-01
**课评内容**
家长好,本周学习的内容是《枚举算法》:
1. 掌握使用自然语言、流程图、伪代码描述算法的方法
2. 理解枚举法的概念与思想,掌握枚举法的基本实现方式
3. 学会枚举法的边界确定,能够合理设置枚举范围
4. 掌握枚举法的优化策略,能够减少不必要的枚举
5. 学会枚举法的代码实现,能够将枚举思想转化为程序代码
铭轩本节课的状态越来越好!能够服从老师的安排,紧跟着老师的节奏完成所有题目,学习积极性很高,老师看到了你的持续进步,非常欣慰!
以你的聪明程度,只要继续保持这种认真的学习状态,课后多花点时间复习巩固本节课的枚举算法知识点,多做练习,一定能把这些知识掌握得很扎实。遇到问题的时候可以多尝试独立调试,慢慢提升自己解决问题的能力,你会越来越优秀的!
加油呀!💪✨
---

View File

@@ -91,3 +91,22 @@
加油呀!💪✨
---
## 第6条枚举算法
**授课日期**2026-05-04
**课评内容**
家长好,本周学习的内容是《枚举算法》:
1. 掌握使用自然语言、流程图、伪代码描述算法的方法
2. 理解枚举法的概念与思想,掌握枚举法的基本实现方式
3. 学会枚举法的边界确定,能够合理设置枚举范围
4. 掌握枚举法的优化策略,能够减少不必要的枚举
5. 学会枚举法的代码实现,能够将枚举思想转化为程序代码
华琛本节课整体状态不错对老师讲的枚举算法知识点能够做出有效的答复学习能力一直在线不过从复习测试中发现华琛对上周的string知识点有些遗忘说明课后复习还需要加强哦。本阶段的知识点会越来越多一定要养成及时复习的好习惯每天花10分钟回顾一下学过的内容把基础打扎实后续学习会更轻松。
加油呀!💪✨
---

View File

@@ -84,3 +84,22 @@
加油呀!💪✨
---
## 第6条枚举算法
**授课日期**2026-05-04
**课评内容**
家长好,本周学习的内容是《枚举算法》:
1. 掌握使用自然语言、流程图、伪代码描述算法的方法
2. 理解枚举法的概念与思想,掌握枚举法的基本实现方式
3. 学会枚举法的边界确定,能够合理设置枚举范围
4. 掌握枚举法的优化策略,能够减少不必要的枚举
5. 学会枚举法的代码实现,能够将枚举思想转化为程序代码
钎宸本节课表现不错能够完成较多的题目做题速度相比之前有所提升这是很大的进步不过老师发现钎宸在课堂上偶尔会开小差注意力不够集中如果能够把专注力再提升一些跟着老师的节奏走学习效果一定会更好。建议在家可以每天练习静坐10分钟慢慢培养专注力相信你会越来越棒的
加油呀!💪✨
---

View File

@@ -84,3 +84,22 @@
加油呀!💪✨
---
## 第9条枚举算法
**授课日期**2026-05-04
**课评内容**
家长好,本周学习的内容是《枚举算法》:
1. 掌握使用自然语言、流程图、伪代码描述算法的方法
2. 理解枚举法的概念与思想,掌握枚举法的基本实现方式
3. 学会枚举法的边界确定,能够合理设置枚举范围
4. 掌握枚举法的优化策略,能够减少不必要的枚举
5. 学会枚举法的代码实现,能够将枚举思想转化为程序代码
佳琳本节课完成了大部分的题目,课堂状态整体不错,对枚举知识能够掌握,这种认真的学习态度值得肯定!枚举算法需要理清思路,一步步去尝试,佳琳的专注力是很适合学习这类算法的。希望佳琳在做题时不要怕出错,先把想到的思路写出来,遇到问题再慢慢调整,相信以你的认真劲儿一定能越做越好!
加油呀!💪✨
---

View File

@@ -9,3 +9,4 @@
| 2026-04-05 | 四季之选 | 第6课 | ✅ 出勤 | |
| 2026-04-17 | 彩虹生成器 | 第8课 | ✅ 出勤 | |
| 2026-04-11 | 我的唱片机 | 第7课 | ✅ 出勤 | |
| 2026-05-01 | 唐诗朗诵会 | 第9课 | ✅ 出勤 | |

View File

@@ -148,3 +148,24 @@
继续加油哦!期待看到你更完美的表现!💪✨
---
## 第9条唐诗朗诵会
**授课日期**2026-05-01
**课评内容**
家长好,本周学习的内容是《唐诗朗诵会》:
1. 复习循环嵌套结构,应用循环嵌套结构实现诗词的展示效果
2. 能够朗诵诗词并录制声音
3. 通过唐诗朗诵会项目的制作,探究循环嵌套结构的综合应用
4. 欣赏古诗词,感受古诗词的魅力,并通过诗词朗诵陶冶性情,开阔胸怀
5. 培养学生的逻辑思维能力和创意表达能力
煜腾上课很活跃,对学习的循环嵌套结构能够理解,特别是能够知道外层循环是做什么工作,内层循环是做什么工作,头脑聪明,反应又快!在制作《唐诗朗诵会》项目时,煜腾能够主动完成任务,表现出很强的学习能力。
做任务的时候会有一点点浮躁,不过老师相信煜腾只要把聪明和耐心结合起来,一定能做出更精致的作品~真正的高手不仅求快,更求好!
继续加油哦!期待看到你更完美的表现!💪✨
---

View File

@@ -9,3 +9,4 @@
| 2026-04-05 | 四季之选 | 第6课 | ✅ 出勤 | |
| 2026-04-17 | 彩虹生成器 | 第8课 | ✅ 出勤 | |
| 2026-04-11 | 我的唱片机 | 第7课 | ✅ 出勤 | |
| 2026-05-01 | 唐诗朗诵会 | 第9课 | ✅ 出勤 | |

View File

@@ -156,3 +156,24 @@
继续加油哦!老师很期待看到你下一个有创意的作品!🌟😊
---
## 第9条唐诗朗诵会
**授课日期**2026-05-01
**课评内容**
家长好,本周学习的内容是《唐诗朗诵会》:
1. 复习循环嵌套结构,应用循环嵌套结构实现诗词的展示效果
2. 能够朗诵诗词并录制声音
3. 通过唐诗朗诵会项目的制作,探究循环嵌套结构的综合应用
4. 欣赏古诗词,感受古诗词的魅力,并通过诗词朗诵陶冶性情,开阔胸怀
5. 培养学生的逻辑思维能力和创意表达能力
晨语做完自己的任务后,可能觉得项目会有一点枯燥,不太愿意继续动手。不过在老师安抚情绪之后,能够静下心来,一点一点地把作品完成,到了回答问题的时候,晨语也可以认真把问题回答出来,这一点很棒!
晨语一直都很有创意,想法天马行空,这是非常宝贵的特质~目前对外层循环和内层循环的区别还有一点点没弄清,后续老师会继续加强循环结构的讲解。要是能更专注一些,把循环结构理解得更透彻,一定会做出更有创意的作品!
继续加油哦!老师很期待看到你下一个有创意的作品!🌟😊
---

View File

@@ -9,3 +9,4 @@
| 2026-04-05 | 四季之选 | 第6课 | ✅ 出勤 | |
| 2026-04-17 | 彩虹生成器 | 第8课 | ✅ 出勤 | |
| 2026-04-11 | 我的唱片机 | 第7课 | ✅ 出勤 | |
| 2026-05-01 | 唐诗朗诵会 | 第9课 | ✅ 出勤 | |

View File

@@ -160,3 +160,24 @@
继续加油哦!期待看到你更棒的表现!🌟💪
---
## 第9条唐诗朗诵会
**授课日期**2026-05-01
**课评内容**
家长好,本周学习的内容是《唐诗朗诵会》:
1. 复习循环嵌套结构,应用循环嵌套结构实现诗词的展示效果
2. 能够朗诵诗词并录制声音
3. 通过唐诗朗诵会项目的制作,探究循环嵌套结构的综合应用
4. 欣赏古诗词,感受古诗词的魅力,并通过诗词朗诵陶冶性情,开阔胸怀
5. 培养学生的逻辑思维能力和创意表达能力
艺嘉对本阶段学习的循环嵌套功能掌握得很扎实,能够很清楚地认识到外层循环是做什么工作,内层循环是做什么工作,整节课的逻辑分析都很清楚!在制作《唐诗朗诵会》项目时,艺嘉能够把循环嵌套的结构运用到诗词展示效果中,思路非常清晰。
艺嘉上课时遇到自己懂的内容,总是敢于大声表达,特别有自信~这种积极的课堂表现非常棒!
继续加油哦!老师会继续关注艺嘉的表现,期待看到你更棒的作品!🌟💪
---

View File

@@ -9,3 +9,4 @@
| 2026-04-05 | 四季之选 | 第6课 | ✅ 出勤 | |
| 2026-04-17 | 彩虹生成器 | 第8课 | ✅ 出勤 | |
| 2026-04-11 | 我的唱片机 | 第7课 | ✅ 出勤 | |
| 2026-05-01 | 唐诗朗诵会 | 第9课 | ✅ 出勤 | |

View File

@@ -154,3 +154,24 @@
继续加油哦!相信你会把程序做得更完整!🌟💡
---
## 第9条唐诗朗诵会
**授课日期**2026-05-01
**课评内容**
家长好,本周学习的内容是《唐诗朗诵会》:
1. 复习循环嵌套结构,应用循环嵌套结构实现诗词的展示效果
2. 能够朗诵诗词并录制声音
3. 通过唐诗朗诵会项目的制作,探究循环嵌套结构的综合应用
4. 欣赏古诗词,感受古诗词的魅力,并通过诗词朗诵陶冶性情,开阔胸怀
5. 培养学生的逻辑思维能力和创意表达能力
圆振可以确保自己的项目能够完成,对本节课学习的循环嵌套有所了解,能够认识到外层循环是做什么工作,内层循环是做什么工作。圆振认真完成了《唐诗朗诵会》的作品,能够把诗词展示效果做出来,特别棒!
作为班里年龄较小的同学,圆振的理解力和反应速度一直都很出色~不过老师发现圆振偶尔会有一点发呆,专注力可以再提升一些。如果能更集中注意力听课,作品一定会做得更完整!
继续加油哦!相信你会把程序做得更完整!
---

View File

@@ -42,7 +42,11 @@
"Bash(start:*)",
"Bash(start \"\" \".claude-design\\\\slide-previews\\\\style-c.html\")",
"Bash(findstr:*)",
"Bash(tree:*)"
"Bash(tree:*)",
"Bash(curl *)",
"Bash(python *)",
"Bash(node index.js 2026-04-24 2026-04-26)",
"Bash(node *)"
]
}
}

View File

@@ -0,0 +1,145 @@
# 教学日程查询 Skill 使用说明
## 功能概述
本技能**直接调用公司API获取实时教学排课数据**,支持查询指定日期或时间段的课程安排,自动生成功能完整的互动网页,帮助老师快速查询授课安排,查看学生名单和出勤情况,支持单天查询和任意时间段查询两种模式。
## 环境配置
### 1. 依赖安装
首次使用前需要安装技能依赖:
```bash
cd .claude/skills/教学日程查询
npm install
```
### 2. API配置
确保项目根目录下的 `.env` 文件包含正确的API配置
```env
# 公司API地址
API_BASE_URL=https://api.qonnwolf.com/api/v1
# API认证令牌
AUTHORIZATION=Bearer your_token_here
# 默认查询的老师姓名
EMPLOYEE_NAME=橙子(程城)
```
## 快速开始
### 1. 调用技能
在Claude Code对话中输入支持多种日期格式
```
# 方式1查询单天
/教学日程查询 # 查询当天日程
/教学日程查询 2026-04-28 # 标准格式
/教学日程查询 2026/04/28 # 斜杠格式
/教学日程查询 20260428 # 纯数字格式
/教学日程查询 4月28日 # 中文格式
/教学日程查询 04-28 # 短格式(默认当前年份)
# 方式2查询时间段
/教学日程查询 2026-04-01 2026-04-30 # 查询4月整个月的日程
/教学日程查询 4月24日 4月26日 # 中文格式时间段
/教学日程查询 20260422 20260428 # 纯数字格式时间段
```
### 2. 查看结果
技能执行完成后会返回网页链接,点击链接即可打开互动网页查看详细信息。
## 网页功能说明
### 顶部功能区
- **日期范围显示**:显示当前查询的日期范围和总天数
- **搜索框**:输入日期、班级名称或学生姓名进行全局快速搜索
- **导出按钮**点击导出整个时间段的课表为Excel文件
- **视图切换**:支持「按日期」和「按班级」两种视图模式一键切换
### 统计面板
- 展示查询范围内的总天数、总课程数、总学生人次
- 汇总出勤人次、缺勤人次,直观展示整体出勤情况
### 课表展示区
#### 按日期视图(默认)
- 按日期分组展示,每天的课程独立排列
- 日期头部粘性定位,滚动时始终可见
- 每个日期组显示当日的课程数量、学生人次和出勤统计
- 课程按时间顺序排列,每个课程以卡片形式展示
- 卡片显示:班级名称、授课时间、授课老师、学生人数、出勤统计
- 点击卡片展开查看该班级的详细学生名单
#### 按班级视图
- 按班级分组展示,同一个班级的所有课程集中排列
- 每个班级组显示课程次数和时间范围
- 方便查看同一个班级在整个时间段内的所有上课情况
### 学生名单
- 表格展示学生姓名和出勤状态
- 出勤状态标识:
- ✅ 出勤:正常上课
- ⏸ 请假:已请假
- ❌ 缺勤:未上课
- 支持按出勤状态筛选学生
### 导出功能
导出的Excel文件包含以下信息
- 课程日期
- 班级名称
- 授课时间
- 授课老师
- 教室
- 学生姓名
- 出勤状态
- 备注信息
* 时间段查询会导出所有日期的完整数据,自动按日期排序
## 目录结构
```
教学日程查询/
├── index.js # 主程序文件处理API调用和网页生成
├── package.json # 依赖配置文件
├── skill.md # Claude技能定义文件
├── template.html # 网页模板文件
└── README.md # 使用说明文档
```
## 输出目录
生成的文件保存在:
```
# 单天查询
.claude/output/teaching-schedule/2026-04-28/
├── schedule.html # 互动网页
└── schedule.json # 原始API数据
# 时间段查询
.claude/output/teaching-schedule/2026-04-01_2026-04-30/
├── schedule.html # 互动网页
└── schedule.json # 原始API数据包含多天的完整数据
```
## 常见问题
### Q: API调用失败提示认证失败
A: 请检查项目根目录下 `.env` 文件中的 `AUTHORIZATION` 配置是否正确,令牌是否过期。
### Q: API调用失败提示网络错误
A: 请检查网络连接是否正常是否能够访问公司API地址或者稍后重试。如果问题持续存在请联系技术支持。
### Q: 为什么没有数据?
A: 可能是查询的日期没有排课或者API返回数据为空。可以尝试查询其他日期或者检查 `EMPLOYEE_NAME` 配置是否正确。
### Q: 导出的Excel文件打不开
A: 请确保使用支持.xlsx格式的办公软件打开如Microsoft Excel、WPS等。
### Q: 可以查询其他老师的课表吗?
A: 可以修改 `.env` 文件中的 `EMPLOYEE_NAME` 配置为要查询的老师姓名,支持模糊匹配。
## 更新日志
### v1.1.0 (2026-04-28)
- ✨ 新增时间段查询功能,支持查询任意起止日期范围内的所有日程
- ✨ 新增双视图展示模式:按日期视图、按班级视图,一键切换
- ✨ 升级统计面板,展示总天数、总课程数、总学生人次等汇总信息
- ✨ 搜索功能升级,支持按日期、班级、学生姓名全局搜索
- ✨ 导出功能升级,支持导出整个时间段的完整数据
- ✨ 优化界面设计,日期分组头部支持粘性定位,滚动浏览更方便
- ♻️ 重构数据处理逻辑,支持多天数据的合并和展示
### v1.0.0 (2026-04-28)
- 初始版本发布
- 支持基础的单天日程查询功能
- 支持搜索、筛选、导出Excel功能
- 响应式界面设计

View File

@@ -0,0 +1,222 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const axios = require('axios');
require('dotenv').config({ path: path.join(__dirname, '../../../.env') });
// API配置
const API_BASE_URL = process.env.API_BASE_URL || 'https://api.qonnwolf.com/api/v1';
const AUTHORIZATION = process.env.AUTHORIZATION || '';
const TEACHER_NAME = process.env.EMPLOYEE_NAME || '橙子(程城)';
// 日期处理工具函数
function formatDate(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
function parseDate(dateStr) {
// 支持多种日期格式2026-04-24、2026/04/24、20260424、04-24、4月24日等
dateStr = dateStr.replace(/年|月/g, '-').replace(/日/g, '');
// 如果是短日期,默认使用当前年份
if (/^\d{1,2}-\d{1,2}$/.test(dateStr)) {
const currentYear = new Date().getFullYear();
dateStr = `${currentYear}-${dateStr}`;
}
// 处理纯数字格式
if (/^\d{8}$/.test(dateStr)) {
dateStr = `${dateStr.slice(0, 4)}-${dateStr.slice(4, 6)}-${dateStr.slice(6, 8)}`;
}
// 替换斜杠为横杠
dateStr = dateStr.replace(/\//g, '-');
const date = new Date(dateStr);
if (isNaN(date.getTime())) {
throw new Error(`无效的日期格式:${dateStr}请使用YYYY-MM-DD格式`);
}
return date;
}
function getDateRange(startDateStr, endDateStr) {
const startDate = parseDate(startDateStr);
const endDate = endDateStr ? parseDate(endDateStr) : startDate;
if (startDate > endDate) {
throw new Error('开始日期不能晚于结束日期');
}
const dates = [];
const currentDate = new Date(startDate);
while (currentDate <= endDate) {
dates.push(formatDate(currentDate));
currentDate.setDate(currentDate.getDate() + 1);
}
return dates;
}
// 调用API获取单天数据
async function fetchSchedule(date) {
try {
console.log(`正在获取 ${date} 的教学日程数据...`);
const response = await axios.get(`${API_BASE_URL}/reports/teaching-schedule`, {
headers: {
'Authorization': AUTHORIZATION
},
params: {
teaching_date: date,
teacher_name: TEACHER_NAME
}
});
if (response.data.code !== 0) {
throw new Error(`API返回错误${response.data.message}`);
}
const data = response.data.data;
return {
teaching_date: date,
items: data.items.map(item => ({
class_id: item.class_id,
class_name: item.class_name,
start_time: item.teaching_time_period.split('-')[0].trim(),
end_time: item.teaching_time_period.split('-')[1].trim(),
teacher_name: item.teacher_name,
classroom: item.school_name,
students: item.student_names.map(name => {
// 先默认都是出勤,后续可以根据实际出勤数据调整
return {
student_name: name,
attendance_status: '✅ 出勤',
remark: ''
};
})
}))
};
} catch (error) {
console.error(`获取 ${date} 数据失败:`, error.message);
throw error;
}
}
// 批量获取日期范围内的数据
async function fetchScheduleRange(dates) {
const scheduleData = [];
for (const date of dates) {
const data = await fetchSchedule(date);
scheduleData.push(data);
}
return scheduleData;
}
// 生成HTML文件
function generateHTML(scheduleData, startDate, endDate) {
// 读取模板文件
const templatePath = path.join(__dirname, 'template.html');
let template = fs.readFileSync(templatePath, 'utf-8');
// 生成日期范围显示文本
const dateRangeText = startDate === endDate ? startDate : `${startDate}${endDate}`;
const updateTime = formatDate(new Date()) + ' ' + new Date().toTimeString().slice(0, 5);
// 替换模板中的占位符
template = template.replace(/{{dateRange}}/g, dateRangeText);
template = template.replace(/{{updateTime}}/g, updateTime);
template = template.replace(/{{totalDays}}/g, scheduleData.length);
template = template.replace(/const scheduleData = {{scheduleData}};/, `const scheduleData = ${JSON.stringify(scheduleData, null, 2)};`);
// 确保输出目录存在
const outputDir = path.join(__dirname, `../../../output/teaching-schedule/${dateRangeText.replace(/ 至 /g, '_')}`);
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
// 写入HTML文件
const htmlPath = path.join(outputDir, 'schedule.html');
fs.writeFileSync(htmlPath, template, 'utf-8');
// 写入JSON数据文件
const jsonPath = path.join(outputDir, 'schedule.json');
fs.writeFileSync(jsonPath, JSON.stringify(scheduleData, null, 2), 'utf-8');
return {
htmlPath,
jsonPath,
outputDir,
dateRangeText
};
}
// 主函数
async function main() {
try {
// 解析命令行参数
const args = process.argv.slice(2);
let startDateStr, endDateStr;
if (args.length === 0) {
// 默认查询今天
const today = new Date();
startDateStr = formatDate(today);
endDateStr = startDateStr;
} else if (args.length === 1) {
// 查询单天
startDateStr = args[0];
endDateStr = startDateStr;
} else {
// 查询时间段
startDateStr = args[0];
endDateStr = args[1];
}
// 获取日期范围
const dates = getDateRange(startDateStr, endDateStr);
const startDate = dates[0];
const endDate = dates[dates.length - 1];
console.log(`查询日期范围:${startDate}${endDate}`);
console.log(`${dates.length}`);
// 获取数据
const scheduleData = await fetchScheduleRange(dates);
// 统计信息
const totalClasses = scheduleData.reduce((sum, day) => sum + day.items.length, 0);
const totalStudents = scheduleData.reduce((sum, day) => {
return sum + day.items.reduce((daySum, cls) => daySum + cls.students.length, 0);
}, 0);
console.log(`查询完成:共 ${totalClasses} 节课,${totalStudents} 人次`);
// 生成HTML
const result = generateHTML(scheduleData, startDate, endDate);
console.log('');
console.log('✅ 教学日程生成成功!');
console.log('📁 输出目录:', result.outputDir);
console.log('📄 网页文件:', result.htmlPath);
console.log('📊 数据文件:', result.jsonPath);
console.log('');
console.log('直接打开schedule.html文件即可查看教学日程');
} catch (error) {
console.error('❌ 生成失败:', error.message);
process.exit(1);
}
}
// 运行主函数
if (require.main === module) {
main();
}
module.exports = {
fetchSchedule,
fetchScheduleRange,
generateHTML
};

View File

@@ -0,0 +1,302 @@
{
"name": "teaching-schedule-query",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"license": "MIT"
},
"node_modules/axios": {
"version": "1.15.2",
"resolved": "https://registry.npmmirror.com/axios/-/axios-1.15.2.tgz",
"integrity": "sha512-wLrXxPtcrPTsNlJmKjkPnNPK2Ihe0hn0wGSaTEiHRPxwjvJwT3hKmXF4dpqxmPO9SoNb2FsYXj/xEo0gHN+D5A==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.11",
"form-data": "^4.0.5",
"proxy-from-env": "^2.1.0"
}
},
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"license": "MIT",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"license": "MIT",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/dotenv": {
"version": "16.6.1",
"resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-16.6.1.tgz",
"integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://dotenvx.com"
}
},
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"es-errors": "^1.3.0",
"gopd": "^1.2.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-errors": {
"version": "1.3.0",
"resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-object-atoms": {
"version": "1.1.1",
"resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-set-tostringtag": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6",
"has-tostringtag": "^1.0.2",
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/follow-redirects": {
"version": "1.16.0",
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.16.0.tgz",
"integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.5",
"resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.5.tgz",
"integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.1.1",
"function-bind": "^1.1.2",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
"math-intrinsics": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-tostringtag": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hasown": {
"version": "2.0.3",
"resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.3.tgz",
"integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==",
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/proxy-from-env": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-2.1.0.tgz",
"integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==",
"license": "MIT",
"engines": {
"node": ">=10"
}
}
}
}

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Alex Indigo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,233 @@
# asynckit [![NPM Module](https://img.shields.io/npm/v/asynckit.svg?style=flat)](https://www.npmjs.com/package/asynckit)
Minimal async jobs utility library, with streams support.
[![PhantomJS Build](https://img.shields.io/travis/alexindigo/asynckit/v0.4.0.svg?label=browser&style=flat)](https://travis-ci.org/alexindigo/asynckit)
[![Linux Build](https://img.shields.io/travis/alexindigo/asynckit/v0.4.0.svg?label=linux:0.12-6.x&style=flat)](https://travis-ci.org/alexindigo/asynckit)
[![Windows Build](https://img.shields.io/appveyor/ci/alexindigo/asynckit/v0.4.0.svg?label=windows:0.12-6.x&style=flat)](https://ci.appveyor.com/project/alexindigo/asynckit)
[![Coverage Status](https://img.shields.io/coveralls/alexindigo/asynckit/v0.4.0.svg?label=code+coverage&style=flat)](https://coveralls.io/github/alexindigo/asynckit?branch=master)
[![Dependency Status](https://img.shields.io/david/alexindigo/asynckit/v0.4.0.svg?style=flat)](https://david-dm.org/alexindigo/asynckit)
[![bitHound Overall Score](https://www.bithound.io/github/alexindigo/asynckit/badges/score.svg)](https://www.bithound.io/github/alexindigo/asynckit)
<!-- [![Readme](https://img.shields.io/badge/readme-tested-brightgreen.svg?style=flat)](https://www.npmjs.com/package/reamde) -->
AsyncKit provides harness for `parallel` and `serial` iterators over list of items represented by arrays or objects.
Optionally it accepts abort function (should be synchronously return by iterator for each item), and terminates left over jobs upon an error event. For specific iteration order built-in (`ascending` and `descending`) and custom sort helpers also supported, via `asynckit.serialOrdered` method.
It ensures async operations to keep behavior more stable and prevent `Maximum call stack size exceeded` errors, from sync iterators.
| compression | size |
| :----------------- | -------: |
| asynckit.js | 12.34 kB |
| asynckit.min.js | 4.11 kB |
| asynckit.min.js.gz | 1.47 kB |
## Install
```sh
$ npm install --save asynckit
```
## Examples
### Parallel Jobs
Runs iterator over provided array in parallel. Stores output in the `result` array,
on the matching positions. In unlikely event of an error from one of the jobs,
will terminate rest of the active jobs (if abort function is provided)
and return error along with salvaged data to the main callback function.
#### Input Array
```javascript
var parallel = require('asynckit').parallel
, assert = require('assert')
;
var source = [ 1, 1, 4, 16, 64, 32, 8, 2 ]
, expectedResult = [ 2, 2, 8, 32, 128, 64, 16, 4 ]
, expectedTarget = [ 1, 1, 2, 4, 8, 16, 32, 64 ]
, target = []
;
parallel(source, asyncJob, function(err, result)
{
assert.deepEqual(result, expectedResult);
assert.deepEqual(target, expectedTarget);
});
// async job accepts one element from the array
// and a callback function
function asyncJob(item, cb)
{
// different delays (in ms) per item
var delay = item * 25;
// pretend different jobs take different time to finish
// and not in consequential order
var timeoutId = setTimeout(function() {
target.push(item);
cb(null, item * 2);
}, delay);
// allow to cancel "leftover" jobs upon error
// return function, invoking of which will abort this job
return clearTimeout.bind(null, timeoutId);
}
```
More examples could be found in [test/test-parallel-array.js](test/test-parallel-array.js).
#### Input Object
Also it supports named jobs, listed via object.
```javascript
var parallel = require('asynckit/parallel')
, assert = require('assert')
;
var source = { first: 1, one: 1, four: 4, sixteen: 16, sixtyFour: 64, thirtyTwo: 32, eight: 8, two: 2 }
, expectedResult = { first: 2, one: 2, four: 8, sixteen: 32, sixtyFour: 128, thirtyTwo: 64, eight: 16, two: 4 }
, expectedTarget = [ 1, 1, 2, 4, 8, 16, 32, 64 ]
, expectedKeys = [ 'first', 'one', 'two', 'four', 'eight', 'sixteen', 'thirtyTwo', 'sixtyFour' ]
, target = []
, keys = []
;
parallel(source, asyncJob, function(err, result)
{
assert.deepEqual(result, expectedResult);
assert.deepEqual(target, expectedTarget);
assert.deepEqual(keys, expectedKeys);
});
// supports full value, key, callback (shortcut) interface
function asyncJob(item, key, cb)
{
// different delays (in ms) per item
var delay = item * 25;
// pretend different jobs take different time to finish
// and not in consequential order
var timeoutId = setTimeout(function() {
keys.push(key);
target.push(item);
cb(null, item * 2);
}, delay);
// allow to cancel "leftover" jobs upon error
// return function, invoking of which will abort this job
return clearTimeout.bind(null, timeoutId);
}
```
More examples could be found in [test/test-parallel-object.js](test/test-parallel-object.js).
### Serial Jobs
Runs iterator over provided array sequentially. Stores output in the `result` array,
on the matching positions. In unlikely event of an error from one of the jobs,
will not proceed to the rest of the items in the list
and return error along with salvaged data to the main callback function.
#### Input Array
```javascript
var serial = require('asynckit/serial')
, assert = require('assert')
;
var source = [ 1, 1, 4, 16, 64, 32, 8, 2 ]
, expectedResult = [ 2, 2, 8, 32, 128, 64, 16, 4 ]
, expectedTarget = [ 0, 1, 2, 3, 4, 5, 6, 7 ]
, target = []
;
serial(source, asyncJob, function(err, result)
{
assert.deepEqual(result, expectedResult);
assert.deepEqual(target, expectedTarget);
});
// extended interface (item, key, callback)
// also supported for arrays
function asyncJob(item, key, cb)
{
target.push(key);
// it will be automatically made async
// even it iterator "returns" in the same event loop
cb(null, item * 2);
}
```
More examples could be found in [test/test-serial-array.js](test/test-serial-array.js).
#### Input Object
Also it supports named jobs, listed via object.
```javascript
var serial = require('asynckit').serial
, assert = require('assert')
;
var source = [ 1, 1, 4, 16, 64, 32, 8, 2 ]
, expectedResult = [ 2, 2, 8, 32, 128, 64, 16, 4 ]
, expectedTarget = [ 0, 1, 2, 3, 4, 5, 6, 7 ]
, target = []
;
var source = { first: 1, one: 1, four: 4, sixteen: 16, sixtyFour: 64, thirtyTwo: 32, eight: 8, two: 2 }
, expectedResult = { first: 2, one: 2, four: 8, sixteen: 32, sixtyFour: 128, thirtyTwo: 64, eight: 16, two: 4 }
, expectedTarget = [ 1, 1, 4, 16, 64, 32, 8, 2 ]
, target = []
;
serial(source, asyncJob, function(err, result)
{
assert.deepEqual(result, expectedResult);
assert.deepEqual(target, expectedTarget);
});
// shortcut interface (item, callback)
// works for object as well as for the arrays
function asyncJob(item, cb)
{
target.push(item);
// it will be automatically made async
// even it iterator "returns" in the same event loop
cb(null, item * 2);
}
```
More examples could be found in [test/test-serial-object.js](test/test-serial-object.js).
_Note: Since _object_ is an _unordered_ collection of properties,
it may produce unexpected results with sequential iterations.
Whenever order of the jobs' execution is important please use `serialOrdered` method._
### Ordered Serial Iterations
TBD
For example [compare-property](compare-property) package.
### Streaming interface
TBD
## Want to Know More?
More examples can be found in [test folder](test/).
Or open an [issue](https://github.com/alexindigo/asynckit/issues) with questions and/or suggestions.
## License
AsyncKit is licensed under the MIT license.

View File

@@ -0,0 +1,76 @@
/* eslint no-console: "off" */
var asynckit = require('./')
, async = require('async')
, assert = require('assert')
, expected = 0
;
var Benchmark = require('benchmark');
var suite = new Benchmark.Suite;
var source = [];
for (var z = 1; z < 100; z++)
{
source.push(z);
expected += z;
}
suite
// add tests
.add('async.map', function(deferred)
{
var total = 0;
async.map(source,
function(i, cb)
{
setImmediate(function()
{
total += i;
cb(null, total);
});
},
function(err, result)
{
assert.ifError(err);
assert.equal(result[result.length - 1], expected);
deferred.resolve();
});
}, {'defer': true})
.add('asynckit.parallel', function(deferred)
{
var total = 0;
asynckit.parallel(source,
function(i, cb)
{
setImmediate(function()
{
total += i;
cb(null, total);
});
},
function(err, result)
{
assert.ifError(err);
assert.equal(result[result.length - 1], expected);
deferred.resolve();
});
}, {'defer': true})
// add listeners
.on('cycle', function(ev)
{
console.log(String(ev.target));
})
.on('complete', function()
{
console.log('Fastest is ' + this.filter('fastest').map('name'));
})
// run async
.run({ 'async': true });

View File

@@ -0,0 +1,6 @@
module.exports =
{
parallel : require('./parallel.js'),
serial : require('./serial.js'),
serialOrdered : require('./serialOrdered.js')
};

View File

@@ -0,0 +1,29 @@
// API
module.exports = abort;
/**
* Aborts leftover active jobs
*
* @param {object} state - current state object
*/
function abort(state)
{
Object.keys(state.jobs).forEach(clean.bind(state));
// reset leftover jobs
state.jobs = {};
}
/**
* Cleans up leftover job by invoking abort function for the provided job id
*
* @this state
* @param {string|number} key - job id to abort
*/
function clean(key)
{
if (typeof this.jobs[key] == 'function')
{
this.jobs[key]();
}
}

View File

@@ -0,0 +1,34 @@
var defer = require('./defer.js');
// API
module.exports = async;
/**
* Runs provided callback asynchronously
* even if callback itself is not
*
* @param {function} callback - callback to invoke
* @returns {function} - augmented callback
*/
function async(callback)
{
var isAsync = false;
// check if async happened
defer(function() { isAsync = true; });
return function async_callback(err, result)
{
if (isAsync)
{
callback(err, result);
}
else
{
defer(function nextTick_callback()
{
callback(err, result);
});
}
};
}

View File

@@ -0,0 +1,26 @@
module.exports = defer;
/**
* Runs provided function on next iteration of the event loop
*
* @param {function} fn - function to run
*/
function defer(fn)
{
var nextTick = typeof setImmediate == 'function'
? setImmediate
: (
typeof process == 'object' && typeof process.nextTick == 'function'
? process.nextTick
: null
);
if (nextTick)
{
nextTick(fn);
}
else
{
setTimeout(fn, 0);
}
}

View File

@@ -0,0 +1,75 @@
var async = require('./async.js')
, abort = require('./abort.js')
;
// API
module.exports = iterate;
/**
* Iterates over each job object
*
* @param {array|object} list - array or object (named list) to iterate over
* @param {function} iterator - iterator to run
* @param {object} state - current job status
* @param {function} callback - invoked when all elements processed
*/
function iterate(list, iterator, state, callback)
{
// store current index
var key = state['keyedList'] ? state['keyedList'][state.index] : state.index;
state.jobs[key] = runJob(iterator, key, list[key], function(error, output)
{
// don't repeat yourself
// skip secondary callbacks
if (!(key in state.jobs))
{
return;
}
// clean up jobs
delete state.jobs[key];
if (error)
{
// don't process rest of the results
// stop still active jobs
// and reset the list
abort(state);
}
else
{
state.results[key] = output;
}
// return salvaged results
callback(error, state.results);
});
}
/**
* Runs iterator over provided job element
*
* @param {function} iterator - iterator to invoke
* @param {string|number} key - key/index of the element in the list of jobs
* @param {mixed} item - job description
* @param {function} callback - invoked after iterator is done with the job
* @returns {function|mixed} - job abort function or something else
*/
function runJob(iterator, key, item, callback)
{
var aborter;
// allow shortcut if iterator expects only two arguments
if (iterator.length == 2)
{
aborter = iterator(item, async(callback));
}
// otherwise go with full three arguments
else
{
aborter = iterator(item, key, async(callback));
}
return aborter;
}

View File

@@ -0,0 +1,91 @@
var streamify = require('./streamify.js')
, defer = require('./defer.js')
;
// API
module.exports = ReadableAsyncKit;
/**
* Base constructor for all streams
* used to hold properties/methods
*/
function ReadableAsyncKit()
{
ReadableAsyncKit.super_.apply(this, arguments);
// list of active jobs
this.jobs = {};
// add stream methods
this.destroy = destroy;
this._start = _start;
this._read = _read;
}
/**
* Destroys readable stream,
* by aborting outstanding jobs
*
* @returns {void}
*/
function destroy()
{
if (this.destroyed)
{
return;
}
this.destroyed = true;
if (typeof this.terminator == 'function')
{
this.terminator();
}
}
/**
* Starts provided jobs in async manner
*
* @private
*/
function _start()
{
// first argument runner function
var runner = arguments[0]
// take away first argument
, args = Array.prototype.slice.call(arguments, 1)
// second argument - input data
, input = args[0]
// last argument - result callback
, endCb = streamify.callback.call(this, args[args.length - 1])
;
args[args.length - 1] = endCb;
// third argument - iterator
args[1] = streamify.iterator.call(this, args[1]);
// allow time for proper setup
defer(function()
{
if (!this.destroyed)
{
this.terminator = runner.apply(null, args);
}
else
{
endCb(null, Array.isArray(input) ? [] : {});
}
}.bind(this));
}
/**
* Implement _read to comply with Readable streams
* Doesn't really make sense for flowing object mode
*
* @private
*/
function _read()
{
}

View File

@@ -0,0 +1,25 @@
var parallel = require('../parallel.js');
// API
module.exports = ReadableParallel;
/**
* Streaming wrapper to `asynckit.parallel`
*
* @param {array|object} list - array or object (named list) to iterate over
* @param {function} iterator - iterator to run
* @param {function} callback - invoked when all elements processed
* @returns {stream.Readable#}
*/
function ReadableParallel(list, iterator, callback)
{
if (!(this instanceof ReadableParallel))
{
return new ReadableParallel(list, iterator, callback);
}
// turn on object mode
ReadableParallel.super_.call(this, {objectMode: true});
this._start(parallel, list, iterator, callback);
}

View File

@@ -0,0 +1,25 @@
var serial = require('../serial.js');
// API
module.exports = ReadableSerial;
/**
* Streaming wrapper to `asynckit.serial`
*
* @param {array|object} list - array or object (named list) to iterate over
* @param {function} iterator - iterator to run
* @param {function} callback - invoked when all elements processed
* @returns {stream.Readable#}
*/
function ReadableSerial(list, iterator, callback)
{
if (!(this instanceof ReadableSerial))
{
return new ReadableSerial(list, iterator, callback);
}
// turn on object mode
ReadableSerial.super_.call(this, {objectMode: true});
this._start(serial, list, iterator, callback);
}

View File

@@ -0,0 +1,29 @@
var serialOrdered = require('../serialOrdered.js');
// API
module.exports = ReadableSerialOrdered;
// expose sort helpers
module.exports.ascending = serialOrdered.ascending;
module.exports.descending = serialOrdered.descending;
/**
* Streaming wrapper to `asynckit.serialOrdered`
*
* @param {array|object} list - array or object (named list) to iterate over
* @param {function} iterator - iterator to run
* @param {function} sortMethod - custom sort function
* @param {function} callback - invoked when all elements processed
* @returns {stream.Readable#}
*/
function ReadableSerialOrdered(list, iterator, sortMethod, callback)
{
if (!(this instanceof ReadableSerialOrdered))
{
return new ReadableSerialOrdered(list, iterator, sortMethod, callback);
}
// turn on object mode
ReadableSerialOrdered.super_.call(this, {objectMode: true});
this._start(serialOrdered, list, iterator, sortMethod, callback);
}

View File

@@ -0,0 +1,37 @@
// API
module.exports = state;
/**
* Creates initial state object
* for iteration over list
*
* @param {array|object} list - list to iterate over
* @param {function|null} sortMethod - function to use for keys sort,
* or `null` to keep them as is
* @returns {object} - initial state object
*/
function state(list, sortMethod)
{
var isNamedList = !Array.isArray(list)
, initState =
{
index : 0,
keyedList: isNamedList || sortMethod ? Object.keys(list) : null,
jobs : {},
results : isNamedList ? {} : [],
size : isNamedList ? Object.keys(list).length : list.length
}
;
if (sortMethod)
{
// sort array keys based on it's values
// sort object's keys just on own merit
initState.keyedList.sort(isNamedList ? sortMethod : function(a, b)
{
return sortMethod(list[a], list[b]);
});
}
return initState;
}

View File

@@ -0,0 +1,141 @@
var async = require('./async.js');
// API
module.exports = {
iterator: wrapIterator,
callback: wrapCallback
};
/**
* Wraps iterators with long signature
*
* @this ReadableAsyncKit#
* @param {function} iterator - function to wrap
* @returns {function} - wrapped function
*/
function wrapIterator(iterator)
{
var stream = this;
return function(item, key, cb)
{
var aborter
, wrappedCb = async(wrapIteratorCallback.call(stream, cb, key))
;
stream.jobs[key] = wrappedCb;
// it's either shortcut (item, cb)
if (iterator.length == 2)
{
aborter = iterator(item, wrappedCb);
}
// or long format (item, key, cb)
else
{
aborter = iterator(item, key, wrappedCb);
}
return aborter;
};
}
/**
* Wraps provided callback function
* allowing to execute snitch function before
* real callback
*
* @this ReadableAsyncKit#
* @param {function} callback - function to wrap
* @returns {function} - wrapped function
*/
function wrapCallback(callback)
{
var stream = this;
var wrapped = function(error, result)
{
return finisher.call(stream, error, result, callback);
};
return wrapped;
}
/**
* Wraps provided iterator callback function
* makes sure snitch only called once,
* but passes secondary calls to the original callback
*
* @this ReadableAsyncKit#
* @param {function} callback - callback to wrap
* @param {number|string} key - iteration key
* @returns {function} wrapped callback
*/
function wrapIteratorCallback(callback, key)
{
var stream = this;
return function(error, output)
{
// don't repeat yourself
if (!(key in stream.jobs))
{
callback(error, output);
return;
}
// clean up jobs
delete stream.jobs[key];
return streamer.call(stream, error, {key: key, value: output}, callback);
};
}
/**
* Stream wrapper for iterator callback
*
* @this ReadableAsyncKit#
* @param {mixed} error - error response
* @param {mixed} output - iterator output
* @param {function} callback - callback that expects iterator results
*/
function streamer(error, output, callback)
{
if (error && !this.error)
{
this.error = error;
this.pause();
this.emit('error', error);
// send back value only, as expected
callback(error, output && output.value);
return;
}
// stream stuff
this.push(output);
// back to original track
// send back value only, as expected
callback(error, output && output.value);
}
/**
* Stream wrapper for finishing callback
*
* @this ReadableAsyncKit#
* @param {mixed} error - error response
* @param {mixed} output - iterator output
* @param {function} callback - callback that expects final results
*/
function finisher(error, output, callback)
{
// signal end of the stream
// only for successfully finished streams
if (!error)
{
this.push(null);
}
// back to original track
callback(error, output);
}

View File

@@ -0,0 +1,29 @@
var abort = require('./abort.js')
, async = require('./async.js')
;
// API
module.exports = terminator;
/**
* Terminates jobs in the attached state context
*
* @this AsyncKitState#
* @param {function} callback - final callback to invoke after termination
*/
function terminator(callback)
{
if (!Object.keys(this.jobs).length)
{
return;
}
// fast forward iteration index
this.index = this.size;
// abort jobs
abort(this);
// send back results we have so far
async(callback)(null, this.results);
}

View File

@@ -0,0 +1,63 @@
{
"name": "asynckit",
"version": "0.4.0",
"description": "Minimal async jobs utility library, with streams support",
"main": "index.js",
"scripts": {
"clean": "rimraf coverage",
"lint": "eslint *.js lib/*.js test/*.js",
"test": "istanbul cover --reporter=json tape -- 'test/test-*.js' | tap-spec",
"win-test": "tape test/test-*.js",
"browser": "browserify -t browserify-istanbul test/lib/browserify_adjustment.js test/test-*.js | obake --coverage | tap-spec",
"report": "istanbul report",
"size": "browserify index.js | size-table asynckit",
"debug": "tape test/test-*.js"
},
"pre-commit": [
"clean",
"lint",
"test",
"browser",
"report",
"size"
],
"repository": {
"type": "git",
"url": "git+https://github.com/alexindigo/asynckit.git"
},
"keywords": [
"async",
"jobs",
"parallel",
"serial",
"iterator",
"array",
"object",
"stream",
"destroy",
"terminate",
"abort"
],
"author": "Alex Indigo <iam@alexindigo.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/alexindigo/asynckit/issues"
},
"homepage": "https://github.com/alexindigo/asynckit#readme",
"devDependencies": {
"browserify": "^13.0.0",
"browserify-istanbul": "^2.0.0",
"coveralls": "^2.11.9",
"eslint": "^2.9.0",
"istanbul": "^0.4.3",
"obake": "^0.1.2",
"phantomjs-prebuilt": "^2.1.7",
"pre-commit": "^1.1.3",
"reamde": "^1.1.0",
"rimraf": "^2.5.2",
"size-table": "^0.2.0",
"tap-spec": "^4.1.1",
"tape": "^4.5.1"
},
"dependencies": {}
}

View File

@@ -0,0 +1,43 @@
var iterate = require('./lib/iterate.js')
, initState = require('./lib/state.js')
, terminator = require('./lib/terminator.js')
;
// Public API
module.exports = parallel;
/**
* Runs iterator over provided array elements in parallel
*
* @param {array|object} list - array or object (named list) to iterate over
* @param {function} iterator - iterator to run
* @param {function} callback - invoked when all elements processed
* @returns {function} - jobs terminator
*/
function parallel(list, iterator, callback)
{
var state = initState(list);
while (state.index < (state['keyedList'] || list).length)
{
iterate(list, iterator, state, function(error, result)
{
if (error)
{
callback(error, result);
return;
}
// looks like it's the last one
if (Object.keys(state.jobs).length === 0)
{
callback(null, state.results);
return;
}
});
state.index++;
}
return terminator.bind(state, callback);
}

View File

@@ -0,0 +1,17 @@
var serialOrdered = require('./serialOrdered.js');
// Public API
module.exports = serial;
/**
* Runs iterator over provided array elements in series
*
* @param {array|object} list - array or object (named list) to iterate over
* @param {function} iterator - iterator to run
* @param {function} callback - invoked when all elements processed
* @returns {function} - jobs terminator
*/
function serial(list, iterator, callback)
{
return serialOrdered(list, iterator, null, callback);
}

View File

@@ -0,0 +1,75 @@
var iterate = require('./lib/iterate.js')
, initState = require('./lib/state.js')
, terminator = require('./lib/terminator.js')
;
// Public API
module.exports = serialOrdered;
// sorting helpers
module.exports.ascending = ascending;
module.exports.descending = descending;
/**
* Runs iterator over provided sorted array elements in series
*
* @param {array|object} list - array or object (named list) to iterate over
* @param {function} iterator - iterator to run
* @param {function} sortMethod - custom sort function
* @param {function} callback - invoked when all elements processed
* @returns {function} - jobs terminator
*/
function serialOrdered(list, iterator, sortMethod, callback)
{
var state = initState(list, sortMethod);
iterate(list, iterator, state, function iteratorHandler(error, result)
{
if (error)
{
callback(error, result);
return;
}
state.index++;
// are we there yet?
if (state.index < (state['keyedList'] || list).length)
{
iterate(list, iterator, state, iteratorHandler);
return;
}
// done here
callback(null, state.results);
});
return terminator.bind(state, callback);
}
/*
* -- Sort methods
*/
/**
* sort helper to sort array elements in ascending order
*
* @param {mixed} a - an item to compare
* @param {mixed} b - an item to compare
* @returns {number} - comparison result
*/
function ascending(a, b)
{
return a < b ? -1 : a > b ? 1 : 0;
}
/**
* sort helper to sort array elements in descending order
*
* @param {mixed} a - an item to compare
* @param {mixed} b - an item to compare
* @returns {number} - comparison result
*/
function descending(a, b)
{
return -1 * ascending(a, b);
}

View File

@@ -0,0 +1,21 @@
var inherits = require('util').inherits
, Readable = require('stream').Readable
, ReadableAsyncKit = require('./lib/readable_asynckit.js')
, ReadableParallel = require('./lib/readable_parallel.js')
, ReadableSerial = require('./lib/readable_serial.js')
, ReadableSerialOrdered = require('./lib/readable_serial_ordered.js')
;
// API
module.exports =
{
parallel : ReadableParallel,
serial : ReadableSerial,
serialOrdered : ReadableSerialOrdered,
};
inherits(ReadableAsyncKit, Readable);
inherits(ReadableParallel, ReadableAsyncKit);
inherits(ReadableSerial, ReadableAsyncKit);
inherits(ReadableSerialOrdered, ReadableAsyncKit);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
# Copyright (c) 2014-present Matt Zabriskie & Collaborators
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,877 @@
# Axios Migration Guide
> **Migrating from Axios 0.x to 1.x**
>
> This guide helps developers upgrade from Axios 0.x to 1.x by documenting breaking changes, providing migration strategies, and offering solutions to common upgrade challenges.
## Table of Contents
- [Overview](#overview)
- [Breaking Changes](#breaking-changes)
- [Error Handling Migration](#error-handling-migration)
- [API Changes](#api-changes)
- [Configuration Changes](#configuration-changes)
- [Migration Strategies](#migration-strategies)
- [Common Patterns](#common-patterns)
- [Troubleshooting](#troubleshooting)
- [Resources](#resources)
## Overview
Axios 1.x introduced several breaking changes to improve consistency, security, and developer experience. While these changes provide better error handling and more predictable behavior, they require code updates when migrating from 0.x versions.
### Key Changes Summary
| Area | 0.x Behavior | 1.x Behavior | Impact |
|------|--------------|--------------|--------|
| Error Handling | Selective throwing | Consistent throwing | High |
| JSON Parsing | Lenient | Strict | Medium |
| Browser Support | IE11+ | Modern browsers | Low-Medium |
| TypeScript | Partial | Full support | Low |
### Migration Complexity
- **Simple applications**: 1-2 hours
- **Medium applications**: 1-2 days
- **Large applications with complex error handling**: 3-5 days
## Breaking Changes
### 1. Error Handling Changes
**The most significant change in Axios 1.x is how errors are handled.**
#### 0.x Behavior
```javascript
// Axios 0.x - Some HTTP error codes didn't throw
axios.get('/api/data')
.then(response => {
// Response interceptor could handle all errors
console.log('Success:', response.data);
});
// Response interceptor handled everything
axios.interceptors.response.use(
response => response,
error => {
handleError(error);
// Error was "handled" and didn't propagate
}
);
```
#### 1.x Behavior
```javascript
// Axios 1.x - All HTTP errors throw consistently
axios.get('/api/data')
.then(response => {
console.log('Success:', response.data);
})
.catch(error => {
// Must handle errors at call site or they propagate
console.error('Request failed:', error);
});
// Response interceptor must re-throw or return rejected promise
axios.interceptors.response.use(
response => response,
error => {
handleError(error);
// Must explicitly handle propagation
return Promise.reject(error); // or throw error;
}
);
```
#### Impact
- **Response interceptors** can no longer "swallow" errors silently
- **Every API call** must handle errors explicitly or they become unhandled promise rejections
- **Centralized error handling** requires new patterns
### 2. JSON Parsing Changes
#### 0.x Behavior
```javascript
// Axios 0.x - Lenient JSON parsing
// Would attempt to parse even invalid JSON
response.data; // Might contain partial data or fallbacks
```
#### 1.x Behavior
```javascript
// Axios 1.x - Strict JSON parsing
// Throws clear errors for invalid JSON
try {
const data = response.data;
} catch (error) {
// Handle JSON parsing errors explicitly
}
```
### 3. Request/Response Transform Changes
#### 0.x Behavior
```javascript
// Implicit transformations with some edge cases
transformRequest: [function (data) {
// Less predictable behavior
return data;
}]
```
#### 1.x Behavior
```javascript
// More consistent transformation pipeline
transformRequest: [function (data, headers) {
// Headers parameter always available
// More predictable behavior
return data;
}]
```
### 4. Browser Support Changes
- **0.x**: Supported IE11 and older browsers
- **1.x**: Requires modern browsers with Promise support
- **Polyfills**: May be needed for older browser support
## Error Handling Migration
The error handling changes are the most complex part of migrating to Axios 1.x. Here are proven strategies:
### Strategy 1: Centralized Error Handling with Error Boundary
```javascript
// Create a centralized error handler
class ApiErrorHandler {
constructor() {
this.setupInterceptors();
}
setupInterceptors() {
axios.interceptors.response.use(
response => response,
error => {
// Centralized error processing
this.processError(error);
// Return a resolved promise with error info for handled errors
if (this.isHandledError(error)) {
return Promise.resolve({
data: null,
error: this.normalizeError(error),
handled: true
});
}
// Re-throw unhandled errors
return Promise.reject(error);
}
);
}
processError(error) {
// Log errors
console.error('API Error:', error);
// Show user notifications
if (error.response?.status === 401) {
this.handleAuthError();
} else if (error.response?.status >= 500) {
this.showErrorNotification('Server error occurred');
}
}
isHandledError(error) {
// Define which errors are "handled" centrally
const handledStatuses = [401, 403, 404, 422, 500, 502, 503];
return handledStatuses.includes(error.response?.status);
}
normalizeError(error) {
return {
status: error.response?.status,
message: error.response?.data?.message || error.message,
code: error.response?.data?.code || error.code
};
}
handleAuthError() {
// Redirect to login, clear tokens, etc.
localStorage.removeItem('token');
window.location.href = '/login';
}
showErrorNotification(message) {
// Show user-friendly error message
console.error(message); // Replace with your notification system
}
}
// Initialize globally
const errorHandler = new ApiErrorHandler();
// Usage in components/services
async function fetchUserData(userId) {
try {
const response = await axios.get(`/api/users/${userId}`);
// Check if error was handled centrally
if (response.handled) {
return { data: null, error: response.error };
}
return { data: response.data, error: null };
} catch (error) {
// Unhandled errors still need local handling
return { data: null, error: { message: 'Unexpected error occurred' } };
}
}
```
### Strategy 2: Wrapper Function Pattern
```javascript
// Create a wrapper that provides 0.x-like behavior
function createApiWrapper() {
const api = axios.create();
// Add response interceptor for centralized handling
api.interceptors.response.use(
response => response,
error => {
// Handle common errors centrally
if (error.response?.status === 401) {
// Handle auth errors
handleAuthError();
}
if (error.response?.status >= 500) {
// Handle server errors
showServerErrorNotification();
}
// Always reject to maintain error propagation
return Promise.reject(error);
}
);
// Wrapper function that mimics 0.x behavior
function safeRequest(requestConfig, options = {}) {
return api(requestConfig)
.then(response => response)
.catch(error => {
if (options.suppressErrors) {
// Return error info instead of throwing
return {
data: null,
error: {
status: error.response?.status,
message: error.response?.data?.message || error.message
}
};
}
throw error;
});
}
return { safeRequest, axios: api };
}
// Usage
const { safeRequest } = createApiWrapper();
// For calls where you want centralized error handling
const result = await safeRequest(
{ method: 'get', url: '/api/data' },
{ suppressErrors: true }
);
if (result.error) {
// Handle error case
console.log('Request failed:', result.error.message);
} else {
// Handle success case
console.log('Data:', result.data);
}
```
### Strategy 3: Global Error Handler with Custom Events
```javascript
// Set up global error handling with events
class GlobalErrorHandler extends EventTarget {
constructor() {
super();
this.setupInterceptors();
}
setupInterceptors() {
axios.interceptors.response.use(
response => response,
error => {
// Emit custom event for global handling
this.dispatchEvent(new CustomEvent('apiError', {
detail: { error, timestamp: new Date() }
}));
// Always reject to maintain proper error flow
return Promise.reject(error);
}
);
}
}
const globalErrorHandler = new GlobalErrorHandler();
// Set up global listeners
globalErrorHandler.addEventListener('apiError', (event) => {
const { error } = event.detail;
// Centralized error logic
if (error.response?.status === 401) {
handleAuthError();
}
if (error.response?.status >= 500) {
showErrorNotification('Server error occurred');
}
});
// Usage remains clean
async function apiCall() {
try {
const response = await axios.get('/api/data');
return response.data;
} catch (error) {
// Error was already handled globally
// Just handle component-specific logic
return null;
}
}
```
## API Changes
### Request Configuration
#### 0.x to 1.x Changes
```javascript
// 0.x - Some properties had different defaults
const config = {
timeout: 0, // No timeout by default
maxContentLength: -1, // No limit
};
// 1.x - More secure defaults
const config = {
timeout: 0, // Still no timeout, but easier to configure
maxContentLength: 2000, // Default limit for security
maxBodyLength: 2000, // New property
};
```
### Response Object
The response object structure remains largely the same, but error responses are more consistent:
```javascript
// Both 0.x and 1.x
response = {
data: {}, // Response body
status: 200, // HTTP status
statusText: 'OK', // HTTP status message
headers: {}, // Response headers
config: {}, // Request config
request: {} // Request object
};
// Error responses are more consistent in 1.x
error.response = {
data: {}, // Error response body
status: 404, // HTTP error status
statusText: 'Not Found',
headers: {},
config: {},
request: {}
};
```
## Configuration Changes
### Default Configuration Updates
```javascript
// 0.x defaults
axios.defaults.timeout = 0; // No timeout
axios.defaults.maxContentLength = -1; // No limit
// 1.x defaults (more secure)
axios.defaults.timeout = 0; // Still no timeout
axios.defaults.maxContentLength = 2000; // 2MB limit
axios.defaults.maxBodyLength = 2000; // 2MB limit
```
### Instance Configuration
```javascript
// 0.x - Instance creation
const api = axios.create({
baseURL: 'https://api.example.com',
timeout: 1000,
});
// 1.x - Same API, but more options available
const api = axios.create({
baseURL: 'https://api.example.com',
timeout: 1000,
maxBodyLength: Infinity, // Override default if needed
maxContentLength: Infinity,
});
```
## Migration Strategies
### Step-by-Step Migration Process
#### Phase 1: Preparation
1. **Audit Current Error Handling**
```bash
# Find all axios usage
grep -r "axios\." src/
grep -r "\.catch" src/
grep -r "interceptors" src/
```
2. **Identify Patterns**
- Response interceptors that handle errors
- Components that rely on centralized error handling
- Authentication and retry logic
3. **Create Test Cases**
```javascript
// Test current error handling behavior
describe('Error Handling Migration', () => {
it('should handle 401 errors consistently', async () => {
// Test authentication error flows
});
it('should handle 500 errors with user feedback', async () => {
// Test server error handling
});
});
```
#### Phase 2: Implementation
1. **Update Dependencies**
```bash
npm update axios
```
2. **Implement New Error Handling**
- Choose one of the strategies above
- Update response interceptors
- Add error handling to API calls
3. **Update Authentication Logic**
```javascript
// 0.x pattern
axios.interceptors.response.use(null, error => {
if (error.response?.status === 401) {
logout();
// Error was "handled"
}
});
// 1.x pattern
axios.interceptors.response.use(
response => response,
error => {
if (error.response?.status === 401) {
logout();
}
return Promise.reject(error); // Always propagate
}
);
```
#### Phase 3: Testing and Validation
1. **Test Error Scenarios**
- Network failures
- HTTP error codes (401, 403, 404, 500, etc.)
- Timeout errors
- JSON parsing errors
2. **Validate User Experience**
- Error messages are shown appropriately
- Authentication redirects work
- Loading states are handled correctly
### Gradual Migration Approach
For large applications, consider gradual migration:
```javascript
// Create a compatibility layer
const axiosCompat = {
// Use new axios instance for new code
v1: axios.create({
// 1.x configuration
}),
// Wrapper for legacy code
legacy: createLegacyWrapper(axios.create({
// Configuration that mimics 0.x behavior
}))
};
function createLegacyWrapper(axiosInstance) {
// Add interceptors that provide 0.x-like behavior
axiosInstance.interceptors.response.use(
response => response,
error => {
// Handle errors in 0.x style for legacy code
handleLegacyError(error);
// Don't propagate certain errors
if (shouldSuppressError(error)) {
return Promise.resolve({ data: null, error: true });
}
return Promise.reject(error);
}
);
return axiosInstance;
}
```
## Common Patterns
### Authentication Interceptors
#### Updated Authentication Pattern
```javascript
// Token refresh interceptor for 1.x
let isRefreshing = false;
let refreshSubscribers = [];
function subscribeTokenRefresh(cb) {
refreshSubscribers.push(cb);
}
function onTokenRefreshed(token) {
refreshSubscribers.forEach(cb => cb(token));
refreshSubscribers = [];
}
axios.interceptors.response.use(
response => response,
async error => {
const originalRequest = error.config;
if (error.response?.status === 401 && !originalRequest._retry) {
if (isRefreshing) {
// Wait for token refresh
return new Promise(resolve => {
subscribeTokenRefresh(token => {
originalRequest.headers.Authorization = `Bearer ${token}`;
resolve(axios(originalRequest));
});
});
}
originalRequest._retry = true;
isRefreshing = true;
try {
const newToken = await refreshToken();
onTokenRefreshed(newToken);
isRefreshing = false;
originalRequest.headers.Authorization = `Bearer ${newToken}`;
return axios(originalRequest);
} catch (refreshError) {
isRefreshing = false;
logout();
return Promise.reject(refreshError);
}
}
return Promise.reject(error);
}
);
```
### Retry Logic
```javascript
// Retry interceptor for 1.x
function createRetryInterceptor(maxRetries = 3, retryDelay = 1000) {
return axios.interceptors.response.use(
response => response,
async error => {
const config = error.config;
if (!config || !config.retry) {
return Promise.reject(error);
}
config.__retryCount = config.__retryCount || 0;
if (config.__retryCount >= maxRetries) {
return Promise.reject(error);
}
config.__retryCount += 1;
// Exponential backoff
const delay = retryDelay * Math.pow(2, config.__retryCount - 1);
await new Promise(resolve => setTimeout(resolve, delay));
return axios(config);
}
);
}
// Usage
const api = axios.create();
createRetryInterceptor(3, 1000);
// Make request with retry
api.get('/api/data', { retry: true });
```
### Loading State Management
```javascript
// Loading interceptor for 1.x
class LoadingManager {
constructor() {
this.requests = new Set();
this.setupInterceptors();
}
setupInterceptors() {
axios.interceptors.request.use(config => {
this.requests.add(config);
this.updateLoadingState();
return config;
});
axios.interceptors.response.use(
response => {
this.requests.delete(response.config);
this.updateLoadingState();
return response;
},
error => {
this.requests.delete(error.config);
this.updateLoadingState();
return Promise.reject(error);
}
);
}
updateLoadingState() {
const isLoading = this.requests.size > 0;
// Update your loading UI
document.body.classList.toggle('loading', isLoading);
}
}
const loadingManager = new LoadingManager();
```
## Troubleshooting
### Common Migration Issues
#### Issue 1: Unhandled Promise Rejections
**Problem:**
```javascript
// This pattern worked in 0.x but causes unhandled rejections in 1.x
axios.get('/api/data'); // No .catch() handler
```
**Solution:**
```javascript
// Always handle promises
axios.get('/api/data')
.catch(error => {
// Handle error appropriately
console.error('Request failed:', error.message);
});
// Or use async/await with try/catch
async function fetchData() {
try {
const response = await axios.get('/api/data');
return response.data;
} catch (error) {
console.error('Request failed:', error.message);
return null;
}
}
```
#### Issue 2: Response Interceptors Not "Handling" Errors
**Problem:**
```javascript
// 0.x style - interceptor "handled" errors
axios.interceptors.response.use(null, error => {
showErrorMessage(error.message);
// Error was considered "handled"
});
```
**Solution:**
```javascript
// 1.x style - explicitly control error propagation
axios.interceptors.response.use(
response => response,
error => {
showErrorMessage(error.message);
// Choose whether to propagate the error
if (shouldPropagateError(error)) {
return Promise.reject(error);
}
// Return success-like response for "handled" errors
return Promise.resolve({
data: null,
handled: true,
error: normalizeError(error)
});
}
);
```
#### Issue 3: JSON Parsing Errors
**Problem:**
```javascript
// 1.x is stricter about JSON parsing
// This might throw where 0.x was lenient
const data = response.data;
```
**Solution:**
```javascript
// Add response transformer for better error handling
axios.defaults.transformResponse = [
function (data) {
if (typeof data === 'string') {
try {
return JSON.parse(data);
} catch (e) {
// Handle JSON parsing errors gracefully
console.warn('Invalid JSON response:', data);
return { error: 'Invalid JSON', rawData: data };
}
}
return data;
}
];
```
#### Issue 4: TypeScript Errors After Upgrade
**Problem:**
```typescript
// TypeScript errors after upgrade
const response = await axios.get('/api/data');
// Property 'someProperty' does not exist on type 'any'
```
**Solution:**
```typescript
// Define proper interfaces
interface ApiResponse {
data: any;
message: string;
success: boolean;
}
const response = await axios.get<ApiResponse>('/api/data');
// Now properly typed
console.log(response.data.data);
```
### Debug Migration Issues
#### Enable Debug Logging
```javascript
// Add request/response logging
axios.interceptors.request.use(config => {
console.log('Request:', config);
return config;
});
axios.interceptors.response.use(
response => {
console.log('Response:', response);
return response;
},
error => {
console.log('Error:', error);
return Promise.reject(error);
}
);
```
#### Compare Behavior
```javascript
// Create side-by-side comparison during migration
const axios0x = require('axios-0x'); // Keep old version for testing
const axios1x = require('axios');
async function compareRequests(config) {
try {
const [result0x, result1x] = await Promise.allSettled([
axios0x(config),
axios1x(config)
]);
console.log('0.x result:', result0x);
console.log('1.x result:', result1x);
} catch (error) {
console.log('Comparison error:', error);
}
}
```
## Resources
### Official Documentation
- [Axios 1.x Documentation](https://axios-http.com/)
- [Axios GitHub Repository](https://github.com/axios/axios)
- [Axios Changelog](https://github.com/axios/axios/blob/main/CHANGELOG.md)
### Migration Tools
- [Axios Migration Codemod](https://github.com/axios/axios-migration-codemod) *(if available)*
- [ESLint Rules for Axios 1.x](https://github.com/axios/eslint-plugin-axios) *(if available)*
### Community Resources
- [Stack Overflow - Axios Migration Questions](https://stackoverflow.com/questions/tagged/axios+migration)
- [GitHub Discussions](https://github.com/axios/axios/discussions)
- [Axios Discord Community](https://discord.gg/axios) *(if available)*
### Related Issues
- [Error Handling Changes Discussion](https://github.com/axios/axios/issues/7208)
- [Migration Guide Request](https://github.com/axios/axios/issues/xxxx) *(link to related issues)*
---
## Need Help?
If you encounter issues during migration that aren't covered in this guide:
1. **Search existing issues** in the [Axios GitHub repository](https://github.com/axios/axios/issues)
2. **Ask questions** in [GitHub Discussions](https://github.com/axios/axios/discussions)
3. **Contribute improvements** to this migration guide
---
*This migration guide is maintained by the community. If you find errors or have suggestions, please [open an issue](https://github.com/axios/axios/issues) or submit a pull request.*

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,703 @@
interface RawAxiosHeaders {
[key: string]: axios.AxiosHeaderValue;
}
type MethodsHeaders = Partial<
{
[Key in axios.Method as Lowercase<Key>]: AxiosHeaders;
} & { common: AxiosHeaders }
>;
type AxiosHeaderMatcher =
| string
| RegExp
| ((this: AxiosHeaders, value: string, name: string) => boolean);
type AxiosHeaderParser = (this: AxiosHeaders, value: axios.AxiosHeaderValue, header: string) => any;
type CommonRequestHeadersList =
| 'Accept'
| 'Content-Length'
| 'User-Agent'
| 'Content-Encoding'
| 'Authorization'
| 'Location';
type ContentType =
| axios.AxiosHeaderValue
| 'text/html'
| 'text/plain'
| 'multipart/form-data'
| 'application/json'
| 'application/x-www-form-urlencoded'
| 'application/octet-stream';
type CommonResponseHeadersList =
| 'Server'
| 'Content-Type'
| 'Content-Length'
| 'Cache-Control'
| 'Content-Encoding';
type CommonResponseHeaderKey = CommonResponseHeadersList | Lowercase<CommonResponseHeadersList>;
type BrowserProgressEvent = any;
declare class AxiosHeaders {
constructor(headers?: RawAxiosHeaders | AxiosHeaders | string);
[key: string]: any;
set(
headerName?: string,
value?: axios.AxiosHeaderValue,
rewrite?: boolean | AxiosHeaderMatcher
): AxiosHeaders;
set(headers?: RawAxiosHeaders | AxiosHeaders | string, rewrite?: boolean): AxiosHeaders;
get(headerName: string, parser: RegExp): RegExpExecArray | null;
get(headerName: string, matcher?: true | AxiosHeaderParser): axios.AxiosHeaderValue;
has(header: string, matcher?: AxiosHeaderMatcher): boolean;
delete(header: string | string[], matcher?: AxiosHeaderMatcher): boolean;
clear(matcher?: AxiosHeaderMatcher): boolean;
normalize(format: boolean): AxiosHeaders;
concat(
...targets: Array<AxiosHeaders | RawAxiosHeaders | string | undefined | null>
): AxiosHeaders;
toJSON(asStrings?: boolean): RawAxiosHeaders;
static from(thing?: AxiosHeaders | RawAxiosHeaders | string): AxiosHeaders;
static accessor(header: string | string[]): AxiosHeaders;
static concat(
...targets: Array<AxiosHeaders | RawAxiosHeaders | string | undefined | null>
): AxiosHeaders;
setContentType(value: ContentType, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders;
getContentType(parser?: RegExp): RegExpExecArray | null;
getContentType(matcher?: AxiosHeaderMatcher): axios.AxiosHeaderValue;
hasContentType(matcher?: AxiosHeaderMatcher): boolean;
setContentLength(
value: axios.AxiosHeaderValue,
rewrite?: boolean | AxiosHeaderMatcher
): AxiosHeaders;
getContentLength(parser?: RegExp): RegExpExecArray | null;
getContentLength(matcher?: AxiosHeaderMatcher): axios.AxiosHeaderValue;
hasContentLength(matcher?: AxiosHeaderMatcher): boolean;
setAccept(value: axios.AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders;
getAccept(parser?: RegExp): RegExpExecArray | null;
getAccept(matcher?: AxiosHeaderMatcher): axios.AxiosHeaderValue;
hasAccept(matcher?: AxiosHeaderMatcher): boolean;
setUserAgent(value: axios.AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders;
getUserAgent(parser?: RegExp): RegExpExecArray | null;
getUserAgent(matcher?: AxiosHeaderMatcher): axios.AxiosHeaderValue;
hasUserAgent(matcher?: AxiosHeaderMatcher): boolean;
setContentEncoding(
value: axios.AxiosHeaderValue,
rewrite?: boolean | AxiosHeaderMatcher
): AxiosHeaders;
getContentEncoding(parser?: RegExp): RegExpExecArray | null;
getContentEncoding(matcher?: AxiosHeaderMatcher): axios.AxiosHeaderValue;
hasContentEncoding(matcher?: AxiosHeaderMatcher): boolean;
setAuthorization(
value: axios.AxiosHeaderValue,
rewrite?: boolean | AxiosHeaderMatcher
): AxiosHeaders;
getAuthorization(parser?: RegExp): RegExpExecArray | null;
getAuthorization(matcher?: AxiosHeaderMatcher): axios.AxiosHeaderValue;
hasAuthorization(matcher?: AxiosHeaderMatcher): boolean;
getSetCookie(): string[];
[Symbol.iterator](): IterableIterator<[string, axios.AxiosHeaderValue]>;
}
declare class AxiosError<T = unknown, D = any> extends Error {
constructor(
message?: string,
code?: string,
config?: axios.InternalAxiosRequestConfig<D>,
request?: any,
response?: axios.AxiosResponse<T, D>
);
config?: axios.InternalAxiosRequestConfig<D>;
code?: string;
request?: any;
response?: axios.AxiosResponse<T, D>;
isAxiosError: boolean;
status?: number;
toJSON: () => object;
cause?: Error;
event?: BrowserProgressEvent;
static from<T = unknown, D = any>(
error: Error | unknown,
code?: string,
config?: axios.InternalAxiosRequestConfig<D>,
request?: any,
response?: axios.AxiosResponse<T, D>,
customProps?: object
): AxiosError<T, D>;
static readonly ERR_FR_TOO_MANY_REDIRECTS = 'ERR_FR_TOO_MANY_REDIRECTS';
static readonly ERR_BAD_OPTION_VALUE = 'ERR_BAD_OPTION_VALUE';
static readonly ERR_BAD_OPTION = 'ERR_BAD_OPTION';
static readonly ERR_NETWORK = 'ERR_NETWORK';
static readonly ERR_DEPRECATED = 'ERR_DEPRECATED';
static readonly ERR_BAD_RESPONSE = 'ERR_BAD_RESPONSE';
static readonly ERR_BAD_REQUEST = 'ERR_BAD_REQUEST';
static readonly ERR_NOT_SUPPORT = 'ERR_NOT_SUPPORT';
static readonly ERR_INVALID_URL = 'ERR_INVALID_URL';
static readonly ERR_CANCELED = 'ERR_CANCELED';
static readonly ERR_FORM_DATA_DEPTH_EXCEEDED = 'ERR_FORM_DATA_DEPTH_EXCEEDED';
static readonly ECONNABORTED = 'ECONNABORTED';
static readonly ETIMEDOUT = 'ETIMEDOUT';
}
declare class CanceledError<T> extends AxiosError<T> {}
declare class Axios {
constructor(config?: axios.AxiosRequestConfig);
defaults: axios.AxiosDefaults;
interceptors: {
request: axios.AxiosInterceptorManager<axios.InternalAxiosRequestConfig>;
response: axios.AxiosInterceptorManager<axios.AxiosResponse>;
};
getUri(config?: axios.AxiosRequestConfig): string;
request<T = any, R = axios.AxiosResponse<T>, D = any>(
config: axios.AxiosRequestConfig<D>
): Promise<R>;
get<T = any, R = axios.AxiosResponse<T>, D = any>(
url: string,
config?: axios.AxiosRequestConfig<D>
): Promise<R>;
delete<T = any, R = axios.AxiosResponse<T>, D = any>(
url: string,
config?: axios.AxiosRequestConfig<D>
): Promise<R>;
head<T = any, R = axios.AxiosResponse<T>, D = any>(
url: string,
config?: axios.AxiosRequestConfig<D>
): Promise<R>;
options<T = any, R = axios.AxiosResponse<T>, D = any>(
url: string,
config?: axios.AxiosRequestConfig<D>
): Promise<R>;
post<T = any, R = axios.AxiosResponse<T>, D = any>(
url: string,
data?: D,
config?: axios.AxiosRequestConfig<D>
): Promise<R>;
put<T = any, R = axios.AxiosResponse<T>, D = any>(
url: string,
data?: D,
config?: axios.AxiosRequestConfig<D>
): Promise<R>;
patch<T = any, R = axios.AxiosResponse<T>, D = any>(
url: string,
data?: D,
config?: axios.AxiosRequestConfig<D>
): Promise<R>;
postForm<T = any, R = axios.AxiosResponse<T>, D = any>(
url: string,
data?: D,
config?: axios.AxiosRequestConfig<D>
): Promise<R>;
putForm<T = any, R = axios.AxiosResponse<T>, D = any>(
url: string,
data?: D,
config?: axios.AxiosRequestConfig<D>
): Promise<R>;
patchForm<T = any, R = axios.AxiosResponse<T>, D = any>(
url: string,
data?: D,
config?: axios.AxiosRequestConfig<D>
): Promise<R>;
}
declare enum HttpStatusCode {
Continue = 100,
SwitchingProtocols = 101,
Processing = 102,
EarlyHints = 103,
Ok = 200,
Created = 201,
Accepted = 202,
NonAuthoritativeInformation = 203,
NoContent = 204,
ResetContent = 205,
PartialContent = 206,
MultiStatus = 207,
AlreadyReported = 208,
ImUsed = 226,
MultipleChoices = 300,
MovedPermanently = 301,
Found = 302,
SeeOther = 303,
NotModified = 304,
UseProxy = 305,
Unused = 306,
TemporaryRedirect = 307,
PermanentRedirect = 308,
BadRequest = 400,
Unauthorized = 401,
PaymentRequired = 402,
Forbidden = 403,
NotFound = 404,
MethodNotAllowed = 405,
NotAcceptable = 406,
ProxyAuthenticationRequired = 407,
RequestTimeout = 408,
Conflict = 409,
Gone = 410,
LengthRequired = 411,
PreconditionFailed = 412,
PayloadTooLarge = 413,
UriTooLong = 414,
UnsupportedMediaType = 415,
RangeNotSatisfiable = 416,
ExpectationFailed = 417,
ImATeapot = 418,
MisdirectedRequest = 421,
UnprocessableEntity = 422,
Locked = 423,
FailedDependency = 424,
TooEarly = 425,
UpgradeRequired = 426,
PreconditionRequired = 428,
TooManyRequests = 429,
RequestHeaderFieldsTooLarge = 431,
UnavailableForLegalReasons = 451,
InternalServerError = 500,
NotImplemented = 501,
BadGateway = 502,
ServiceUnavailable = 503,
GatewayTimeout = 504,
HttpVersionNotSupported = 505,
VariantAlsoNegotiates = 506,
InsufficientStorage = 507,
LoopDetected = 508,
NotExtended = 510,
NetworkAuthenticationRequired = 511,
}
type InternalAxiosError<T = unknown, D = any> = AxiosError<T, D>;
declare namespace axios {
type AxiosError<T = unknown, D = any> = InternalAxiosError<T, D>;
type RawAxiosRequestHeaders = Partial<
RawAxiosHeaders & {
[Key in CommonRequestHeadersList]: AxiosHeaderValue;
} & {
'Content-Type': ContentType;
}
>;
type AxiosRequestHeaders = RawAxiosRequestHeaders & AxiosHeaders;
type AxiosHeaderValue = AxiosHeaders | string | string[] | number | boolean | null;
type RawCommonResponseHeaders = {
[Key in CommonResponseHeaderKey]: AxiosHeaderValue;
} & {
'set-cookie': string[];
};
type RawAxiosResponseHeaders = Partial<RawAxiosHeaders & RawCommonResponseHeaders>;
type AxiosResponseHeaders = RawAxiosResponseHeaders & AxiosHeaders;
interface AxiosRequestTransformer {
(this: InternalAxiosRequestConfig, data: any, headers: AxiosRequestHeaders): any;
}
interface AxiosResponseTransformer {
(
this: InternalAxiosRequestConfig,
data: any,
headers: AxiosResponseHeaders,
status?: number
): any;
}
interface AxiosAdapter {
(config: InternalAxiosRequestConfig): AxiosPromise;
}
interface AxiosBasicCredentials {
username: string;
password: string;
}
interface AxiosProxyConfig {
host: string;
port: number;
auth?: AxiosBasicCredentials;
protocol?: string;
}
type UppercaseMethod =
| 'GET'
| 'DELETE'
| 'HEAD'
| 'OPTIONS'
| 'POST'
| 'PUT'
| 'PATCH'
| 'PURGE'
| 'LINK'
| 'UNLINK';
type Method = (UppercaseMethod | Lowercase<UppercaseMethod>) & {};
type ResponseType = 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream' | 'formdata';
type UppercaseResponseEncoding =
| 'ASCII'
| 'ANSI'
| 'BINARY'
| 'BASE64'
| 'BASE64URL'
| 'HEX'
| 'LATIN1'
| 'UCS-2'
| 'UCS2'
| 'UTF-8'
| 'UTF8'
| 'UTF16LE';
type responseEncoding = (UppercaseResponseEncoding | Lowercase<UppercaseResponseEncoding>) & {};
interface TransitionalOptions {
silentJSONParsing?: boolean;
forcedJSONParsing?: boolean;
clarifyTimeoutError?: boolean;
legacyInterceptorReqResOrdering?: boolean;
}
interface GenericAbortSignal {
readonly aborted: boolean;
onabort?: ((...args: any) => any) | null;
addEventListener?: (...args: any) => any;
removeEventListener?: (...args: any) => any;
}
interface FormDataVisitorHelpers {
defaultVisitor: SerializerVisitor;
convertValue: (value: any) => any;
isVisitable: (value: any) => boolean;
}
interface SerializerVisitor {
(
this: GenericFormData,
value: any,
key: string | number,
path: null | Array<string | number>,
helpers: FormDataVisitorHelpers
): boolean;
}
interface SerializerOptions {
visitor?: SerializerVisitor;
dots?: boolean;
metaTokens?: boolean;
indexes?: boolean | null;
}
// tslint:disable-next-line
interface FormSerializerOptions extends SerializerOptions {}
interface ParamEncoder {
(value: any, defaultEncoder: (value: any) => any): any;
}
interface CustomParamsSerializer {
(params: Record<string, any>, options?: ParamsSerializerOptions): string;
}
interface ParamsSerializerOptions extends SerializerOptions {
encode?: ParamEncoder;
serialize?: CustomParamsSerializer;
}
type MaxUploadRate = number;
type MaxDownloadRate = number;
interface AxiosProgressEvent {
loaded: number;
total?: number;
progress?: number;
bytes: number;
rate?: number;
estimated?: number;
upload?: boolean;
download?: boolean;
event?: BrowserProgressEvent;
lengthComputable: boolean;
}
type Milliseconds = number;
type AxiosAdapterName = 'fetch' | 'xhr' | 'http' | (string & {});
type AxiosAdapterConfig = AxiosAdapter | AxiosAdapterName;
type AddressFamily = 4 | 6 | undefined;
interface LookupAddressEntry {
address: string;
family?: AddressFamily;
}
type LookupAddress = string | LookupAddressEntry;
interface AxiosRequestConfig<D = any> {
url?: string;
method?: Method | string;
baseURL?: string;
allowAbsoluteUrls?: boolean;
transformRequest?: AxiosRequestTransformer | AxiosRequestTransformer[];
transformResponse?: AxiosResponseTransformer | AxiosResponseTransformer[];
headers?: (RawAxiosRequestHeaders & MethodsHeaders) | AxiosHeaders;
params?: any;
paramsSerializer?: ParamsSerializerOptions | CustomParamsSerializer;
data?: D;
timeout?: Milliseconds;
timeoutErrorMessage?: string;
withCredentials?: boolean;
adapter?: AxiosAdapterConfig | AxiosAdapterConfig[];
auth?: AxiosBasicCredentials;
responseType?: ResponseType;
responseEncoding?: responseEncoding | string;
xsrfCookieName?: string;
xsrfHeaderName?: string;
onUploadProgress?: (progressEvent: AxiosProgressEvent) => void;
onDownloadProgress?: (progressEvent: AxiosProgressEvent) => void;
maxContentLength?: number;
validateStatus?: ((status: number) => boolean) | null;
maxBodyLength?: number;
maxRedirects?: number;
maxRate?: number | [MaxUploadRate, MaxDownloadRate];
beforeRedirect?: (
options: Record<string, any>,
responseDetails: { headers: Record<string, string>; statusCode: HttpStatusCode }
) => void;
socketPath?: string | null;
allowedSocketPaths?: string | string[] | null;
transport?: any;
httpAgent?: any;
httpsAgent?: any;
proxy?: AxiosProxyConfig | false;
cancelToken?: CancelToken;
decompress?: boolean;
transitional?: TransitionalOptions;
signal?: GenericAbortSignal;
insecureHTTPParser?: boolean;
env?: {
FormData?: new (...args: any[]) => object;
fetch?: (input: URL | Request | string, init?: RequestInit) => Promise<Response>;
Request?: new (input: URL | Request | string, init?: RequestInit) => Request;
Response?: new (
body?: ArrayBuffer | ArrayBufferView | Blob | FormData | URLSearchParams | string | null,
init?: ResponseInit
) => Response;
};
formSerializer?: FormSerializerOptions;
family?: AddressFamily;
lookup?:
| ((
hostname: string,
options: object,
cb: (
err: Error | null,
address: LookupAddress | LookupAddress[],
family?: AddressFamily
) => void
) => void)
| ((
hostname: string,
options: object
) => Promise<
| [address: LookupAddressEntry | LookupAddressEntry[], family?: AddressFamily]
| LookupAddress
>);
withXSRFToken?: boolean | ((config: InternalAxiosRequestConfig) => boolean | undefined);
fetchOptions?:
| Omit<RequestInit, 'body' | 'headers' | 'method' | 'signal'>
| Record<string, any>;
httpVersion?: 1 | 2;
http2Options?: Record<string, any> & {
sessionTimeout?: number;
};
}
// Alias
type RawAxiosRequestConfig<D = any> = AxiosRequestConfig<D>;
interface InternalAxiosRequestConfig<D = any> extends AxiosRequestConfig<D> {
headers: AxiosRequestHeaders;
}
interface HeadersDefaults {
common: RawAxiosRequestHeaders;
delete: RawAxiosRequestHeaders;
get: RawAxiosRequestHeaders;
head: RawAxiosRequestHeaders;
post: RawAxiosRequestHeaders;
put: RawAxiosRequestHeaders;
patch: RawAxiosRequestHeaders;
options?: RawAxiosRequestHeaders;
purge?: RawAxiosRequestHeaders;
link?: RawAxiosRequestHeaders;
unlink?: RawAxiosRequestHeaders;
}
interface AxiosDefaults<D = any> extends Omit<AxiosRequestConfig<D>, 'headers'> {
headers: HeadersDefaults;
}
interface CreateAxiosDefaults<D = any> extends Omit<AxiosRequestConfig<D>, 'headers'> {
headers?: RawAxiosRequestHeaders | AxiosHeaders | Partial<HeadersDefaults>;
}
interface AxiosResponse<T = any, D = any, H = {}> {
data: T;
status: number;
statusText: string;
headers: (H & RawAxiosResponseHeaders) | AxiosResponseHeaders;
config: InternalAxiosRequestConfig<D>;
request?: any;
}
type AxiosPromise<T = any> = Promise<AxiosResponse<T>>;
interface CancelStatic {
new (message?: string): Cancel;
}
interface Cancel {
message: string | undefined;
}
interface Canceler {
(message?: string, config?: AxiosRequestConfig, request?: any): void;
}
interface CancelTokenStatic {
new (executor: (cancel: Canceler) => void): CancelToken;
source(): CancelTokenSource;
}
interface CancelToken {
promise: Promise<Cancel>;
reason?: Cancel;
throwIfRequested(): void;
}
interface CancelTokenSource {
token: CancelToken;
cancel: Canceler;
}
interface AxiosInterceptorOptions {
synchronous?: boolean;
runWhen?: ((config: InternalAxiosRequestConfig) => boolean) | null;
}
type AxiosInterceptorFulfilled<T> = (value: T) => T | Promise<T>;
type AxiosInterceptorRejected = (error: any) => any;
type AxiosRequestInterceptorUse<T> = (
onFulfilled?: AxiosInterceptorFulfilled<T> | null,
onRejected?: AxiosInterceptorRejected | null,
options?: AxiosInterceptorOptions
) => number;
type AxiosResponseInterceptorUse<T> = (
onFulfilled?: AxiosInterceptorFulfilled<T> | null,
onRejected?: AxiosInterceptorRejected | null
) => number;
interface AxiosInterceptorHandler<T> {
fulfilled: AxiosInterceptorFulfilled<T>;
rejected?: AxiosInterceptorRejected;
synchronous: boolean;
runWhen?: ((config: InternalAxiosRequestConfig) => boolean) | null;
}
interface AxiosInterceptorManager<V> {
use: V extends AxiosResponse ? AxiosResponseInterceptorUse<V> : AxiosRequestInterceptorUse<V>;
eject(id: number): void;
clear(): void;
handlers?: Array<AxiosInterceptorHandler<V>>;
}
interface AxiosInstance extends Axios {
<T = any, R = AxiosResponse<T>, D = any>(config: AxiosRequestConfig<D>): Promise<R>;
<T = any, R = AxiosResponse<T>, D = any>(
url: string,
config?: AxiosRequestConfig<D>
): Promise<R>;
create(config?: CreateAxiosDefaults): AxiosInstance;
defaults: Omit<AxiosDefaults, 'headers'> & {
headers: HeadersDefaults & {
[key: string]: AxiosHeaderValue;
};
};
}
interface GenericFormData {
append(name: string, value: any, options?: any): any;
}
interface GenericHTMLFormElement {
name: string;
method: string;
submit(): void;
}
interface AxiosStatic extends AxiosInstance {
Cancel: CancelStatic;
CancelToken: CancelTokenStatic;
Axios: typeof Axios;
AxiosError: typeof AxiosError;
CanceledError: typeof CanceledError;
HttpStatusCode: typeof HttpStatusCode;
readonly VERSION: string;
isCancel(value: any): value is Cancel;
all<T>(values: Array<T | Promise<T>>): Promise<T[]>;
spread<T, R>(callback: (...args: T[]) => R): (array: T[]) => R;
isAxiosError<T = any, D = any>(payload: any): payload is AxiosError<T, D>;
toFormData(
sourceObj: object,
targetFormData?: GenericFormData,
options?: FormSerializerOptions
): GenericFormData;
formToJSON(form: GenericFormData | GenericHTMLFormElement): object;
getAdapter(adapters: AxiosAdapterConfig | AxiosAdapterConfig[] | undefined): AxiosAdapter;
AxiosHeaders: typeof AxiosHeaders;
mergeConfig<D = any>(
config1: AxiosRequestConfig<D>,
config2: AxiosRequestConfig<D>
): AxiosRequestConfig<D>;
}
}
declare const axios: axios.AxiosStatic;
export = axios;

View File

@@ -0,0 +1,717 @@
// TypeScript Version: 4.7
type StringLiteralsOrString<Literals extends string> = Literals | (string & {});
export type AxiosHeaderValue = AxiosHeaders | string | string[] | number | boolean | null;
interface RawAxiosHeaders {
[key: string]: AxiosHeaderValue;
}
type MethodsHeaders = Partial<
{
[Key in Method as Lowercase<Key>]: AxiosHeaders;
} & { common: AxiosHeaders }
>;
type AxiosHeaderMatcher =
| string
| RegExp
| ((this: AxiosHeaders, value: string, name: string) => boolean);
type AxiosHeaderParser = (this: AxiosHeaders, value: AxiosHeaderValue, header: string) => any;
export class AxiosHeaders {
constructor(headers?: RawAxiosHeaders | AxiosHeaders | string);
[key: string]: any;
set(
headerName?: string,
value?: AxiosHeaderValue,
rewrite?: boolean | AxiosHeaderMatcher
): AxiosHeaders;
set(headers?: RawAxiosHeaders | AxiosHeaders | string, rewrite?: boolean): AxiosHeaders;
get(headerName: string, parser: RegExp): RegExpExecArray | null;
get(headerName: string, matcher?: true | AxiosHeaderParser): AxiosHeaderValue;
has(header: string, matcher?: AxiosHeaderMatcher): boolean;
delete(header: string | string[], matcher?: AxiosHeaderMatcher): boolean;
clear(matcher?: AxiosHeaderMatcher): boolean;
normalize(format: boolean): AxiosHeaders;
concat(
...targets: Array<AxiosHeaders | RawAxiosHeaders | string | undefined | null>
): AxiosHeaders;
toJSON(asStrings?: boolean): RawAxiosHeaders;
static from(thing?: AxiosHeaders | RawAxiosHeaders | string): AxiosHeaders;
static accessor(header: string | string[]): AxiosHeaders;
static concat(
...targets: Array<AxiosHeaders | RawAxiosHeaders | string | undefined | null>
): AxiosHeaders;
setContentType(value: ContentType, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders;
getContentType(parser?: RegExp): RegExpExecArray | null;
getContentType(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
hasContentType(matcher?: AxiosHeaderMatcher): boolean;
setContentLength(value: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders;
getContentLength(parser?: RegExp): RegExpExecArray | null;
getContentLength(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
hasContentLength(matcher?: AxiosHeaderMatcher): boolean;
setAccept(value: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders;
getAccept(parser?: RegExp): RegExpExecArray | null;
getAccept(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
hasAccept(matcher?: AxiosHeaderMatcher): boolean;
setUserAgent(value: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders;
getUserAgent(parser?: RegExp): RegExpExecArray | null;
getUserAgent(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
hasUserAgent(matcher?: AxiosHeaderMatcher): boolean;
setContentEncoding(value: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders;
getContentEncoding(parser?: RegExp): RegExpExecArray | null;
getContentEncoding(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
hasContentEncoding(matcher?: AxiosHeaderMatcher): boolean;
setAuthorization(value: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders;
getAuthorization(parser?: RegExp): RegExpExecArray | null;
getAuthorization(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
hasAuthorization(matcher?: AxiosHeaderMatcher): boolean;
getSetCookie(): string[];
[Symbol.iterator](): IterableIterator<[string, AxiosHeaderValue]>;
}
type CommonRequestHeadersList =
| 'Accept'
| 'Content-Length'
| 'User-Agent'
| 'Content-Encoding'
| 'Authorization'
| 'Location';
type ContentType =
| AxiosHeaderValue
| 'text/html'
| 'text/plain'
| 'multipart/form-data'
| 'application/json'
| 'application/x-www-form-urlencoded'
| 'application/octet-stream';
export type RawAxiosRequestHeaders = Partial<
RawAxiosHeaders & {
[Key in CommonRequestHeadersList]: AxiosHeaderValue;
} & {
'Content-Type': ContentType;
}
>;
export type AxiosRequestHeaders = RawAxiosRequestHeaders & AxiosHeaders;
type CommonResponseHeadersList =
| 'Server'
| 'Content-Type'
| 'Content-Length'
| 'Cache-Control'
| 'Content-Encoding';
type CommonResponseHeaderKey = CommonResponseHeadersList | Lowercase<CommonResponseHeadersList>;
type RawCommonResponseHeaders = {
[Key in CommonResponseHeaderKey]: AxiosHeaderValue;
} & {
'set-cookie': string[];
};
export type RawAxiosResponseHeaders = Partial<RawAxiosHeaders & RawCommonResponseHeaders>;
export type AxiosResponseHeaders = RawAxiosResponseHeaders & AxiosHeaders;
export interface AxiosRequestTransformer {
(this: InternalAxiosRequestConfig, data: any, headers: AxiosRequestHeaders): any;
}
export interface AxiosResponseTransformer {
(
this: InternalAxiosRequestConfig,
data: any,
headers: AxiosResponseHeaders,
status?: number
): any;
}
export interface AxiosAdapter {
(config: InternalAxiosRequestConfig): AxiosPromise;
}
export interface AxiosBasicCredentials {
username: string;
password: string;
}
export interface AxiosProxyConfig {
host: string;
port: number;
auth?: AxiosBasicCredentials;
protocol?: string;
}
export enum HttpStatusCode {
Continue = 100,
SwitchingProtocols = 101,
Processing = 102,
EarlyHints = 103,
Ok = 200,
Created = 201,
Accepted = 202,
NonAuthoritativeInformation = 203,
NoContent = 204,
ResetContent = 205,
PartialContent = 206,
MultiStatus = 207,
AlreadyReported = 208,
ImUsed = 226,
MultipleChoices = 300,
MovedPermanently = 301,
Found = 302,
SeeOther = 303,
NotModified = 304,
UseProxy = 305,
Unused = 306,
TemporaryRedirect = 307,
PermanentRedirect = 308,
BadRequest = 400,
Unauthorized = 401,
PaymentRequired = 402,
Forbidden = 403,
NotFound = 404,
MethodNotAllowed = 405,
NotAcceptable = 406,
ProxyAuthenticationRequired = 407,
RequestTimeout = 408,
Conflict = 409,
Gone = 410,
LengthRequired = 411,
PreconditionFailed = 412,
PayloadTooLarge = 413,
UriTooLong = 414,
UnsupportedMediaType = 415,
RangeNotSatisfiable = 416,
ExpectationFailed = 417,
ImATeapot = 418,
MisdirectedRequest = 421,
UnprocessableEntity = 422,
Locked = 423,
FailedDependency = 424,
TooEarly = 425,
UpgradeRequired = 426,
PreconditionRequired = 428,
TooManyRequests = 429,
RequestHeaderFieldsTooLarge = 431,
UnavailableForLegalReasons = 451,
InternalServerError = 500,
NotImplemented = 501,
BadGateway = 502,
ServiceUnavailable = 503,
GatewayTimeout = 504,
HttpVersionNotSupported = 505,
VariantAlsoNegotiates = 506,
InsufficientStorage = 507,
LoopDetected = 508,
NotExtended = 510,
NetworkAuthenticationRequired = 511,
}
type UppercaseMethod =
| 'GET'
| 'DELETE'
| 'HEAD'
| 'OPTIONS'
| 'POST'
| 'PUT'
| 'PATCH'
| 'PURGE'
| 'LINK'
| 'UNLINK';
export type Method = (UppercaseMethod | Lowercase<UppercaseMethod>) & {};
export type ResponseType =
| 'arraybuffer'
| 'blob'
| 'document'
| 'json'
| 'text'
| 'stream'
| 'formdata';
type UppercaseResponseEncoding =
| 'ASCII'
| 'ANSI'
| 'BINARY'
| 'BASE64'
| 'BASE64URL'
| 'HEX'
| 'LATIN1'
| 'UCS-2'
| 'UCS2'
| 'UTF-8'
| 'UTF8'
| 'UTF16LE';
export type responseEncoding = (
| UppercaseResponseEncoding
| Lowercase<UppercaseResponseEncoding>
) & {};
export interface TransitionalOptions {
silentJSONParsing?: boolean;
forcedJSONParsing?: boolean;
clarifyTimeoutError?: boolean;
legacyInterceptorReqResOrdering?: boolean;
}
export interface GenericAbortSignal {
readonly aborted: boolean;
onabort?: ((...args: any) => any) | null;
addEventListener?: (...args: any) => any;
removeEventListener?: (...args: any) => any;
}
export interface FormDataVisitorHelpers {
defaultVisitor: SerializerVisitor;
convertValue: (value: any) => any;
isVisitable: (value: any) => boolean;
}
export interface SerializerVisitor {
(
this: GenericFormData,
value: any,
key: string | number,
path: null | Array<string | number>,
helpers: FormDataVisitorHelpers
): boolean;
}
export interface SerializerOptions {
visitor?: SerializerVisitor;
dots?: boolean;
metaTokens?: boolean;
indexes?: boolean | null;
}
// tslint:disable-next-line
export interface FormSerializerOptions extends SerializerOptions {}
export interface ParamEncoder {
(value: any, defaultEncoder: (value: any) => any): any;
}
export interface CustomParamsSerializer {
(params: Record<string, any>, options?: ParamsSerializerOptions): string;
}
export interface ParamsSerializerOptions extends SerializerOptions {
encode?: ParamEncoder;
serialize?: CustomParamsSerializer;
}
type MaxUploadRate = number;
type MaxDownloadRate = number;
type BrowserProgressEvent = any;
export interface AxiosProgressEvent {
loaded: number;
total?: number;
progress?: number;
bytes: number;
rate?: number;
estimated?: number;
upload?: boolean;
download?: boolean;
event?: BrowserProgressEvent;
lengthComputable: boolean;
}
type Milliseconds = number;
type AxiosAdapterName = StringLiteralsOrString<'xhr' | 'http' | 'fetch'>;
type AxiosAdapterConfig = AxiosAdapter | AxiosAdapterName;
export type AddressFamily = 4 | 6 | undefined;
export interface LookupAddressEntry {
address: string;
family?: AddressFamily;
}
export type LookupAddress = string | LookupAddressEntry;
export interface AxiosRequestConfig<D = any> {
url?: string;
method?: StringLiteralsOrString<Method>;
baseURL?: string;
allowAbsoluteUrls?: boolean;
transformRequest?: AxiosRequestTransformer | AxiosRequestTransformer[];
transformResponse?: AxiosResponseTransformer | AxiosResponseTransformer[];
headers?: (RawAxiosRequestHeaders & MethodsHeaders) | AxiosHeaders;
params?: any;
paramsSerializer?: ParamsSerializerOptions | CustomParamsSerializer;
data?: D;
timeout?: Milliseconds;
timeoutErrorMessage?: string;
withCredentials?: boolean;
adapter?: AxiosAdapterConfig | AxiosAdapterConfig[];
auth?: AxiosBasicCredentials;
responseType?: ResponseType;
responseEncoding?: StringLiteralsOrString<responseEncoding>;
xsrfCookieName?: string;
xsrfHeaderName?: string;
onUploadProgress?: (progressEvent: AxiosProgressEvent) => void;
onDownloadProgress?: (progressEvent: AxiosProgressEvent) => void;
maxContentLength?: number;
validateStatus?: ((status: number) => boolean) | null;
maxBodyLength?: number;
maxRedirects?: number;
maxRate?: number | [MaxUploadRate, MaxDownloadRate];
beforeRedirect?: (
options: Record<string, any>,
responseDetails: {
headers: Record<string, string>;
statusCode: HttpStatusCode;
}
) => void;
socketPath?: string | null;
allowedSocketPaths?: string | string[] | null;
transport?: any;
httpAgent?: any;
httpsAgent?: any;
proxy?: AxiosProxyConfig | false;
cancelToken?: CancelToken | undefined;
decompress?: boolean;
transitional?: TransitionalOptions;
signal?: GenericAbortSignal;
insecureHTTPParser?: boolean;
env?: {
FormData?: new (...args: any[]) => object;
fetch?: (input: URL | Request | string, init?: RequestInit) => Promise<Response>;
Request?: new (input: URL | Request | string, init?: RequestInit) => Request;
Response?: new (
body?: ArrayBuffer | ArrayBufferView | Blob | FormData | URLSearchParams | string | null,
init?: ResponseInit
) => Response;
};
formSerializer?: FormSerializerOptions;
family?: AddressFamily;
lookup?:
| ((
hostname: string,
options: object,
cb: (
err: Error | null,
address: LookupAddress | LookupAddress[],
family?: AddressFamily
) => void
) => void)
| ((
hostname: string,
options: object
) => Promise<
[address: LookupAddressEntry | LookupAddressEntry[], family?: AddressFamily] | LookupAddress
>);
withXSRFToken?: boolean | ((config: InternalAxiosRequestConfig) => boolean | undefined);
parseReviver?: (this: any, key: string, value: any) => any;
fetchOptions?: Omit<RequestInit, 'body' | 'headers' | 'method' | 'signal'> | Record<string, any>;
httpVersion?: 1 | 2;
http2Options?: Record<string, any> & {
sessionTimeout?: number;
};
}
// Alias
export type RawAxiosRequestConfig<D = any> = AxiosRequestConfig<D>;
export interface InternalAxiosRequestConfig<D = any> extends AxiosRequestConfig<D> {
headers: AxiosRequestHeaders;
}
export interface HeadersDefaults {
common: RawAxiosRequestHeaders;
delete: RawAxiosRequestHeaders;
get: RawAxiosRequestHeaders;
head: RawAxiosRequestHeaders;
post: RawAxiosRequestHeaders;
put: RawAxiosRequestHeaders;
patch: RawAxiosRequestHeaders;
options?: RawAxiosRequestHeaders;
purge?: RawAxiosRequestHeaders;
link?: RawAxiosRequestHeaders;
unlink?: RawAxiosRequestHeaders;
}
export interface AxiosDefaults<D = any> extends Omit<AxiosRequestConfig<D>, 'headers'> {
headers: HeadersDefaults;
}
export interface CreateAxiosDefaults<D = any> extends Omit<AxiosRequestConfig<D>, 'headers'> {
headers?: RawAxiosRequestHeaders | AxiosHeaders | Partial<HeadersDefaults>;
}
export interface AxiosResponse<T = any, D = any, H = {}> {
data: T;
status: number;
statusText: string;
headers: (H & RawAxiosResponseHeaders) | AxiosResponseHeaders;
config: InternalAxiosRequestConfig<D>;
request?: any;
}
export class AxiosError<T = unknown, D = any> extends Error {
constructor(
message?: string,
code?: string,
config?: InternalAxiosRequestConfig<D>,
request?: any,
response?: AxiosResponse<T, D>
);
config?: InternalAxiosRequestConfig<D>;
code?: string;
request?: any;
response?: AxiosResponse<T, D>;
isAxiosError: boolean;
status?: number;
toJSON: () => object;
cause?: Error;
event?: BrowserProgressEvent;
static from<T = unknown, D = any>(
error: Error | unknown,
code?: string,
config?: InternalAxiosRequestConfig<D>,
request?: any,
response?: AxiosResponse<T, D>,
customProps?: object
): AxiosError<T, D>;
static readonly ERR_FR_TOO_MANY_REDIRECTS = 'ERR_FR_TOO_MANY_REDIRECTS';
static readonly ERR_BAD_OPTION_VALUE = 'ERR_BAD_OPTION_VALUE';
static readonly ERR_BAD_OPTION = 'ERR_BAD_OPTION';
static readonly ERR_NETWORK = 'ERR_NETWORK';
static readonly ERR_DEPRECATED = 'ERR_DEPRECATED';
static readonly ERR_BAD_RESPONSE = 'ERR_BAD_RESPONSE';
static readonly ERR_BAD_REQUEST = 'ERR_BAD_REQUEST';
static readonly ERR_NOT_SUPPORT = 'ERR_NOT_SUPPORT';
static readonly ERR_INVALID_URL = 'ERR_INVALID_URL';
static readonly ERR_CANCELED = 'ERR_CANCELED';
static readonly ERR_FORM_DATA_DEPTH_EXCEEDED = 'ERR_FORM_DATA_DEPTH_EXCEEDED';
static readonly ECONNABORTED = 'ECONNABORTED';
static readonly ETIMEDOUT = 'ETIMEDOUT';
}
export class CanceledError<T> extends AxiosError<T> {
readonly name: 'CanceledError';
}
export type AxiosPromise<T = any> = Promise<AxiosResponse<T>>;
export interface CancelStatic {
new (message?: string): Cancel;
}
export interface Cancel {
message: string | undefined;
}
export interface Canceler {
(message?: string, config?: AxiosRequestConfig, request?: any): void;
}
export interface CancelTokenStatic {
new (executor: (cancel: Canceler) => void): CancelToken;
source(): CancelTokenSource;
}
export interface CancelToken {
promise: Promise<Cancel>;
reason?: Cancel;
throwIfRequested(): void;
}
export interface CancelTokenSource {
token: CancelToken;
cancel: Canceler;
}
export interface AxiosInterceptorOptions {
synchronous?: boolean;
runWhen?: ((config: InternalAxiosRequestConfig) => boolean) | null;
}
type AxiosInterceptorFulfilled<T> = (value: T) => T | Promise<T>;
type AxiosInterceptorRejected = (error: any) => any;
type AxiosRequestInterceptorUse<T> = (
onFulfilled?: AxiosInterceptorFulfilled<T> | null,
onRejected?: AxiosInterceptorRejected | null,
options?: AxiosInterceptorOptions
) => number;
type AxiosResponseInterceptorUse<T> = (
onFulfilled?: AxiosInterceptorFulfilled<T> | null,
onRejected?: AxiosInterceptorRejected | null
) => number;
interface AxiosInterceptorHandler<T> {
fulfilled: AxiosInterceptorFulfilled<T>;
rejected?: AxiosInterceptorRejected;
synchronous: boolean;
runWhen?: ((config: InternalAxiosRequestConfig) => boolean) | null;
}
export interface AxiosInterceptorManager<V> {
use: V extends AxiosResponse ? AxiosResponseInterceptorUse<V> : AxiosRequestInterceptorUse<V>;
eject(id: number): void;
clear(): void;
handlers?: Array<AxiosInterceptorHandler<V>>;
}
export class Axios {
constructor(config?: AxiosRequestConfig);
defaults: AxiosDefaults;
interceptors: {
request: AxiosInterceptorManager<InternalAxiosRequestConfig>;
response: AxiosInterceptorManager<AxiosResponse>;
};
getUri(config?: AxiosRequestConfig): string;
request<T = any, R = AxiosResponse<T>, D = any>(config: AxiosRequestConfig<D>): Promise<R>;
get<T = any, R = AxiosResponse<T>, D = any>(
url: string,
config?: AxiosRequestConfig<D>
): Promise<R>;
delete<T = any, R = AxiosResponse<T>, D = any>(
url: string,
config?: AxiosRequestConfig<D>
): Promise<R>;
head<T = any, R = AxiosResponse<T>, D = any>(
url: string,
config?: AxiosRequestConfig<D>
): Promise<R>;
options<T = any, R = AxiosResponse<T>, D = any>(
url: string,
config?: AxiosRequestConfig<D>
): Promise<R>;
post<T = any, R = AxiosResponse<T>, D = any>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>
): Promise<R>;
put<T = any, R = AxiosResponse<T>, D = any>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>
): Promise<R>;
patch<T = any, R = AxiosResponse<T>, D = any>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>
): Promise<R>;
postForm<T = any, R = AxiosResponse<T>, D = any>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>
): Promise<R>;
putForm<T = any, R = AxiosResponse<T>, D = any>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>
): Promise<R>;
patchForm<T = any, R = AxiosResponse<T>, D = any>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>
): Promise<R>;
}
export interface AxiosInstance extends Axios {
<T = any, R = AxiosResponse<T>, D = any>(config: AxiosRequestConfig<D>): Promise<R>;
<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R>;
create(config?: CreateAxiosDefaults): AxiosInstance;
defaults: Omit<AxiosDefaults, 'headers'> & {
headers: HeadersDefaults & {
[key: string]: AxiosHeaderValue;
};
};
}
export interface GenericFormData {
append(name: string, value: any, options?: any): any;
}
export interface GenericHTMLFormElement {
name: string;
method: string;
submit(): void;
}
export function getAdapter(
adapters: AxiosAdapterConfig | AxiosAdapterConfig[] | undefined
): AxiosAdapter;
export function toFormData(
sourceObj: object,
targetFormData?: GenericFormData,
options?: FormSerializerOptions
): GenericFormData;
export function formToJSON(form: GenericFormData | GenericHTMLFormElement): object;
export function isAxiosError<T = any, D = any>(payload: any): payload is AxiosError<T, D>;
export function spread<T, R>(callback: (...args: T[]) => R): (array: T[]) => R;
export function isCancel<T = any>(value: any): value is CanceledError<T>;
export function all<T>(values: Array<T | Promise<T>>): Promise<T[]>;
export function mergeConfig<D = any>(
config1: AxiosRequestConfig<D>,
config2: AxiosRequestConfig<D>
): AxiosRequestConfig<D>;
export interface AxiosStatic extends AxiosInstance {
Cancel: CancelStatic;
CancelToken: CancelTokenStatic;
Axios: typeof Axios;
AxiosError: typeof AxiosError;
HttpStatusCode: typeof HttpStatusCode;
readonly VERSION: string;
isCancel: typeof isCancel;
all: typeof all;
spread: typeof spread;
isAxiosError: typeof isAxiosError;
toFormData: typeof toFormData;
formToJSON: typeof formToJSON;
getAdapter: typeof getAdapter;
CanceledError: typeof CanceledError;
AxiosHeaders: typeof AxiosHeaders;
mergeConfig: typeof mergeConfig;
}
declare const axios: AxiosStatic;
export default axios;

View File

@@ -0,0 +1,43 @@
import axios from './lib/axios.js';
// This module is intended to unwrap Axios default export as named.
// Keep top-level export same with static properties
// so that it can keep same with es module or cjs
const {
Axios,
AxiosError,
CanceledError,
isCancel,
CancelToken,
VERSION,
all,
Cancel,
isAxiosError,
spread,
toFormData,
AxiosHeaders,
HttpStatusCode,
formToJSON,
getAdapter,
mergeConfig,
} = axios;
export {
axios as default,
Axios,
AxiosError,
CanceledError,
isCancel,
CancelToken,
VERSION,
all,
Cancel,
isAxiosError,
spread,
toFormData,
AxiosHeaders,
HttpStatusCode,
formToJSON,
getAdapter,
mergeConfig,
};

View File

@@ -0,0 +1,36 @@
# axios // adapters
The modules under `adapters/` are modules that handle dispatching a request and settling a returned `Promise` once a response is received.
## Example
```js
var settle = require('../core/settle');
module.exports = function myAdapter(config) {
// At this point:
// - config has been merged with defaults
// - request transformers have already run
// - request interceptors have already run
// Make the request using config provided
// Upon response settle the Promise
return new Promise(function (resolve, reject) {
var response = {
data: responseData,
status: request.status,
statusText: request.statusText,
headers: responseHeaders,
config: config,
request: request,
};
settle(resolve, reject, response);
// From here:
// - response transformers will run
// - response interceptors will run
});
};
```

View File

@@ -0,0 +1,130 @@
import utils from '../utils.js';
import httpAdapter from './http.js';
import xhrAdapter from './xhr.js';
import * as fetchAdapter from './fetch.js';
import AxiosError from '../core/AxiosError.js';
/**
* Known adapters mapping.
* Provides environment-specific adapters for Axios:
* - `http` for Node.js
* - `xhr` for browsers
* - `fetch` for fetch API-based requests
*
* @type {Object<string, Function|Object>}
*/
const knownAdapters = {
http: httpAdapter,
xhr: xhrAdapter,
fetch: {
get: fetchAdapter.getFetch,
},
};
// Assign adapter names for easier debugging and identification
utils.forEach(knownAdapters, (fn, value) => {
if (fn) {
try {
Object.defineProperty(fn, 'name', { value });
} catch (e) {
// eslint-disable-next-line no-empty
}
Object.defineProperty(fn, 'adapterName', { value });
}
});
/**
* Render a rejection reason string for unknown or unsupported adapters
*
* @param {string} reason
* @returns {string}
*/
const renderReason = (reason) => `- ${reason}`;
/**
* Check if the adapter is resolved (function, null, or false)
*
* @param {Function|null|false} adapter
* @returns {boolean}
*/
const isResolvedHandle = (adapter) =>
utils.isFunction(adapter) || adapter === null || adapter === false;
/**
* Get the first suitable adapter from the provided list.
* Tries each adapter in order until a supported one is found.
* Throws an AxiosError if no adapter is suitable.
*
* @param {Array<string|Function>|string|Function} adapters - Adapter(s) by name or function.
* @param {Object} config - Axios request configuration
* @throws {AxiosError} If no suitable adapter is available
* @returns {Function} The resolved adapter function
*/
function getAdapter(adapters, config) {
adapters = utils.isArray(adapters) ? adapters : [adapters];
const { length } = adapters;
let nameOrAdapter;
let adapter;
const rejectedReasons = {};
for (let i = 0; i < length; i++) {
nameOrAdapter = adapters[i];
let id;
adapter = nameOrAdapter;
if (!isResolvedHandle(nameOrAdapter)) {
adapter = knownAdapters[(id = String(nameOrAdapter)).toLowerCase()];
if (adapter === undefined) {
throw new AxiosError(`Unknown adapter '${id}'`);
}
}
if (adapter && (utils.isFunction(adapter) || (adapter = adapter.get(config)))) {
break;
}
rejectedReasons[id || '#' + i] = adapter;
}
if (!adapter) {
const reasons = Object.entries(rejectedReasons).map(
([id, state]) =>
`adapter ${id} ` +
(state === false ? 'is not supported by the environment' : 'is not available in the build')
);
let s = length
? reasons.length > 1
? 'since :\n' + reasons.map(renderReason).join('\n')
: ' ' + renderReason(reasons[0])
: 'as no adapter specified';
throw new AxiosError(
`There is no suitable adapter to dispatch the request ` + s,
'ERR_NOT_SUPPORT'
);
}
return adapter;
}
/**
* Exports Axios adapters and utility to resolve an adapter
*/
export default {
/**
* Resolve an adapter from a list of adapter names or functions.
* @type {Function}
*/
getAdapter,
/**
* Exposes all known adapters
* @type {Object<string, Function|Object>}
*/
adapters: knownAdapters,
};

View File

@@ -0,0 +1,353 @@
import platform from '../platform/index.js';
import utils from '../utils.js';
import AxiosError from '../core/AxiosError.js';
import composeSignals from '../helpers/composeSignals.js';
import { trackStream } from '../helpers/trackStream.js';
import AxiosHeaders from '../core/AxiosHeaders.js';
import {
progressEventReducer,
progressEventDecorator,
asyncDecorator,
} from '../helpers/progressEventReducer.js';
import resolveConfig from '../helpers/resolveConfig.js';
import settle from '../core/settle.js';
const DEFAULT_CHUNK_SIZE = 64 * 1024;
const { isFunction } = utils;
const globalFetchAPI = (({ Request, Response }) => ({
Request,
Response,
}))(utils.global);
const { ReadableStream, TextEncoder } = utils.global;
const test = (fn, ...args) => {
try {
return !!fn(...args);
} catch (e) {
return false;
}
};
const factory = (env) => {
env = utils.merge.call(
{
skipUndefined: true,
},
globalFetchAPI,
env
);
const { fetch: envFetch, Request, Response } = env;
const isFetchSupported = envFetch ? isFunction(envFetch) : typeof fetch === 'function';
const isRequestSupported = isFunction(Request);
const isResponseSupported = isFunction(Response);
if (!isFetchSupported) {
return false;
}
const isReadableStreamSupported = isFetchSupported && isFunction(ReadableStream);
const encodeText =
isFetchSupported &&
(typeof TextEncoder === 'function'
? (
(encoder) => (str) =>
encoder.encode(str)
)(new TextEncoder())
: async (str) => new Uint8Array(await new Request(str).arrayBuffer()));
const supportsRequestStream =
isRequestSupported &&
isReadableStreamSupported &&
test(() => {
let duplexAccessed = false;
const request = new Request(platform.origin, {
body: new ReadableStream(),
method: 'POST',
get duplex() {
duplexAccessed = true;
return 'half';
},
});
const hasContentType = request.headers.has('Content-Type');
if (request.body != null) {
request.body.cancel();
}
return duplexAccessed && !hasContentType;
});
const supportsResponseStream =
isResponseSupported &&
isReadableStreamSupported &&
test(() => utils.isReadableStream(new Response('').body));
const resolvers = {
stream: supportsResponseStream && ((res) => res.body),
};
isFetchSupported &&
(() => {
['text', 'arrayBuffer', 'blob', 'formData', 'stream'].forEach((type) => {
!resolvers[type] &&
(resolvers[type] = (res, config) => {
let method = res && res[type];
if (method) {
return method.call(res);
}
throw new AxiosError(
`Response type '${type}' is not supported`,
AxiosError.ERR_NOT_SUPPORT,
config
);
});
});
})();
const getBodyLength = async (body) => {
if (body == null) {
return 0;
}
if (utils.isBlob(body)) {
return body.size;
}
if (utils.isSpecCompliantForm(body)) {
const _request = new Request(platform.origin, {
method: 'POST',
body,
});
return (await _request.arrayBuffer()).byteLength;
}
if (utils.isArrayBufferView(body) || utils.isArrayBuffer(body)) {
return body.byteLength;
}
if (utils.isURLSearchParams(body)) {
body = body + '';
}
if (utils.isString(body)) {
return (await encodeText(body)).byteLength;
}
};
const resolveBodyLength = async (headers, body) => {
const length = utils.toFiniteNumber(headers.getContentLength());
return length == null ? getBodyLength(body) : length;
};
return async (config) => {
let {
url,
method,
data,
signal,
cancelToken,
timeout,
onDownloadProgress,
onUploadProgress,
responseType,
headers,
withCredentials = 'same-origin',
fetchOptions,
} = resolveConfig(config);
let _fetch = envFetch || fetch;
responseType = responseType ? (responseType + '').toLowerCase() : 'text';
let composedSignal = composeSignals(
[signal, cancelToken && cancelToken.toAbortSignal()],
timeout
);
let request = null;
const unsubscribe =
composedSignal &&
composedSignal.unsubscribe &&
(() => {
composedSignal.unsubscribe();
});
let requestContentLength;
try {
if (
onUploadProgress &&
supportsRequestStream &&
method !== 'get' &&
method !== 'head' &&
(requestContentLength = await resolveBodyLength(headers, data)) !== 0
) {
let _request = new Request(url, {
method: 'POST',
body: data,
duplex: 'half',
});
let contentTypeHeader;
if (utils.isFormData(data) && (contentTypeHeader = _request.headers.get('content-type'))) {
headers.setContentType(contentTypeHeader);
}
if (_request.body) {
const [onProgress, flush] = progressEventDecorator(
requestContentLength,
progressEventReducer(asyncDecorator(onUploadProgress))
);
data = trackStream(_request.body, DEFAULT_CHUNK_SIZE, onProgress, flush);
}
}
if (!utils.isString(withCredentials)) {
withCredentials = withCredentials ? 'include' : 'omit';
}
// Cloudflare Workers throws when credentials are defined
// see https://github.com/cloudflare/workerd/issues/902
const isCredentialsSupported = isRequestSupported && 'credentials' in Request.prototype;
// If data is FormData and Content-Type is multipart/form-data without boundary,
// delete it so fetch can set it correctly with the boundary
if (utils.isFormData(data)) {
const contentType = headers.getContentType();
if (
contentType &&
/^multipart\/form-data/i.test(contentType) &&
!/boundary=/i.test(contentType)
) {
headers.delete('content-type');
}
}
const resolvedOptions = {
...fetchOptions,
signal: composedSignal,
method: method.toUpperCase(),
headers: headers.normalize().toJSON(),
body: data,
duplex: 'half',
credentials: isCredentialsSupported ? withCredentials : undefined,
};
request = isRequestSupported && new Request(url, resolvedOptions);
let response = await (isRequestSupported
? _fetch(request, fetchOptions)
: _fetch(url, resolvedOptions));
const isStreamResponse =
supportsResponseStream && (responseType === 'stream' || responseType === 'response');
if (supportsResponseStream && (onDownloadProgress || (isStreamResponse && unsubscribe))) {
const options = {};
['status', 'statusText', 'headers'].forEach((prop) => {
options[prop] = response[prop];
});
const responseContentLength = utils.toFiniteNumber(response.headers.get('content-length'));
const [onProgress, flush] =
(onDownloadProgress &&
progressEventDecorator(
responseContentLength,
progressEventReducer(asyncDecorator(onDownloadProgress), true)
)) ||
[];
response = new Response(
trackStream(response.body, DEFAULT_CHUNK_SIZE, onProgress, () => {
flush && flush();
unsubscribe && unsubscribe();
}),
options
);
}
responseType = responseType || 'text';
let responseData = await resolvers[utils.findKey(resolvers, responseType) || 'text'](
response,
config
);
!isStreamResponse && unsubscribe && unsubscribe();
return await new Promise((resolve, reject) => {
settle(resolve, reject, {
data: responseData,
headers: AxiosHeaders.from(response.headers),
status: response.status,
statusText: response.statusText,
config,
request,
});
});
} catch (err) {
unsubscribe && unsubscribe();
if (err && err.name === 'TypeError' && /Load failed|fetch/i.test(err.message)) {
throw Object.assign(
new AxiosError(
'Network Error',
AxiosError.ERR_NETWORK,
config,
request,
err && err.response
),
{
cause: err.cause || err,
}
);
}
throw AxiosError.from(err, err && err.code, config, request, err && err.response);
}
};
};
const seedCache = new Map();
export const getFetch = (config) => {
let env = (config && config.env) || {};
const { fetch, Request, Response } = env;
const seeds = [Request, Response, fetch];
let len = seeds.length,
i = len,
seed,
target,
map = seedCache;
while (i--) {
seed = seeds[i];
target = map.get(seed);
target === undefined && map.set(seed, (target = i ? new Map() : factory(env)));
map = target;
}
return target;
};
const adapter = getFetch();
export default adapter;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,222 @@
import utils from '../utils.js';
import settle from '../core/settle.js';
import transitionalDefaults from '../defaults/transitional.js';
import AxiosError from '../core/AxiosError.js';
import CanceledError from '../cancel/CanceledError.js';
import parseProtocol from '../helpers/parseProtocol.js';
import platform from '../platform/index.js';
import AxiosHeaders from '../core/AxiosHeaders.js';
import { progressEventReducer } from '../helpers/progressEventReducer.js';
import resolveConfig from '../helpers/resolveConfig.js';
const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined';
export default isXHRAdapterSupported &&
function (config) {
return new Promise(function dispatchXhrRequest(resolve, reject) {
const _config = resolveConfig(config);
let requestData = _config.data;
const requestHeaders = AxiosHeaders.from(_config.headers).normalize();
let { responseType, onUploadProgress, onDownloadProgress } = _config;
let onCanceled;
let uploadThrottled, downloadThrottled;
let flushUpload, flushDownload;
function done() {
flushUpload && flushUpload(); // flush events
flushDownload && flushDownload(); // flush events
_config.cancelToken && _config.cancelToken.unsubscribe(onCanceled);
_config.signal && _config.signal.removeEventListener('abort', onCanceled);
}
let request = new XMLHttpRequest();
request.open(_config.method.toUpperCase(), _config.url, true);
// Set the request timeout in MS
request.timeout = _config.timeout;
function onloadend() {
if (!request) {
return;
}
// Prepare the response
const responseHeaders = AxiosHeaders.from(
'getAllResponseHeaders' in request && request.getAllResponseHeaders()
);
const responseData =
!responseType || responseType === 'text' || responseType === 'json'
? request.responseText
: request.response;
const response = {
data: responseData,
status: request.status,
statusText: request.statusText,
headers: responseHeaders,
config,
request,
};
settle(
function _resolve(value) {
resolve(value);
done();
},
function _reject(err) {
reject(err);
done();
},
response
);
// Clean up request
request = null;
}
if ('onloadend' in request) {
// Use onloadend if available
request.onloadend = onloadend;
} else {
// Listen for ready state to emulate onloadend
request.onreadystatechange = function handleLoad() {
if (!request || request.readyState !== 4) {
return;
}
// The request errored out and we didn't get a response, this will be
// handled by onerror instead
// With one exception: request that using file: protocol, most browsers
// will return status as 0 even though it's a successful request
if (
request.status === 0 &&
!(request.responseURL && request.responseURL.indexOf('file:') === 0)
) {
return;
}
// readystate handler is calling before onerror or ontimeout handlers,
// so we should call onloadend on the next 'tick'
setTimeout(onloadend);
};
}
// Handle browser request cancellation (as opposed to a manual cancellation)
request.onabort = function handleAbort() {
if (!request) {
return;
}
reject(new AxiosError('Request aborted', AxiosError.ECONNABORTED, config, request));
// Clean up request
request = null;
};
// Handle low level network errors
request.onerror = function handleError(event) {
// Browsers deliver a ProgressEvent in XHR onerror
// (message may be empty; when present, surface it)
// See https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/error_event
const msg = event && event.message ? event.message : 'Network Error';
const err = new AxiosError(msg, AxiosError.ERR_NETWORK, config, request);
// attach the underlying event for consumers who want details
err.event = event || null;
reject(err);
request = null;
};
// Handle timeout
request.ontimeout = function handleTimeout() {
let timeoutErrorMessage = _config.timeout
? 'timeout of ' + _config.timeout + 'ms exceeded'
: 'timeout exceeded';
const transitional = _config.transitional || transitionalDefaults;
if (_config.timeoutErrorMessage) {
timeoutErrorMessage = _config.timeoutErrorMessage;
}
reject(
new AxiosError(
timeoutErrorMessage,
transitional.clarifyTimeoutError ? AxiosError.ETIMEDOUT : AxiosError.ECONNABORTED,
config,
request
)
);
// Clean up request
request = null;
};
// Remove Content-Type if data is undefined
requestData === undefined && requestHeaders.setContentType(null);
// Add headers to the request
if ('setRequestHeader' in request) {
utils.forEach(requestHeaders.toJSON(), function setRequestHeader(val, key) {
request.setRequestHeader(key, val);
});
}
// Add withCredentials to request if needed
if (!utils.isUndefined(_config.withCredentials)) {
request.withCredentials = !!_config.withCredentials;
}
// Add responseType to request if needed
if (responseType && responseType !== 'json') {
request.responseType = _config.responseType;
}
// Handle progress if needed
if (onDownloadProgress) {
[downloadThrottled, flushDownload] = progressEventReducer(onDownloadProgress, true);
request.addEventListener('progress', downloadThrottled);
}
// Not all browsers support upload events
if (onUploadProgress && request.upload) {
[uploadThrottled, flushUpload] = progressEventReducer(onUploadProgress);
request.upload.addEventListener('progress', uploadThrottled);
request.upload.addEventListener('loadend', flushUpload);
}
if (_config.cancelToken || _config.signal) {
// Handle cancellation
// eslint-disable-next-line func-names
onCanceled = (cancel) => {
if (!request) {
return;
}
reject(!cancel || cancel.type ? new CanceledError(null, config, request) : cancel);
request.abort();
request = null;
};
_config.cancelToken && _config.cancelToken.subscribe(onCanceled);
if (_config.signal) {
_config.signal.aborted
? onCanceled()
: _config.signal.addEventListener('abort', onCanceled);
}
}
const protocol = parseProtocol(_config.url);
if (protocol && platform.protocols.indexOf(protocol) === -1) {
reject(
new AxiosError(
'Unsupported protocol ' + protocol + ':',
AxiosError.ERR_BAD_REQUEST,
config
)
);
return;
}
// Send the request
request.send(requestData || null);
});
};

View File

@@ -0,0 +1,89 @@
'use strict';
import utils from './utils.js';
import bind from './helpers/bind.js';
import Axios from './core/Axios.js';
import mergeConfig from './core/mergeConfig.js';
import defaults from './defaults/index.js';
import formDataToJSON from './helpers/formDataToJSON.js';
import CanceledError from './cancel/CanceledError.js';
import CancelToken from './cancel/CancelToken.js';
import isCancel from './cancel/isCancel.js';
import { VERSION } from './env/data.js';
import toFormData from './helpers/toFormData.js';
import AxiosError from './core/AxiosError.js';
import spread from './helpers/spread.js';
import isAxiosError from './helpers/isAxiosError.js';
import AxiosHeaders from './core/AxiosHeaders.js';
import adapters from './adapters/adapters.js';
import HttpStatusCode from './helpers/HttpStatusCode.js';
/**
* Create an instance of Axios
*
* @param {Object} defaultConfig The default config for the instance
*
* @returns {Axios} A new instance of Axios
*/
function createInstance(defaultConfig) {
const context = new Axios(defaultConfig);
const instance = bind(Axios.prototype.request, context);
// Copy axios.prototype to instance
utils.extend(instance, Axios.prototype, context, { allOwnKeys: true });
// Copy context to instance
utils.extend(instance, context, null, { allOwnKeys: true });
// Factory for creating new instances
instance.create = function create(instanceConfig) {
return createInstance(mergeConfig(defaultConfig, instanceConfig));
};
return instance;
}
// Create the default instance to be exported
const axios = createInstance(defaults);
// Expose Axios class to allow class inheritance
axios.Axios = Axios;
// Expose Cancel & CancelToken
axios.CanceledError = CanceledError;
axios.CancelToken = CancelToken;
axios.isCancel = isCancel;
axios.VERSION = VERSION;
axios.toFormData = toFormData;
// Expose AxiosError class
axios.AxiosError = AxiosError;
// alias for CanceledError for backward compatibility
axios.Cancel = axios.CanceledError;
// Expose all/spread
axios.all = function all(promises) {
return Promise.all(promises);
};
axios.spread = spread;
// Expose isAxiosError
axios.isAxiosError = isAxiosError;
// Expose mergeConfig
axios.mergeConfig = mergeConfig;
axios.AxiosHeaders = AxiosHeaders;
axios.formToJSON = (thing) => formDataToJSON(utils.isHTMLForm(thing) ? new FormData(thing) : thing);
axios.getAdapter = adapters.getAdapter;
axios.HttpStatusCode = HttpStatusCode;
axios.default = axios;
// this module should only have a default export
export default axios;

Some files were not shown because too many files have changed in this diff Show More