-
-
Notifications
You must be signed in to change notification settings - Fork 24.3k
/
Copy pathtop-languages-fetcher.js
111 lines (99 loc) · 2.84 KB
/
top-languages-fetcher.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
// @ts-check
const { request, logger, MissingParamError } = require("../common/utils");
const retryer = require("../common/retryer");
require("dotenv").config();
/**
* @param {import('Axios').AxiosRequestHeaders} variables
* @param {string} token
*/
const fetcher = (variables, token) => {
return request(
{
query: `
query userInfo($login: String!) {
user(login: $login) {
# fetch only owner repos & not forks
repositories(ownerAffiliations: OWNER, isFork: false, first: 100) {
nodes {
name
languages(first: 10, orderBy: {field: SIZE, direction: DESC}) {
edges {
size
node {
color
name
}
}
}
}
}
}
}
`,
variables,
},
{
Authorization: `token ${token}`,
},
);
};
/**
* @param {string} username
* @param {string[]} exclude_repo
* @returns {Promise<import("./types").TopLangData>}
*/
async function fetchTopLanguages(username, exclude_repo = []) {
if (!username) throw new MissingParamError(["username"]);
const res = await retryer(fetcher, { login: username });
if (res.data.errors) {
logger.error(res.data.errors);
throw Error(res.data.errors[0].message || "Could not fetch user");
}
let repoNodes = res.data.data.user.repositories.nodes;
let repoToHide = {};
// populate repoToHide map for quick lookup
// while filtering out
if (exclude_repo) {
exclude_repo.forEach((repoName) => {
repoToHide[repoName] = true;
});
}
// filter out repositories to be hidden
repoNodes = repoNodes
.sort((a, b) => b.size - a.size)
.filter((name) => {
return !repoToHide[name.name];
});
repoNodes = repoNodes
.filter((node) => {
return node.languages.edges.length > 0;
})
// flatten the list of language nodes
.reduce((acc, curr) => curr.languages.edges.concat(acc), [])
.reduce((acc, prev) => {
// get the size of the language (bytes)
let langSize = prev.size;
// if we already have the language in the accumulator
// & the current language name is same as previous name
// add the size to the language size.
if (acc[prev.node.name] && prev.node.name === acc[prev.node.name].name) {
langSize = prev.size + acc[prev.node.name].size;
}
return {
...acc,
[prev.node.name]: {
name: prev.node.name,
color: prev.node.color,
size: langSize,
},
};
}, {});
const topLangs = Object.keys(repoNodes)
.sort((a, b) => repoNodes[b].size - repoNodes[a].size)
.reduce((result, key) => {
result[key] = repoNodes[key];
return result;
}, {});
return topLangs;
}
module.exports = fetchTopLanguages;