-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.ts
103 lines (87 loc) · 2.61 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import {z} from "zod";
const args = Bun.argv;
if (args.length < 2) {
throw new Error(`
Must Provide Profile Name like this
"bun run get-data Jonathan.Higger"
`);
}
const profileName = decodeURIComponent(args.at(-1) ?? "");
if (!profileName || profileName.startsWith('/')) {
throw new Error("Profile name is required and must be a valid string");
}
const CODE_CHALLENGES_API_URL = "https://www.codewars.com/api/v1/code-challenges/";
const assignmentSchema = z.object({
id: z.string(),
name: z.string(),
slug: z.string(),
completedLanguages: z.array(z.string()),
completedAt: z.string(),
});
type Assignment = z.infer<typeof assignmentSchema>;
const responseSchema = z.object({
totalPages: z.number(),
totalItems: z.number(),
data: z.array(assignmentSchema).optional(),
});
const urlWithPage = (page: number, profile: string) =>
`https://www.codewars.com/api/v1/users/${profile}/code-challenges/completed?page=${page}`;
const getAllAssignmentsForUser = async (
profileName: string,
page: number = 0,
prevAssignments: Assignment[] = [],
) => {
const result = await fetch(urlWithPage(page, profileName))
.then((response) => {
if (!response.ok) {
throw new Error(`Could not get data for ${profileName}`);
}
return response;
})
.then((response) => response.json())
.then(responseSchema.parse);
if (result.totalPages - 1 === page) {
return [...prevAssignments, ...(result?.data ?? [])];
}
return getAllAssignmentsForUser(profileName, page + 1, result.data ?? []);
};
const deepAssignmentSchema = z.object({
id: z.string(),
name: z.string(),
slug: z.string(),
category: z.string(),
publishedAt: z.string(),
// approvedAt: z.string(),
rank: z.object({
id: z.number(),
name: z.string(),
color: z.string(),
}),
});
const getAllAssignmentData = (assignmentSlug: string) =>
fetch(`${CODE_CHALLENGES_API_URL}${assignmentSlug}`)
.then((response) => response.json())
.then(deepAssignmentSchema.parse);
const allAssignments = await Promise.all(
(await getAllAssignmentsForUser(profileName)).map((assignment) =>
getAllAssignmentData(assignment.slug),
),
);
let assignmentMap = allAssignments.reduce<
Record<string, { count: number; names: string[] }>
>((acc, assignment) => {
return {
...acc,
[assignment.rank.name]: {
count: (acc[assignment.rank.name]?.count ?? 0) + 1,
names: [...(acc[assignment.rank.name]?.names ?? []), assignment.name],
},
};
}, {});
await Bun.write(
`students/${profileName}/${new Date(Date.now()).toString()}.json`,
JSON.stringify(assignmentMap, null, 2),
{
createPath: true,
},
);