@stats-organization/github-readme-stats-core 2.1.3 → 2.1.4
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 +0 -1
- package/build/api/index.d.ts.map +1 -1
- package/build/api/index.js +0 -1
- package/build/api/pin.d.ts.map +1 -1
- package/build/api/pin.js +0 -1
- package/build/api/top-langs.d.ts.map +1 -1
- package/build/api/top-langs.js +0 -1
- package/build/api/wakatime.d.ts.map +1 -1
- package/build/api/wakatime.js +0 -1
- 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 +0 -1
- package/build/cards/stats.d.ts.map +1 -1
- package/build/cards/stats.js +0 -1
- package/build/cards/top-languages.d.ts.map +1 -1
- package/build/cards/top-languages.js +0 -1
- package/build/cards/wakatime.d.ts.map +1 -1
- package/build/cards/wakatime.js +0 -1
- package/build/common/Card.d.ts +48 -60
- package/build/common/Card.d.ts.map +1 -1
- package/build/common/Card.js +49 -50
- 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 +30 -40
- package/build/common/color.d.ts.map +1 -1
- package/build/common/color.js +30 -42
- 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 +1 -5
- package/build/common/http.d.ts.map +1 -1
- package/build/common/http.js +0 -1
- 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/ops.d.ts.map +1 -1
- package/build/common/ops.js +0 -1
- package/build/common/render.d.ts.map +1 -1
- package/build/common/render.js +0 -1
- package/build/common/retryer.d.ts +18 -15
- package/build/common/retryer.d.ts.map +1 -1
- package/build/common/retryer.js +21 -30
- package/build/fetchers/gist.d.ts.map +1 -1
- package/build/fetchers/gist.js +0 -1
- package/build/fetchers/repo.d.ts.map +1 -1
- package/build/fetchers/repo.js +3 -6
- package/build/fetchers/stats.d.ts.map +1 -1
- package/build/fetchers/stats.js +3 -6
- package/build/fetchers/top-languages.d.ts.map +1 -1
- package/build/fetchers/top-languages.js +0 -1
- 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 +1 -1
- package/src/api/gist.js +0 -2
- package/src/api/index.js +0 -2
- package/src/api/pin.js +0 -2
- package/src/api/top-langs.js +0 -2
- package/src/api/wakatime.js +0 -2
- package/src/cards/gist.js +0 -2
- package/src/cards/repo.js +0 -2
- package/src/cards/stats.js +0 -2
- package/src/cards/top-languages.js +0 -2
- package/src/cards/wakatime.js +0 -2
- package/src/common/{Card.js → Card.ts} +89 -61
- package/src/common/I18n.ts +49 -0
- package/src/common/{color.js → color.ts} +55 -51
- 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.js +0 -2
- package/src/common/{icons.js → icons.ts} +9 -7
- package/src/common/ops.js +0 -2
- package/src/common/render.js +0 -2
- package/src/common/{retryer.js → retryer.ts} +45 -32
- package/src/fetchers/gist.js +0 -2
- package/src/fetchers/repo.js +3 -7
- package/src/fetchers/stats.js +3 -7
- package/src/fetchers/top-languages.js +0 -2
- package/src/fetchers/types.d.ts +1 -1
- package/src/fetchers/wakatime.js +0 -2
- package/src/{translations.js → translations.ts} +14 -10
- package/src/common/I18n.js +0 -42
- package/src/common/config.js +0 -78
- package/src/common/constants.js +0 -9
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
1
|
import { OWNER_AFFILIATIONS } from "./constants.js";
|
|
4
2
|
|
|
5
3
|
/**
|
|
6
|
-
*
|
|
4
|
+
* A general message to ask user to try again later.
|
|
7
5
|
*/
|
|
8
6
|
const TRY_AGAIN_LATER = "Please try again later";
|
|
9
7
|
|
|
10
8
|
/**
|
|
11
|
-
*
|
|
9
|
+
* A map of error types to secondary error messages.
|
|
12
10
|
*/
|
|
13
11
|
const SECONDARY_ERROR_MESSAGES = {
|
|
14
12
|
MAX_RETRY:
|
|
@@ -28,16 +26,21 @@ const SECONDARY_ERROR_MESSAGES = {
|
|
|
28
26
|
* Custom error class to handle custom GRS errors.
|
|
29
27
|
*/
|
|
30
28
|
class CustomError extends Error {
|
|
29
|
+
type: string;
|
|
30
|
+
secondaryMessage: string;
|
|
31
|
+
|
|
31
32
|
/**
|
|
32
33
|
* Custom error constructor.
|
|
33
34
|
*
|
|
34
|
-
* @param
|
|
35
|
-
* @param
|
|
35
|
+
* @param message Error message.
|
|
36
|
+
* @param type Error type.
|
|
36
37
|
*/
|
|
37
|
-
constructor(message, type) {
|
|
38
|
+
constructor(message: string, type: string) {
|
|
38
39
|
super(message);
|
|
39
40
|
this.type = type;
|
|
40
|
-
|
|
41
|
+
type PartialRecord = Partial<Record<string, string>>;
|
|
42
|
+
this.secondaryMessage =
|
|
43
|
+
(SECONDARY_ERROR_MESSAGES as PartialRecord)[type] ?? type;
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
static MAX_RETRY = "MAX_RETRY";
|
|
@@ -53,13 +56,16 @@ class CustomError extends Error {
|
|
|
53
56
|
* Missing query parameter class.
|
|
54
57
|
*/
|
|
55
58
|
class MissingParamError extends Error {
|
|
59
|
+
missedParams: Array<string>;
|
|
60
|
+
secondaryMessage: string | undefined;
|
|
61
|
+
|
|
56
62
|
/**
|
|
57
63
|
* Missing query parameter error constructor.
|
|
58
64
|
*
|
|
59
|
-
* @param
|
|
60
|
-
* @param
|
|
65
|
+
* @param missedParams An array of missing parameters names.
|
|
66
|
+
* @param secondaryMessage Optional secondary message to display.
|
|
61
67
|
*/
|
|
62
|
-
constructor(missedParams
|
|
68
|
+
constructor(missedParams: Array<string>, secondaryMessage?: string) {
|
|
63
69
|
const msg = `Missing params ${missedParams
|
|
64
70
|
.map((p) => `"${p}"`)
|
|
65
71
|
.join(", ")} make sure you pass the parameters in URL`;
|
|
@@ -72,10 +78,10 @@ class MissingParamError extends Error {
|
|
|
72
78
|
/**
|
|
73
79
|
* Retrieve secondary message from an error object.
|
|
74
80
|
*
|
|
75
|
-
* @param
|
|
76
|
-
* @returns
|
|
81
|
+
* @param err The error object.
|
|
82
|
+
* @returns The secondary message if available, otherwise undefined.
|
|
77
83
|
*/
|
|
78
|
-
const retrieveSecondaryMessage = (err) => {
|
|
84
|
+
const retrieveSecondaryMessage = (err: Error): string | undefined => {
|
|
79
85
|
return "secondaryMessage" in err && typeof err.secondaryMessage === "string"
|
|
80
86
|
? err.secondaryMessage
|
|
81
87
|
: undefined;
|
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
1
|
import { encodeHTML } from "./html.js";
|
|
4
2
|
import { splitWrappedText } from "./render.js";
|
|
5
3
|
|
|
6
4
|
/**
|
|
7
5
|
* Retrieves num with suffix k(thousands) precise to given decimal places.
|
|
8
6
|
*
|
|
9
|
-
* @param
|
|
10
|
-
* @param
|
|
11
|
-
* @returns
|
|
7
|
+
* @param num The number to format.
|
|
8
|
+
* @param precision The number of decimal places to include.
|
|
9
|
+
* @returns The formatted number.
|
|
12
10
|
*/
|
|
13
|
-
const kFormatter = (num, precision) => {
|
|
11
|
+
const kFormatter = (num: number, precision?: number): string | number => {
|
|
14
12
|
const abs = Math.abs(num);
|
|
15
13
|
const sign = Math.sign(num);
|
|
16
14
|
|
|
@@ -22,17 +20,17 @@ const kFormatter = (num, precision) => {
|
|
|
22
20
|
return sign * abs;
|
|
23
21
|
}
|
|
24
22
|
|
|
25
|
-
return sign * parseFloat((abs / 1000).toFixed(1))
|
|
23
|
+
return `${sign * parseFloat((abs / 1000).toFixed(1))}k`;
|
|
26
24
|
};
|
|
27
25
|
|
|
28
26
|
/**
|
|
29
27
|
* Convert bytes to a human-readable string representation.
|
|
30
28
|
*
|
|
31
|
-
* @param
|
|
32
|
-
* @returns
|
|
29
|
+
* @param bytes The number of bytes to convert.
|
|
30
|
+
* @returns The human-readable representation of bytes.
|
|
33
31
|
* @throws {Error} If bytes is negative or too large.
|
|
34
32
|
*/
|
|
35
|
-
const formatBytes = (bytes) => {
|
|
33
|
+
const formatBytes = (bytes: number): string => {
|
|
36
34
|
if (bytes < 0) {
|
|
37
35
|
throw new Error("Bytes must be a non-negative number");
|
|
38
36
|
}
|
|
@@ -45,23 +43,29 @@ const formatBytes = (bytes) => {
|
|
|
45
43
|
const base = 1024;
|
|
46
44
|
const i = Math.floor(Math.log(bytes) / Math.log(base));
|
|
47
45
|
|
|
48
|
-
|
|
46
|
+
const unit = sizes[i];
|
|
47
|
+
if (unit === undefined) {
|
|
49
48
|
throw new Error("Bytes is too large to convert to a human-readable string");
|
|
50
49
|
}
|
|
51
50
|
|
|
52
|
-
return `${(bytes / Math.pow(base, i)).toFixed(1)} ${
|
|
51
|
+
return `${(bytes / Math.pow(base, i)).toFixed(1)} ${unit}`;
|
|
53
52
|
};
|
|
54
53
|
|
|
55
54
|
/**
|
|
56
55
|
* Split text over multiple lines based on the card width.
|
|
57
56
|
*
|
|
58
|
-
* @param
|
|
59
|
-
* @param
|
|
60
|
-
* @param
|
|
61
|
-
* @param
|
|
62
|
-
* @returns
|
|
57
|
+
* @param text Text to split.
|
|
58
|
+
* @param width Available wrap width in px.
|
|
59
|
+
* @param fontSize Font size in px.
|
|
60
|
+
* @param maxLines Maximum number of lines.
|
|
61
|
+
* @returns Array of lines.
|
|
63
62
|
*/
|
|
64
|
-
const wrapTextMultiline = (
|
|
63
|
+
const wrapTextMultiline = (
|
|
64
|
+
text: string,
|
|
65
|
+
width: number,
|
|
66
|
+
fontSize: number,
|
|
67
|
+
maxLines = 3,
|
|
68
|
+
): Array<string> => {
|
|
65
69
|
const wrapped = splitWrappedText(text, fontSize, width);
|
|
66
70
|
const lines = wrapped
|
|
67
71
|
.map((line) => encodeHTML(line.trim()))
|
|
@@ -69,7 +73,11 @@ const wrapTextMultiline = (text, width, fontSize, maxLines = 3) => {
|
|
|
69
73
|
|
|
70
74
|
// Add "..." to the last line if the text exceeds maxLines
|
|
71
75
|
if (wrapped.length > maxLines) {
|
|
72
|
-
|
|
76
|
+
const lastIndex = maxLines - 1;
|
|
77
|
+
const lastLine = lines[lastIndex];
|
|
78
|
+
if (lastLine !== undefined) {
|
|
79
|
+
lines[lastIndex] = `${lastLine}...`;
|
|
80
|
+
}
|
|
73
81
|
}
|
|
74
82
|
|
|
75
83
|
// Remove empty lines if text fits in less than maxLines lines
|
|
@@ -1,18 +1,13 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Encode string as HTML.
|
|
5
3
|
*
|
|
6
4
|
* @see https://stackoverflow.com/a/48073476/10629172
|
|
7
|
-
*
|
|
8
|
-
* @param {string} str String to encode.
|
|
9
|
-
* @returns {string} Encoded string.
|
|
10
5
|
*/
|
|
11
|
-
const encodeHTML = (str) => {
|
|
6
|
+
const encodeHTML = (str: string): string => {
|
|
12
7
|
return (
|
|
13
8
|
str
|
|
14
|
-
.replace(/[\u00A0-\u9999<>&](?!#)/gim, (i) => {
|
|
15
|
-
return
|
|
9
|
+
.replace(/[\u00A0-\u9999<>&](?!#)/gim, (i: string) => {
|
|
10
|
+
return `&#${i.charCodeAt(0)};`;
|
|
16
11
|
})
|
|
17
12
|
// eslint-disable-next-line no-control-regex
|
|
18
13
|
.replace(/\u0008/gim, "")
|
package/src/common/http.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
1
|
/*
|
|
4
2
|
The icons in this file are based on https://github.com/primer/octicons which is released under the MIT license:
|
|
5
3
|
|
|
@@ -46,12 +44,16 @@ const icons = {
|
|
|
46
44
|
/**
|
|
47
45
|
* Get rank icon
|
|
48
46
|
*
|
|
49
|
-
* @param
|
|
50
|
-
* @param
|
|
51
|
-
* @param
|
|
52
|
-
* @returns
|
|
47
|
+
* @param rankIcon - The rank icon type.
|
|
48
|
+
* @param rankLevel - The rank level.
|
|
49
|
+
* @param percentile - The rank percentile.
|
|
50
|
+
* @returns The SVG code of the rank icon
|
|
53
51
|
*/
|
|
54
|
-
const rankIcon = (
|
|
52
|
+
const rankIcon = (
|
|
53
|
+
rankIcon: string,
|
|
54
|
+
rankLevel: string,
|
|
55
|
+
percentile: number,
|
|
56
|
+
): string => {
|
|
55
57
|
switch (rankIcon) {
|
|
56
58
|
case "github":
|
|
57
59
|
return `
|
package/src/common/ops.js
CHANGED
package/src/common/render.js
CHANGED
|
@@ -1,43 +1,56 @@
|
|
|
1
|
-
|
|
1
|
+
import type { AxiosResponse } from "axios";
|
|
2
2
|
|
|
3
3
|
import { getConfig } from "./config.js";
|
|
4
4
|
import { CustomError } from "./error.js";
|
|
5
5
|
import { logger } from "./log.js";
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Subset of the response payload the retryer inspects to detect
|
|
9
|
+
* rate-limiting and credential failures.
|
|
10
|
+
*/
|
|
11
|
+
interface ResponseData {
|
|
12
|
+
errors?: Array<{ type?: string; message?: string }>;
|
|
13
|
+
message?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
7
16
|
/**
|
|
8
17
|
* Returns a random integer from 0 (inclusive) to `max` (exclusive).
|
|
9
18
|
*
|
|
10
19
|
* The value is generated using `Math.random()` and uniformly distributed
|
|
11
20
|
* across the range.
|
|
12
21
|
*
|
|
13
|
-
* @param
|
|
22
|
+
* @param max The upper bound (exclusive). Must be a positive number.
|
|
14
23
|
*
|
|
15
|
-
* @returns
|
|
24
|
+
* @returns A random integer `n` such that `0 <= n < max`.
|
|
16
25
|
*/
|
|
17
|
-
function getRandomInt(max) {
|
|
26
|
+
function getRandomInt(max: number): number {
|
|
18
27
|
return Math.floor(Math.random() * max);
|
|
19
28
|
}
|
|
20
29
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
30
|
+
type FetcherResponse = AxiosResponse<ResponseData>;
|
|
31
|
+
|
|
32
|
+
type FetcherFunction = (
|
|
33
|
+
variables: Record<string, unknown>,
|
|
34
|
+
token: string,
|
|
35
|
+
retriesForTests?: number,
|
|
36
|
+
) => Promise<FetcherResponse>;
|
|
25
37
|
|
|
26
38
|
/**
|
|
27
39
|
* Try to execute the fetcher function until it succeeds or the max number of retries is reached.
|
|
28
40
|
*
|
|
29
|
-
* @param
|
|
30
|
-
* @param
|
|
31
|
-
* @param
|
|
32
|
-
* @returns
|
|
41
|
+
* @param fetcher The fetcher function.
|
|
42
|
+
* @param variables Object with arguments to pass to the fetcher function.
|
|
43
|
+
* @param pat Optional PAT override.
|
|
44
|
+
* @returns The response from the fetcher function.
|
|
33
45
|
*/
|
|
34
|
-
const retryer = async (
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
46
|
+
const retryer = async (
|
|
47
|
+
fetcher: FetcherFunction,
|
|
48
|
+
variables: Record<string, unknown>,
|
|
49
|
+
pat: string | null = null,
|
|
50
|
+
): Promise<FetcherResponse> => {
|
|
51
|
+
const PATs = pat
|
|
52
|
+
? [{ name: "user PAT from database", value: pat }]
|
|
53
|
+
: getConfig().pats;
|
|
41
54
|
|
|
42
55
|
if (!PATs.length) {
|
|
43
56
|
throw new CustomError("No GitHub API tokens found", CustomError.NO_TOKENS);
|
|
@@ -46,11 +59,13 @@ const retryer = async (fetcher, variables, pat = null) => {
|
|
|
46
59
|
|
|
47
60
|
for (let retries = 0; retries < PATs.length; retries++) {
|
|
48
61
|
const currentPAT = PATs[(startPAT + retries) % PATs.length];
|
|
62
|
+
if (!currentPAT) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
49
65
|
|
|
50
66
|
try {
|
|
51
|
-
|
|
67
|
+
const response = await fetcher(
|
|
52
68
|
variables,
|
|
53
|
-
// @ts-ignore
|
|
54
69
|
currentPAT.value,
|
|
55
70
|
// used in tests for faking rate limit
|
|
56
71
|
retries,
|
|
@@ -58,11 +73,11 @@ const retryer = async (fetcher, variables, pat = null) => {
|
|
|
58
73
|
|
|
59
74
|
// react on both type and message-based rate-limit signals.
|
|
60
75
|
// https://github.com/anuraghazra/github-readme-stats/issues/4425
|
|
61
|
-
const errors = response
|
|
76
|
+
const errors = response.data.errors;
|
|
62
77
|
const errorType = errors?.[0]?.type;
|
|
63
|
-
const errorMsg = errors?.[0]?.message
|
|
78
|
+
const errorMsg = errors?.[0]?.message ?? "";
|
|
64
79
|
const isRateLimited =
|
|
65
|
-
(errors && errorType === "RATE_LIMITED") ||
|
|
80
|
+
(!!errors && errorType === "RATE_LIMITED") ||
|
|
66
81
|
/rate limit/i.test(errorMsg);
|
|
67
82
|
|
|
68
83
|
if (isRateLimited) {
|
|
@@ -71,20 +86,18 @@ const retryer = async (fetcher, variables, pat = null) => {
|
|
|
71
86
|
return response;
|
|
72
87
|
}
|
|
73
88
|
} catch (err) {
|
|
74
|
-
|
|
75
|
-
const e = err;
|
|
89
|
+
const e = err as { response?: FetcherResponse };
|
|
76
90
|
|
|
77
91
|
// network/unexpected error → let caller treat as failure
|
|
78
|
-
if (!e
|
|
79
|
-
throw
|
|
92
|
+
if (!e.response) {
|
|
93
|
+
throw err;
|
|
80
94
|
}
|
|
81
95
|
|
|
82
|
-
// prettier-ignore
|
|
83
96
|
// also checking for bad credentials if any tokens gets invalidated
|
|
84
|
-
const
|
|
85
|
-
|
|
97
|
+
const message = e.response.data.message;
|
|
98
|
+
const isBadCredential = message === "Bad credentials";
|
|
86
99
|
const isAccountSuspended =
|
|
87
|
-
|
|
100
|
+
message === "Sorry. Your account was suspended.";
|
|
88
101
|
|
|
89
102
|
if (isBadCredential || isAccountSuspended) {
|
|
90
103
|
logger.log(`${currentPAT.name} Failed due to bad credentials`);
|
package/src/fetchers/gist.js
CHANGED
package/src/fetchers/repo.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
1
|
import { MissingParamError } from "../common/error.js";
|
|
4
2
|
import { request } from "../common/http.js";
|
|
5
3
|
import { retryer } from "../common/retryer.js";
|
|
@@ -23,9 +21,7 @@ const fetcher = (variables, token) => {
|
|
|
23
21
|
isPrivate
|
|
24
22
|
isArchived
|
|
25
23
|
isTemplate
|
|
26
|
-
|
|
27
|
-
totalCount
|
|
28
|
-
}
|
|
24
|
+
stargazerCount
|
|
29
25
|
description
|
|
30
26
|
primaryLanguage {
|
|
31
27
|
color
|
|
@@ -130,7 +126,7 @@ const fetchRepo = async (
|
|
|
130
126
|
return {
|
|
131
127
|
...repoUserStats,
|
|
132
128
|
...data.user.repository,
|
|
133
|
-
starCount: data.user.repository.
|
|
129
|
+
starCount: data.user.repository.stargazerCount,
|
|
134
130
|
};
|
|
135
131
|
}
|
|
136
132
|
|
|
@@ -155,7 +151,7 @@ const fetchRepo = async (
|
|
|
155
151
|
return {
|
|
156
152
|
...repoUserStats,
|
|
157
153
|
...data.organization.repository,
|
|
158
|
-
starCount: data.organization.repository.
|
|
154
|
+
starCount: data.organization.repository.stargazerCount,
|
|
159
155
|
};
|
|
160
156
|
}
|
|
161
157
|
|
package/src/fetchers/stats.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
1
|
import axios from "axios";
|
|
4
2
|
import githubUsernameRegex from "github-username-regex";
|
|
5
3
|
|
|
@@ -18,9 +16,7 @@ const GRAPHQL_REPOS_FIELD = `
|
|
|
18
16
|
totalCount
|
|
19
17
|
nodes {
|
|
20
18
|
name
|
|
21
|
-
|
|
22
|
-
totalCount
|
|
23
|
-
}
|
|
19
|
+
stargazerCount
|
|
24
20
|
}
|
|
25
21
|
pageInfo {
|
|
26
22
|
hasNextPage
|
|
@@ -159,7 +155,7 @@ const statsFetcher = async ({
|
|
|
159
155
|
// Disable multi page fetching on public Vercel instance due to rate limits.
|
|
160
156
|
fetchedPages++;
|
|
161
157
|
const repoNodesWithStars = repoNodes.filter(
|
|
162
|
-
(node) => node.
|
|
158
|
+
(node) => node.stargazerCount !== 0,
|
|
163
159
|
);
|
|
164
160
|
|
|
165
161
|
hasNextPage =
|
|
@@ -458,7 +454,7 @@ const fetchStats = async (
|
|
|
458
454
|
return !repoToHide.has(data.name);
|
|
459
455
|
})
|
|
460
456
|
.reduce((prev, curr) => {
|
|
461
|
-
return prev + curr.
|
|
457
|
+
return prev + curr.stargazerCount;
|
|
462
458
|
}, 0);
|
|
463
459
|
|
|
464
460
|
stats.rank = calculateRank({
|
package/src/fetchers/types.d.ts
CHANGED
package/src/fetchers/wakatime.js
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
1
|
import { encodeHTML } from "./common/html.js";
|
|
4
2
|
|
|
5
3
|
/**
|
|
6
4
|
* Retrieves stat card labels in the available locales.
|
|
7
5
|
*
|
|
8
|
-
* @param
|
|
9
|
-
* @param
|
|
10
|
-
* @param
|
|
11
|
-
* @returns
|
|
6
|
+
* @param props Function arguments.
|
|
7
|
+
* @param props.name The name of the locale.
|
|
8
|
+
* @param props.apostrophe Whether to use apostrophe or not.
|
|
9
|
+
* @returns The locales object.
|
|
12
10
|
*
|
|
13
11
|
* @see https://www.andiamo.co.uk/resources/iso-language-codes/ for language codes.
|
|
14
12
|
*/
|
|
15
|
-
const statCardLocales = ({
|
|
13
|
+
const statCardLocales = ({
|
|
14
|
+
name,
|
|
15
|
+
apostrophe,
|
|
16
|
+
}: {
|
|
17
|
+
name: string;
|
|
18
|
+
apostrophe: string;
|
|
19
|
+
}) => {
|
|
16
20
|
const encodedName = encodeHTML(name);
|
|
17
21
|
return {
|
|
18
22
|
"statcard.title": {
|
|
@@ -1140,10 +1144,10 @@ const availableLocales = Object.keys(repoCardLocales["repocard.archived"]);
|
|
|
1140
1144
|
/**
|
|
1141
1145
|
* Checks whether the locale is available or not.
|
|
1142
1146
|
*
|
|
1143
|
-
* @param
|
|
1144
|
-
* @returns
|
|
1147
|
+
* @param locale The locale to check.
|
|
1148
|
+
* @returns Boolean specifying whether the locale is available or not.
|
|
1145
1149
|
*/
|
|
1146
|
-
const isLocaleAvailable = (locale) => {
|
|
1150
|
+
const isLocaleAvailable = (locale: string): boolean => {
|
|
1147
1151
|
return availableLocales.includes(locale.toLowerCase());
|
|
1148
1152
|
};
|
|
1149
1153
|
|
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/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;
|