@stats-organization/github-readme-stats-core 2.1.3 → 2.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/api/gist.d.ts.map +1 -1
- package/build/api/gist.js +34 -1
- package/build/api/index.d.ts.map +1 -1
- package/build/api/index.js +18 -1
- package/build/api/pin.d.ts.map +1 -1
- package/build/api/pin.js +17 -1
- package/build/api/top-langs.d.ts.map +1 -1
- package/build/api/top-langs.js +36 -5
- package/build/api/wakatime.d.ts.map +1 -1
- package/build/api/wakatime.js +34 -1
- package/build/calculateRank.d.ts +12 -11
- package/build/calculateRank.d.ts.map +1 -1
- package/build/calculateRank.js +18 -18
- package/build/cards/gist.d.ts.map +1 -1
- package/build/cards/gist.js +0 -1
- package/build/cards/repo.d.ts.map +1 -1
- package/build/cards/repo.js +29 -21
- package/build/cards/stats.d.ts +4 -2
- package/build/cards/stats.d.ts.map +1 -1
- package/build/cards/stats.js +21 -9
- package/build/cards/top-languages.d.ts.map +1 -1
- package/build/cards/top-languages.js +39 -12
- package/build/cards/wakatime.d.ts.map +1 -1
- package/build/cards/wakatime.js +29 -9
- package/build/common/Card.d.ts +54 -60
- package/build/common/Card.d.ts.map +1 -1
- package/build/common/Card.js +88 -61
- package/build/common/I18n.d.ts +13 -14
- package/build/common/I18n.d.ts.map +1 -1
- package/build/common/I18n.js +13 -12
- package/build/common/color.d.ts +56 -32
- package/build/common/color.d.ts.map +1 -1
- package/build/common/color.js +87 -50
- package/build/common/config.d.ts +18 -2
- package/build/common/config.d.ts.map +1 -1
- package/build/common/config.js +17 -26
- package/build/common/constants.d.ts +2 -2
- package/build/common/constants.d.ts.map +1 -1
- package/build/common/constants.js +5 -3
- package/build/common/error.d.ts +36 -29
- package/build/common/error.d.ts.map +1 -1
- package/build/common/error.js +14 -10
- package/build/common/fmt.d.ts +14 -13
- package/build/common/fmt.d.ts.map +1 -1
- package/build/common/fmt.js +19 -15
- package/build/common/html.d.ts +2 -4
- package/build/common/html.d.ts.map +1 -1
- package/build/common/html.js +2 -6
- package/build/common/http.d.ts +13 -4
- package/build/common/http.d.ts.map +1 -1
- package/build/common/http.js +3 -4
- package/build/common/icons.d.ts +22 -21
- package/build/common/icons.d.ts.map +1 -1
- package/build/common/icons.js +4 -5
- package/build/common/languageColors.json +9 -1
- package/build/common/ops.d.ts +30 -29
- package/build/common/ops.d.ts.map +1 -1
- package/build/common/ops.js +32 -38
- package/build/common/render.d.ts +115 -111
- package/build/common/render.d.ts.map +1 -1
- package/build/common/render.js +138 -88
- package/build/common/retryer.d.ts +24 -13
- package/build/common/retryer.d.ts.map +1 -1
- package/build/common/retryer.js +22 -30
- package/build/fetchers/gist.d.ts +6 -21
- package/build/fetchers/gist.d.ts.map +1 -1
- package/build/fetchers/gist.js +30 -36
- package/build/fetchers/repo.d.ts.map +1 -1
- package/build/fetchers/repo.js +4 -7
- package/build/fetchers/stats.d.ts.map +1 -1
- package/build/fetchers/stats.js +3 -7
- package/build/fetchers/top-languages.d.ts.map +1 -1
- package/build/fetchers/top-languages.js +0 -1
- package/build/fetchers/types.d.ts +126 -0
- package/build/fetchers/types.d.ts.map +1 -0
- package/build/fetchers/types.js +1 -0
- package/build/fetchers/wakatime.d.ts.map +1 -1
- package/build/fetchers/wakatime.js +0 -1
- package/build/translations.d.ts +627 -24
- package/build/translations.d.ts.map +1 -1
- package/build/translations.js +7 -8
- package/package.json +4 -4
- package/src/_emoji-name-map.d.ts +10 -0
- package/src/api/gist.js +36 -2
- package/src/api/index.js +19 -2
- package/src/api/pin.js +18 -2
- package/src/api/top-langs.js +38 -6
- package/src/api/wakatime.js +36 -2
- package/src/{calculateRank.js → calculateRank.ts} +29 -19
- package/src/cards/gist.js +0 -2
- package/src/cards/repo.js +30 -22
- package/src/cards/stats.js +22 -10
- package/src/cards/top-languages.js +49 -13
- package/src/cards/wakatime.js +33 -10
- package/src/common/Card.ts +338 -0
- package/src/common/I18n.ts +49 -0
- package/src/common/color.ts +212 -0
- package/src/common/config.ts +83 -0
- package/src/common/constants.ts +10 -0
- package/src/common/{error.js → error.ts} +20 -14
- package/src/common/{fmt.js → fmt.ts} +27 -19
- package/src/common/{html.js → html.ts} +3 -8
- package/src/common/http.ts +31 -0
- package/src/common/{icons.js → icons.ts} +9 -7
- package/src/common/languageColors.json +9 -1
- package/src/common/{ops.js → ops.ts} +48 -52
- package/src/common/{render.js → render.ts} +208 -98
- package/src/common/retryer.ts +125 -0
- package/src/fetchers/gist.ts +136 -0
- package/src/fetchers/repo.js +4 -8
- package/src/fetchers/stats.js +3 -8
- package/src/fetchers/top-languages.js +0 -2
- package/src/fetchers/{types.d.ts → types.ts} +1 -1
- package/src/fetchers/wakatime.js +0 -2
- package/src/{translations.js → translations.ts} +14 -10
- package/src/common/Card.js +0 -275
- package/src/common/I18n.js +0 -42
- package/src/common/color.js +0 -145
- package/src/common/config.js +0 -78
- package/src/common/constants.js +0 -9
- package/src/common/http.js +0 -21
- package/src/common/retryer.js +0 -104
- package/src/fetchers/gist.js +0 -114
package/src/common/I18n.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
const FALLBACK_LOCALE = "en";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* I18n translation class.
|
|
7
|
-
*/
|
|
8
|
-
class I18n {
|
|
9
|
-
/**
|
|
10
|
-
* Constructor.
|
|
11
|
-
*
|
|
12
|
-
* @param {Object} options Options.
|
|
13
|
-
* @param {string=} options.locale Locale.
|
|
14
|
-
* @param {any} options.translations Translations.
|
|
15
|
-
*/
|
|
16
|
-
constructor({ locale, translations }) {
|
|
17
|
-
this.locale = locale || FALLBACK_LOCALE;
|
|
18
|
-
this.translations = translations;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Get translation.
|
|
23
|
-
*
|
|
24
|
-
* @param {string} str String to translate.
|
|
25
|
-
* @returns {string} Translated string.
|
|
26
|
-
*/
|
|
27
|
-
t(str) {
|
|
28
|
-
if (!this.translations[str]) {
|
|
29
|
-
throw new Error(`${str} Translation string not found`);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (!this.translations[str][this.locale]) {
|
|
33
|
-
throw new Error(
|
|
34
|
-
`'${str}' translation not found for locale '${this.locale}'`,
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return this.translations[str][this.locale];
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export { I18n };
|
package/src/common/color.js
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
import { themes } from "../themes/index.js";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Checks if a string is a valid hex color.
|
|
7
|
-
*
|
|
8
|
-
* @param {string} hexColor String to check.
|
|
9
|
-
* @returns {boolean} True if the given string is a valid hex color.
|
|
10
|
-
*/
|
|
11
|
-
const isValidHexColor = (hexColor) => {
|
|
12
|
-
return new RegExp(
|
|
13
|
-
/^([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|[A-Fa-f0-9]{4})$/,
|
|
14
|
-
).test(hexColor);
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Check if the given string is a valid gradient.
|
|
19
|
-
*
|
|
20
|
-
* @param {string[]} colors Array of colors.
|
|
21
|
-
* @returns {boolean} True if the given string is a valid gradient.
|
|
22
|
-
*/
|
|
23
|
-
const isValidGradient = (colors) => {
|
|
24
|
-
return (
|
|
25
|
-
colors.length > 2 &&
|
|
26
|
-
colors.slice(1).every((color) => isValidHexColor(color))
|
|
27
|
-
);
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Retrieves a gradient if color has more than one valid hex codes else a single color.
|
|
32
|
-
*
|
|
33
|
-
* @param {string} color The color to parse.
|
|
34
|
-
* @param {string | string[]} fallbackColor The fallback color.
|
|
35
|
-
* @returns {string | string[]} The gradient or color.
|
|
36
|
-
*/
|
|
37
|
-
const fallbackColor = (color, fallbackColor) => {
|
|
38
|
-
let gradient = null;
|
|
39
|
-
|
|
40
|
-
let colors = color ? color.split(",") : [];
|
|
41
|
-
if (colors.length > 1 && isValidGradient(colors)) {
|
|
42
|
-
gradient = colors;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return (
|
|
46
|
-
(gradient ? gradient : isValidHexColor(color) && `#${color}`) ||
|
|
47
|
-
fallbackColor
|
|
48
|
-
);
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Object containing card colors.
|
|
53
|
-
* @typedef {{
|
|
54
|
-
* titleColor: string;
|
|
55
|
-
* iconColor: string;
|
|
56
|
-
* textColor: string;
|
|
57
|
-
* bgColor: string | string[];
|
|
58
|
-
* borderColor: string;
|
|
59
|
-
* ringColor: string;
|
|
60
|
-
* }} CardColors
|
|
61
|
-
*/
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Returns theme based colors with proper overrides and defaults.
|
|
65
|
-
*
|
|
66
|
-
* @param {Object} args Function arguments.
|
|
67
|
-
* @param {string=} args.title_color Card title color.
|
|
68
|
-
* @param {string=} args.text_color Card text color.
|
|
69
|
-
* @param {string=} args.icon_color Card icon color.
|
|
70
|
-
* @param {string=} args.bg_color Card background color.
|
|
71
|
-
* @param {string=} args.border_color Card border color.
|
|
72
|
-
* @param {string=} args.ring_color Card ring color.
|
|
73
|
-
* @param {string=} args.theme Card theme.
|
|
74
|
-
* @returns {CardColors} Card colors.
|
|
75
|
-
*/
|
|
76
|
-
const getCardColors = ({
|
|
77
|
-
title_color,
|
|
78
|
-
text_color,
|
|
79
|
-
icon_color,
|
|
80
|
-
bg_color,
|
|
81
|
-
border_color,
|
|
82
|
-
ring_color,
|
|
83
|
-
theme,
|
|
84
|
-
}) => {
|
|
85
|
-
const defaultTheme = themes["default"];
|
|
86
|
-
const isThemeProvided =
|
|
87
|
-
theme !== null && theme !== undefined && theme in themes;
|
|
88
|
-
|
|
89
|
-
// @ts-ignore
|
|
90
|
-
const selectedTheme = isThemeProvided ? themes[theme] : defaultTheme;
|
|
91
|
-
|
|
92
|
-
const defaultBorderColor =
|
|
93
|
-
"border_color" in selectedTheme
|
|
94
|
-
? selectedTheme.border_color
|
|
95
|
-
: // @ts-ignore
|
|
96
|
-
defaultTheme.border_color;
|
|
97
|
-
|
|
98
|
-
// get the color provided by the user else the theme color
|
|
99
|
-
// finally if both colors are invalid fallback to default theme
|
|
100
|
-
const titleColor = fallbackColor(
|
|
101
|
-
title_color || selectedTheme.title_color,
|
|
102
|
-
"#" + defaultTheme.title_color,
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
// get the color provided by the user else the theme color
|
|
106
|
-
// finally if both colors are invalid we use the titleColor
|
|
107
|
-
const ringColor = fallbackColor(
|
|
108
|
-
// @ts-ignore
|
|
109
|
-
ring_color || selectedTheme.ring_color,
|
|
110
|
-
titleColor,
|
|
111
|
-
);
|
|
112
|
-
const iconColor = fallbackColor(
|
|
113
|
-
icon_color || selectedTheme.icon_color,
|
|
114
|
-
"#" + defaultTheme.icon_color,
|
|
115
|
-
);
|
|
116
|
-
const textColor = fallbackColor(
|
|
117
|
-
text_color || selectedTheme.text_color,
|
|
118
|
-
"#" + defaultTheme.text_color,
|
|
119
|
-
);
|
|
120
|
-
const bgColor = fallbackColor(
|
|
121
|
-
bg_color || selectedTheme.bg_color,
|
|
122
|
-
"#" + defaultTheme.bg_color,
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
const borderColor = fallbackColor(
|
|
126
|
-
border_color || defaultBorderColor,
|
|
127
|
-
"#" + defaultBorderColor,
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
if (
|
|
131
|
-
typeof titleColor !== "string" ||
|
|
132
|
-
typeof textColor !== "string" ||
|
|
133
|
-
typeof ringColor !== "string" ||
|
|
134
|
-
typeof iconColor !== "string" ||
|
|
135
|
-
typeof borderColor !== "string"
|
|
136
|
-
) {
|
|
137
|
-
throw new Error(
|
|
138
|
-
"Unexpected behavior, all colors except background should be string.",
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return { titleColor, iconColor, textColor, bgColor, borderColor, ringColor };
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
export { fallbackColor, getCardColors };
|
package/src/common/config.js
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @param {string | undefined} value Comma-separated string.
|
|
5
|
-
* @returns {string[] | undefined} Parsed string values.
|
|
6
|
-
*/
|
|
7
|
-
const parseCsv = (value) => {
|
|
8
|
-
if (!value) {
|
|
9
|
-
return undefined;
|
|
10
|
-
}
|
|
11
|
-
return value.split(",");
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @param {Record<string, string | undefined>} env Environment variables to inspect.
|
|
16
|
-
* @returns {{name: string, value: string}[]} Personal access tokens found in the environment.
|
|
17
|
-
*/
|
|
18
|
-
const parsePATsFromEnv = (env) => {
|
|
19
|
-
return Object.keys(env)
|
|
20
|
-
.filter((key) => /PAT_\d*$/.exec(key))
|
|
21
|
-
.map((name) => ({
|
|
22
|
-
name,
|
|
23
|
-
value: env[name],
|
|
24
|
-
}));
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* @returns {Record<string, string | undefined>} `process.env` if available, otherwise `{}`.
|
|
29
|
-
*/
|
|
30
|
-
const getDefaultEnv = () => {
|
|
31
|
-
if (typeof process !== "undefined" && process?.env) {
|
|
32
|
-
return process.env;
|
|
33
|
-
}
|
|
34
|
-
return {};
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* @param {Partial<ReturnType<typeof loadConfigFromEnv>>} config (Partial) config values to normalize.
|
|
39
|
-
* @returns {{
|
|
40
|
-
* whitelist: string[] | undefined,
|
|
41
|
-
* gistWhitelist: string[] | undefined,
|
|
42
|
-
* excludeRepositories: string[],
|
|
43
|
-
* fetchMultiPageStars: string | undefined,
|
|
44
|
-
* pats: {name: string, value: string}[],
|
|
45
|
-
* }} Normalized config object with defaults applied.
|
|
46
|
-
*/
|
|
47
|
-
const normalizeConfig = (config = {}) => {
|
|
48
|
-
return {
|
|
49
|
-
whitelist: config.whitelist,
|
|
50
|
-
gistWhitelist: config.gistWhitelist,
|
|
51
|
-
excludeRepositories: config.excludeRepositories || [],
|
|
52
|
-
fetchMultiPageStars: config.fetchMultiPageStars,
|
|
53
|
-
pats: config.pats || [],
|
|
54
|
-
};
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
let currentConfig;
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* @param {Record<string, string | undefined>} env Environment variables used to build the runtime config.
|
|
61
|
-
*/
|
|
62
|
-
export const loadConfigFromEnv = (env = getDefaultEnv()) => {
|
|
63
|
-
const whitelist = parseCsv(env.WHITELIST);
|
|
64
|
-
const gistWhitelist = parseCsv(env.GIST_WHITELIST);
|
|
65
|
-
const excludeRepositories = parseCsv(env.EXCLUDE_REPO) || [];
|
|
66
|
-
|
|
67
|
-
currentConfig = normalizeConfig({
|
|
68
|
-
whitelist,
|
|
69
|
-
gistWhitelist,
|
|
70
|
-
excludeRepositories,
|
|
71
|
-
fetchMultiPageStars: env.FETCH_MULTI_PAGE_STARS,
|
|
72
|
-
pats: parsePATsFromEnv(env),
|
|
73
|
-
});
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
loadConfigFromEnv();
|
|
77
|
-
|
|
78
|
-
export const getConfig = () => currentConfig;
|
package/src/common/constants.js
DELETED
package/src/common/http.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
import axios from "axios";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Send GraphQL request to GitHub API.
|
|
7
|
-
*
|
|
8
|
-
* @param {import('axios').AxiosRequestConfig['data']} data Request data.
|
|
9
|
-
* @param {import('axios').AxiosRequestConfig['headers']} headers Request headers.
|
|
10
|
-
* @returns {Promise<any>} Request response.
|
|
11
|
-
*/
|
|
12
|
-
const request = (data, headers) => {
|
|
13
|
-
return axios({
|
|
14
|
-
url: "https://api.github.com/graphql",
|
|
15
|
-
method: "post",
|
|
16
|
-
headers,
|
|
17
|
-
data,
|
|
18
|
-
});
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export { request };
|
package/src/common/retryer.js
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
import { getConfig } from "./config.js";
|
|
4
|
-
import { CustomError } from "./error.js";
|
|
5
|
-
import { logger } from "./log.js";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Returns a random integer from 0 (inclusive) to `max` (exclusive).
|
|
9
|
-
*
|
|
10
|
-
* The value is generated using `Math.random()` and uniformly distributed
|
|
11
|
-
* across the range.
|
|
12
|
-
*
|
|
13
|
-
* @param {number} max The upper bound (exclusive). Must be a positive number.
|
|
14
|
-
*
|
|
15
|
-
* @returns {number} A random integer `n` such that `0 <= n < max`.
|
|
16
|
-
*/
|
|
17
|
-
function getRandomInt(max) {
|
|
18
|
-
return Math.floor(Math.random() * max);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* @typedef {import("axios").AxiosResponse} AxiosResponse Axios response.
|
|
23
|
-
* @typedef {(variables: any, token: string, retriesForTests?: number) => Promise<AxiosResponse>} FetcherFunction Fetcher function.
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Try to execute the fetcher function until it succeeds or the max number of retries is reached.
|
|
28
|
-
*
|
|
29
|
-
* @param {FetcherFunction} fetcher The fetcher function.
|
|
30
|
-
* @param {any} variables Object with arguments to pass to the fetcher function.
|
|
31
|
-
* @param {string | null} pat Optional PAT override.
|
|
32
|
-
* @returns {Promise<any>} The response from the fetcher function.
|
|
33
|
-
*/
|
|
34
|
-
const retryer = async (fetcher, variables, pat = null) => {
|
|
35
|
-
let PATs;
|
|
36
|
-
if (pat) {
|
|
37
|
-
PATs = [{ name: "user PAT from database", value: pat }];
|
|
38
|
-
} else {
|
|
39
|
-
PATs = getConfig().pats;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (!PATs.length) {
|
|
43
|
-
throw new CustomError("No GitHub API tokens found", CustomError.NO_TOKENS);
|
|
44
|
-
}
|
|
45
|
-
const startPAT = getRandomInt(PATs.length);
|
|
46
|
-
|
|
47
|
-
for (let retries = 0; retries < PATs.length; retries++) {
|
|
48
|
-
const currentPAT = PATs[(startPAT + retries) % PATs.length];
|
|
49
|
-
|
|
50
|
-
try {
|
|
51
|
-
let response = await fetcher(
|
|
52
|
-
variables,
|
|
53
|
-
// @ts-ignore
|
|
54
|
-
currentPAT.value,
|
|
55
|
-
// used in tests for faking rate limit
|
|
56
|
-
retries,
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
// react on both type and message-based rate-limit signals.
|
|
60
|
-
// https://github.com/anuraghazra/github-readme-stats/issues/4425
|
|
61
|
-
const errors = response?.data?.errors;
|
|
62
|
-
const errorType = errors?.[0]?.type;
|
|
63
|
-
const errorMsg = errors?.[0]?.message || "";
|
|
64
|
-
const isRateLimited =
|
|
65
|
-
(errors && errorType === "RATE_LIMITED") ||
|
|
66
|
-
/rate limit/i.test(errorMsg);
|
|
67
|
-
|
|
68
|
-
if (isRateLimited) {
|
|
69
|
-
logger.log(`${currentPAT.name} Failed due to rate limiting`);
|
|
70
|
-
} else {
|
|
71
|
-
return response;
|
|
72
|
-
}
|
|
73
|
-
} catch (err) {
|
|
74
|
-
/** @type {any} */
|
|
75
|
-
const e = err;
|
|
76
|
-
|
|
77
|
-
// network/unexpected error → let caller treat as failure
|
|
78
|
-
if (!e?.response) {
|
|
79
|
-
throw e;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// prettier-ignore
|
|
83
|
-
// also checking for bad credentials if any tokens gets invalidated
|
|
84
|
-
const isBadCredential =
|
|
85
|
-
e?.response?.data?.message === "Bad credentials";
|
|
86
|
-
const isAccountSuspended =
|
|
87
|
-
e?.response?.data?.message === "Sorry. Your account was suspended.";
|
|
88
|
-
|
|
89
|
-
if (isBadCredential || isAccountSuspended) {
|
|
90
|
-
logger.log(`${currentPAT.name} Failed due to bad credentials`);
|
|
91
|
-
} else {
|
|
92
|
-
// HTTP error with a response → return it for caller-side handling
|
|
93
|
-
return e.response;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
throw new CustomError(
|
|
99
|
-
"Downtime due to GitHub API rate limiting",
|
|
100
|
-
CustomError.MAX_RETRY,
|
|
101
|
-
);
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
export { retryer };
|
package/src/fetchers/gist.js
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
import { MissingParamError } from "../common/error.js";
|
|
4
|
-
import { request } from "../common/http.js";
|
|
5
|
-
import { retryer } from "../common/retryer.js";
|
|
6
|
-
|
|
7
|
-
const QUERY = `
|
|
8
|
-
query gistInfo($gistName: String!) {
|
|
9
|
-
viewer {
|
|
10
|
-
gist(name: $gistName) {
|
|
11
|
-
description
|
|
12
|
-
owner {
|
|
13
|
-
login
|
|
14
|
-
}
|
|
15
|
-
stargazerCount
|
|
16
|
-
forks {
|
|
17
|
-
totalCount
|
|
18
|
-
}
|
|
19
|
-
files {
|
|
20
|
-
name
|
|
21
|
-
language {
|
|
22
|
-
name
|
|
23
|
-
}
|
|
24
|
-
size
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
`;
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Gist data fetcher.
|
|
33
|
-
*
|
|
34
|
-
* @param {object} variables Fetcher variables.
|
|
35
|
-
* @param {string} token GitHub token.
|
|
36
|
-
* @returns {Promise<import('axios').AxiosResponse>} The response.
|
|
37
|
-
*/
|
|
38
|
-
const fetcher = async (variables, token) => {
|
|
39
|
-
return await request(
|
|
40
|
-
{ query: QUERY, variables },
|
|
41
|
-
{ Authorization: `token ${token}` },
|
|
42
|
-
);
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* @typedef {{ name: string; language: { name: string; }, size: number }} GistFile Gist file.
|
|
47
|
-
*/
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* This function calculates the primary language of a gist by files size.
|
|
51
|
-
*
|
|
52
|
-
* @param {GistFile[]} files Files.
|
|
53
|
-
* @returns {string} Primary language.
|
|
54
|
-
*/
|
|
55
|
-
const calculatePrimaryLanguage = (files) => {
|
|
56
|
-
/** @type {Record<string, number>} */
|
|
57
|
-
const languages = {};
|
|
58
|
-
|
|
59
|
-
for (const file of files) {
|
|
60
|
-
if (file.language) {
|
|
61
|
-
if (languages[file.language.name]) {
|
|
62
|
-
languages[file.language.name] += file.size;
|
|
63
|
-
} else {
|
|
64
|
-
languages[file.language.name] = file.size;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
let primaryLanguage = Object.keys(languages)[0];
|
|
70
|
-
for (const language in languages) {
|
|
71
|
-
if (languages[language] > languages[primaryLanguage]) {
|
|
72
|
-
primaryLanguage = language;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return primaryLanguage;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* @typedef {import('./types').GistData} GistData Gist data.
|
|
81
|
-
*/
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Fetch GitHub gist information by given username and ID.
|
|
85
|
-
*
|
|
86
|
-
* @param {string} id GitHub gist ID.
|
|
87
|
-
* @param {string | null} pat Optional PAT override.
|
|
88
|
-
* @returns {Promise<GistData>} Gist data.
|
|
89
|
-
*/
|
|
90
|
-
const fetchGist = async (id, pat = null) => {
|
|
91
|
-
if (!id) {
|
|
92
|
-
throw new MissingParamError(["id"], "/api/gist?id=GIST_ID");
|
|
93
|
-
}
|
|
94
|
-
const res = await retryer(fetcher, { gistName: id }, pat);
|
|
95
|
-
if (res.data.errors) {
|
|
96
|
-
throw new Error(res.data.errors[0].message);
|
|
97
|
-
}
|
|
98
|
-
if (!res.data.data.viewer.gist) {
|
|
99
|
-
throw new Error("Gist not found");
|
|
100
|
-
}
|
|
101
|
-
const data = res.data.data.viewer.gist;
|
|
102
|
-
return {
|
|
103
|
-
name: data.files[Object.keys(data.files)[0]].name,
|
|
104
|
-
nameWithOwner: `${data.owner.login}/${
|
|
105
|
-
data.files[Object.keys(data.files)[0]].name
|
|
106
|
-
}`,
|
|
107
|
-
description: data.description,
|
|
108
|
-
language: calculatePrimaryLanguage(data.files),
|
|
109
|
-
starsCount: data.stargazerCount,
|
|
110
|
-
forksCount: data.forks.totalCount,
|
|
111
|
-
};
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
export { fetchGist };
|