-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfetch.js
185 lines (169 loc) · 6.39 KB
/
fetch.js
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// https://github.com/huchenme/github-trending-api/blob/master/src/functions/utils/fetch.js
import cheerio from 'cheerio';
const GITHUB_URL = 'https://github.com';
/**
* Filters out null and undefined values from an object.
*
* @param {object} obj - The object to filter.
* @return {object} The filtered object.
*/
function omitNil(obj) {
return Object.entries(obj).reduce((acc, [key, value]) => {
if (value !== null && value !== undefined) {
acc[key] = value;
}
return acc;
}, {});
}
/**
* Removes the default avatar size from the given source URL.
*
* @param {string} src - The source URL of the avatar image.
* @return {string} The modified source URL without the default avatar size.
*/
function removeDefaultAvatarSize(src) {
if (!src) {
return src;
}
return src.replace(/\?s=.*$/, '');
}
/**
* Fetches repositories based on the specified language, time period, and spoken language.
*
* @param {Object} options - The options for fetching repositories.
* @param {string} options.language - The language of the repositories to fetch.
* @param {string} options.since - The time period for which to fetch repositories.
* @param {string} options.spokenLanguage - The spoken language of the repositories to fetch.
* @return {Promise<Array>} An array of repository objects containing information such as author, name, avatar, url, description, language, language color, stars, forks, current period stars, and built by.
*/
export async function fetchRepositories({
language = '',
since = 'daily',
spokenLanguage = '',
} = {}) {
const url = `${GITHUB_URL}/trending/${encodeURIComponent(
language,
)}?since=${since}&spoken_language_code=${encodeURIComponent(spokenLanguage)}`;
const data = await fetch(url);
const $ = cheerio.load(await data.text());
return (
$('.Box article.Box-row')
.get()
// eslint-disable-next-line complexity
.map((repo) => {
const $repo = $(repo);
const title = $repo.find('.h3').text().trim();
const [username, repoName] = title.split('/').map((v) => v.trim());
const relativeUrl = $repo.find('.h3').find('a').attr('href');
const currentPeriodStarsString =
$repo.find('.float-sm-right').text().trim() ||
/* istanbul ignore next */ '';
const builtBy = $repo
.find('span:contains("Built by")')
.find('[data-hovercard-type="user"]')
.map((i, user) => {
const altString = $(user).children('img').attr('alt');
const avatarUrl = $(user).children('img').attr('src');
return {
username: altString ?
altString.slice(1) /* istanbul ignore next */ :
null,
href: `${GITHUB_URL}${user.attribs.href}`,
avatar: removeDefaultAvatarSize(avatarUrl),
};
})
.get();
const colorNode = $repo.find('.repo-language-color');
const langColor = colorNode.length ?
colorNode.css('background-color') :
null;
const langNode = $repo.find('[itemprop=programmingLanguage]');
const lang = langNode.length ?
langNode.text().trim() /* istanbul ignore next */ :
null;
return omitNil({
author: username,
name: repoName,
avatar: `${GITHUB_URL}/${username}.png`,
url: `${GITHUB_URL}${relativeUrl}`,
description: $repo.find('p.my-1').text().trim() || '',
language: lang,
languageColor: langColor,
stars: parseInt(
$repo
.find('.mr-3 svg[aria-label=\'star\']')
.first()
.parent()
.text()
.trim()
.replace(',', '') || /* istanbul ignore next */ '0',
10,
),
forks: parseInt(
$repo
.find('svg[aria-label=\'fork\']')
.first()
.parent()
.text()
.trim()
.replace(',', '') || /* istanbul ignore next */ '0',
10,
),
currentPeriodStars: parseInt(
currentPeriodStarsString.split(' ')[0].replace(',', '') ||
/* istanbul ignore next */ '0',
10,
),
builtBy,
});
})
);
}
/**
* Fetches developers from the GitHub API based on the specified language and time period.
*
* @param {Object} options - Optional parameters for the API request.
* @param {string} options.language - The language to filter the developers by. Defaults to an empty string.
* @param {string} options.since - The time period to filter the developers by. Defaults to 'daily'.
* @return {Promise<Array>} An array of developer objects containing their username, name, type, URL, sponsor URL, avatar, and repository information.
*/
export async function fetchDevelopers({language = '', since = 'daily'} = {}) {
const data = await fetch(
`${GITHUB_URL}/trending/developers/${language}?since=${since}`,
);
const $ = cheerio.load(await data.text());
return $('.Box article.Box-row')
.get()
.map((dev) => {
const $dev = $(dev);
const relativeUrl = $dev.find('.h3 a').attr('href');
const sponsorRelativeUrl = $dev
.find('span:contains("Sponsor")')
.parent()
.attr('href');
const name = $dev.find('.h3 a').text().trim();
const username = relativeUrl.slice(1);
const type = $dev.find('img').parent().attr('data-hovercard-type');
const $repo = $dev.find('.mt-2 > article');
$repo.find('svg').remove();
return omitNil({
username,
name,
type,
url: `${GITHUB_URL}${relativeUrl}`,
sponsorUrl: sponsorRelativeUrl ?
`${GITHUB_URL}${sponsorRelativeUrl}` :
undefined,
avatar: removeDefaultAvatarSize($dev.find('img').attr('src')),
repo: $repo.length ?
{
name: $repo.find('a').text().trim(),
description:
$repo.find('.f6.mt-1').text().trim() ||
/* istanbul ignore next */ '',
url: `${GITHUB_URL}${$repo.find('a').attr('href')}`,
} :
null,
});
});
}