@stats-organization/github-readme-stats-core 2.1.4 → 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 -0
- package/build/api/index.d.ts.map +1 -1
- package/build/api/index.js +18 -0
- package/build/api/pin.d.ts.map +1 -1
- package/build/api/pin.js +17 -0
- package/build/api/top-langs.d.ts.map +1 -1
- package/build/api/top-langs.js +36 -4
- package/build/api/wakatime.d.ts.map +1 -1
- package/build/api/wakatime.js +34 -0
- package/build/calculateRank.d.ts +12 -11
- package/build/calculateRank.d.ts.map +1 -1
- package/build/calculateRank.js +18 -18
- package/build/cards/repo.d.ts.map +1 -1
- package/build/cards/repo.js +29 -20
- package/build/cards/stats.d.ts +4 -2
- package/build/cards/stats.d.ts.map +1 -1
- package/build/cards/stats.js +21 -8
- package/build/cards/top-languages.d.ts.map +1 -1
- package/build/cards/top-languages.js +39 -11
- package/build/cards/wakatime.d.ts.map +1 -1
- package/build/cards/wakatime.js +29 -8
- package/build/common/Card.d.ts +9 -3
- package/build/common/Card.d.ts.map +1 -1
- package/build/common/Card.js +47 -19
- package/build/common/color.d.ts +42 -8
- package/build/common/color.d.ts.map +1 -1
- package/build/common/color.js +62 -13
- package/build/common/html.js +1 -1
- package/build/common/http.d.ts +13 -4
- package/build/common/http.d.ts.map +1 -1
- package/build/common/http.js +3 -3
- 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 -37
- package/build/common/render.d.ts +115 -111
- package/build/common/render.d.ts.map +1 -1
- package/build/common/render.js +138 -87
- package/build/common/retryer.d.ts +14 -6
- package/build/common/retryer.d.ts.map +1 -1
- package/build/common/retryer.js +1 -0
- package/build/fetchers/gist.d.ts +6 -21
- package/build/fetchers/gist.d.ts.map +1 -1
- package/build/fetchers/gist.js +30 -35
- package/build/fetchers/repo.js +1 -1
- package/build/fetchers/stats.d.ts.map +1 -1
- package/build/fetchers/stats.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/package.json +4 -4
- package/src/_emoji-name-map.d.ts +10 -0
- package/src/api/gist.js +36 -0
- package/src/api/index.js +19 -0
- package/src/api/pin.js +18 -0
- package/src/api/top-langs.js +38 -4
- package/src/api/wakatime.js +36 -0
- package/src/{calculateRank.js → calculateRank.ts} +29 -19
- package/src/cards/repo.js +30 -20
- package/src/cards/stats.js +22 -8
- package/src/cards/top-languages.js +49 -11
- package/src/cards/wakatime.js +33 -8
- package/src/common/Card.ts +51 -16
- package/src/common/color.ts +85 -22
- package/src/common/html.ts +1 -1
- package/src/common/http.ts +31 -0
- package/src/common/languageColors.json +9 -1
- package/src/common/{ops.js → ops.ts} +48 -50
- package/src/common/{render.js → render.ts} +208 -96
- package/src/common/retryer.ts +18 -10
- package/src/fetchers/gist.ts +136 -0
- package/src/fetchers/repo.js +1 -1
- package/src/fetchers/stats.js +0 -1
- package/src/common/http.js +0 -19
- package/src/fetchers/gist.js +0 -112
- /package/src/fetchers/{types.d.ts → types.ts} +0 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
export interface GistData {
|
|
2
|
+
name: string;
|
|
3
|
+
nameWithOwner: string;
|
|
4
|
+
description: string | null;
|
|
5
|
+
language: string | null;
|
|
6
|
+
starsCount: number;
|
|
7
|
+
forksCount: number;
|
|
8
|
+
}
|
|
9
|
+
export interface RepositoryData {
|
|
10
|
+
name: string;
|
|
11
|
+
nameWithOwner: string;
|
|
12
|
+
isPrivate: boolean;
|
|
13
|
+
isArchived: boolean;
|
|
14
|
+
isTemplate: boolean;
|
|
15
|
+
stargazerCount: number;
|
|
16
|
+
description: string;
|
|
17
|
+
primaryLanguage: {
|
|
18
|
+
color: string;
|
|
19
|
+
id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
};
|
|
22
|
+
forkCount: number;
|
|
23
|
+
starCount: number;
|
|
24
|
+
totalPRsAuthored: number;
|
|
25
|
+
totalPRsCommented: number;
|
|
26
|
+
totalPRsReviewed: number;
|
|
27
|
+
totalIssuesAuthored: number;
|
|
28
|
+
totalIssuesCommented: number;
|
|
29
|
+
}
|
|
30
|
+
export interface StatsData {
|
|
31
|
+
name: string;
|
|
32
|
+
totalPRs: number;
|
|
33
|
+
totalPRsMerged: number;
|
|
34
|
+
mergedPRsPercentage: number;
|
|
35
|
+
totalReviews: number;
|
|
36
|
+
totalCommits: number;
|
|
37
|
+
totalIssues: number;
|
|
38
|
+
totalStars: number;
|
|
39
|
+
totalDiscussionsStarted: number;
|
|
40
|
+
totalDiscussionsAnswered: number;
|
|
41
|
+
contributedTo: number;
|
|
42
|
+
totalPRsAuthored: number;
|
|
43
|
+
totalPRsCommented: number;
|
|
44
|
+
totalPRsReviewed: number;
|
|
45
|
+
totalIssuesAuthored: number;
|
|
46
|
+
totalIssuesCommented: number;
|
|
47
|
+
rank: {
|
|
48
|
+
level: string;
|
|
49
|
+
percentile: number;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export interface Lang {
|
|
53
|
+
name: string;
|
|
54
|
+
color: string;
|
|
55
|
+
size: number;
|
|
56
|
+
}
|
|
57
|
+
export type TopLangData = Record<string, Lang>;
|
|
58
|
+
export interface WakaTimeData {
|
|
59
|
+
categories: Array<{
|
|
60
|
+
digital: string;
|
|
61
|
+
hours: number;
|
|
62
|
+
minutes: number;
|
|
63
|
+
name: string;
|
|
64
|
+
percent: number;
|
|
65
|
+
text: string;
|
|
66
|
+
total_seconds: number;
|
|
67
|
+
}>;
|
|
68
|
+
daily_average: number;
|
|
69
|
+
daily_average_including_other_language: number;
|
|
70
|
+
days_including_holidays: number;
|
|
71
|
+
days_minus_holidays: number;
|
|
72
|
+
editors: Array<{
|
|
73
|
+
digital: string;
|
|
74
|
+
hours: number;
|
|
75
|
+
minutes: number;
|
|
76
|
+
name: string;
|
|
77
|
+
percent: number;
|
|
78
|
+
text: string;
|
|
79
|
+
total_seconds: number;
|
|
80
|
+
}>;
|
|
81
|
+
holidays: number;
|
|
82
|
+
human_readable_daily_average: string;
|
|
83
|
+
human_readable_daily_average_including_other_language: string;
|
|
84
|
+
human_readable_total: string;
|
|
85
|
+
human_readable_total_including_other_language: string;
|
|
86
|
+
id: string;
|
|
87
|
+
is_already_updating: boolean;
|
|
88
|
+
is_coding_activity_visible: boolean;
|
|
89
|
+
is_including_today: boolean;
|
|
90
|
+
is_other_usage_visible: boolean;
|
|
91
|
+
is_stuck: boolean;
|
|
92
|
+
is_up_to_date: boolean;
|
|
93
|
+
languages: Array<{
|
|
94
|
+
digital: string;
|
|
95
|
+
hours: number;
|
|
96
|
+
minutes: number;
|
|
97
|
+
name: string;
|
|
98
|
+
percent: number;
|
|
99
|
+
text: string;
|
|
100
|
+
total_seconds: number;
|
|
101
|
+
}>;
|
|
102
|
+
operating_systems: Array<{
|
|
103
|
+
digital: string;
|
|
104
|
+
hours: number;
|
|
105
|
+
minutes: number;
|
|
106
|
+
name: string;
|
|
107
|
+
percent: number;
|
|
108
|
+
text: string;
|
|
109
|
+
total_seconds: number;
|
|
110
|
+
}>;
|
|
111
|
+
percent_calculated: number;
|
|
112
|
+
range: string;
|
|
113
|
+
status: string;
|
|
114
|
+
timeout: number;
|
|
115
|
+
total_seconds: number;
|
|
116
|
+
total_seconds_including_other_language: number;
|
|
117
|
+
user_id: string;
|
|
118
|
+
username: string;
|
|
119
|
+
writes_only: boolean;
|
|
120
|
+
}
|
|
121
|
+
export interface WakaTimeLang {
|
|
122
|
+
name: string;
|
|
123
|
+
text: string;
|
|
124
|
+
percent: number;
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/fetchers/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stats-organization/github-readme-stats-core",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"homepage": "https://github-stats-extended.vercel.app/frontend",
|
|
6
6
|
"bugs": {
|
|
@@ -71,12 +71,12 @@
|
|
|
71
71
|
"@testing-library/jest-dom": "6.9.1",
|
|
72
72
|
"@uppercod/css-to-object": "1.1.1",
|
|
73
73
|
"axios-mock-adapter": "2.1.0",
|
|
74
|
-
"js-yaml": "
|
|
74
|
+
"js-yaml": "5.2.1",
|
|
75
75
|
"jsdom": "29.1.1",
|
|
76
|
-
"vitest": "4.1.
|
|
76
|
+
"vitest": "4.1.10"
|
|
77
77
|
},
|
|
78
78
|
"dependencies": {
|
|
79
|
-
"axios": "^1.
|
|
79
|
+
"axios": "^1.18.1",
|
|
80
80
|
"emoji-name-map": "^2.0.3",
|
|
81
81
|
"github-username-regex": "^1.0.0"
|
|
82
82
|
},
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `emoji-name-map` ships no type definitions and exposes no `exports` map, so it
|
|
3
|
+
* cannot be resolved under `nodenext`. Declare the minimal surface used here.
|
|
4
|
+
*/
|
|
5
|
+
declare module "emoji-name-map" {
|
|
6
|
+
const emojiNameMap: {
|
|
7
|
+
get(name: string): string | undefined;
|
|
8
|
+
};
|
|
9
|
+
export default emojiNameMap;
|
|
10
|
+
}
|
package/src/api/gist.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { renderGistCard } from "../cards/gist.js";
|
|
2
|
+
import { findInvalidColor } from "../common/color.js";
|
|
2
3
|
import {
|
|
3
4
|
MissingParamError,
|
|
4
5
|
retrieveSecondaryMessage,
|
|
@@ -26,6 +27,23 @@ export default async (
|
|
|
26
27
|
},
|
|
27
28
|
pat = null,
|
|
28
29
|
) => {
|
|
30
|
+
const invalidColorInput = findInvalidColor({
|
|
31
|
+
title_color,
|
|
32
|
+
icon_color,
|
|
33
|
+
text_color,
|
|
34
|
+
bg_color,
|
|
35
|
+
border_color,
|
|
36
|
+
});
|
|
37
|
+
if (invalidColorInput) {
|
|
38
|
+
return {
|
|
39
|
+
status: "error - permanent",
|
|
40
|
+
content: renderError({
|
|
41
|
+
message: "Something went wrong",
|
|
42
|
+
secondaryMessage: `Invalid color input for parameter "${invalidColorInput}"`,
|
|
43
|
+
}),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
29
47
|
if (locale && !isLocaleAvailable(locale)) {
|
|
30
48
|
return {
|
|
31
49
|
status: "error - permanent",
|
|
@@ -43,6 +61,24 @@ export default async (
|
|
|
43
61
|
};
|
|
44
62
|
}
|
|
45
63
|
|
|
64
|
+
const safePattern = /^[-\w/.,]+$/;
|
|
65
|
+
if (id && !safePattern.test(id)) {
|
|
66
|
+
return {
|
|
67
|
+
status: "error - permanent",
|
|
68
|
+
content: renderError({
|
|
69
|
+
message: "Something went wrong",
|
|
70
|
+
secondaryMessage: "Gist ID contains unsafe characters",
|
|
71
|
+
renderOptions: {
|
|
72
|
+
title_color,
|
|
73
|
+
text_color,
|
|
74
|
+
bg_color,
|
|
75
|
+
border_color,
|
|
76
|
+
theme,
|
|
77
|
+
},
|
|
78
|
+
}),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
46
82
|
try {
|
|
47
83
|
const gistData = await fetchGist(id, pat);
|
|
48
84
|
|
package/src/api/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { renderStatsCard } from "../cards/stats.js";
|
|
2
|
+
import { findInvalidColor } from "../common/color.js";
|
|
2
3
|
import {
|
|
3
4
|
MissingParamError,
|
|
4
5
|
retrieveSecondaryMessage,
|
|
@@ -44,6 +45,24 @@ export default async (
|
|
|
44
45
|
},
|
|
45
46
|
pat = null,
|
|
46
47
|
) => {
|
|
48
|
+
const invalidColorInput = findInvalidColor({
|
|
49
|
+
title_color,
|
|
50
|
+
ring_color,
|
|
51
|
+
icon_color,
|
|
52
|
+
text_color,
|
|
53
|
+
bg_color,
|
|
54
|
+
border_color,
|
|
55
|
+
});
|
|
56
|
+
if (invalidColorInput) {
|
|
57
|
+
return {
|
|
58
|
+
status: "error - permanent",
|
|
59
|
+
content: renderError({
|
|
60
|
+
message: "Something went wrong",
|
|
61
|
+
secondaryMessage: `Invalid color input for parameter "${invalidColorInput}"`,
|
|
62
|
+
}),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
47
66
|
if (locale && !isLocaleAvailable(locale)) {
|
|
48
67
|
return {
|
|
49
68
|
status: "error - permanent",
|
package/src/api/pin.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { renderRepoCard } from "../cards/repo.js";
|
|
2
|
+
import { findInvalidColor } from "../common/color.js";
|
|
2
3
|
import {
|
|
3
4
|
MissingParamError,
|
|
4
5
|
retrieveSecondaryMessage,
|
|
@@ -34,6 +35,23 @@ export default async (
|
|
|
34
35
|
},
|
|
35
36
|
pat = null,
|
|
36
37
|
) => {
|
|
38
|
+
const invalidColorInput = findInvalidColor({
|
|
39
|
+
title_color,
|
|
40
|
+
icon_color,
|
|
41
|
+
text_color,
|
|
42
|
+
bg_color,
|
|
43
|
+
border_color,
|
|
44
|
+
});
|
|
45
|
+
if (invalidColorInput) {
|
|
46
|
+
return {
|
|
47
|
+
status: "error - permanent",
|
|
48
|
+
content: renderError({
|
|
49
|
+
message: "Something went wrong",
|
|
50
|
+
secondaryMessage: `Invalid color input for parameter "${invalidColorInput}"`,
|
|
51
|
+
}),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
37
55
|
if (locale && !isLocaleAvailable(locale)) {
|
|
38
56
|
return {
|
|
39
57
|
status: "error - permanent",
|
package/src/api/top-langs.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { renderTopLanguages } from "../cards/top-languages.js";
|
|
2
|
+
import { findInvalidColor } from "../common/color.js";
|
|
2
3
|
import {
|
|
3
4
|
MissingParamError,
|
|
4
5
|
retrieveSecondaryMessage,
|
|
@@ -38,6 +39,23 @@ export default async (
|
|
|
38
39
|
},
|
|
39
40
|
pat = null,
|
|
40
41
|
) => {
|
|
42
|
+
const invalidColorInput = findInvalidColor({
|
|
43
|
+
title_color,
|
|
44
|
+
text_color,
|
|
45
|
+
bg_color,
|
|
46
|
+
prog_bar_bg_color,
|
|
47
|
+
border_color,
|
|
48
|
+
});
|
|
49
|
+
if (invalidColorInput) {
|
|
50
|
+
return {
|
|
51
|
+
status: "error - permanent",
|
|
52
|
+
content: renderError({
|
|
53
|
+
message: "Something went wrong",
|
|
54
|
+
secondaryMessage: `Invalid color input for parameter "${invalidColorInput}"`,
|
|
55
|
+
}),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
41
59
|
if (locale && !isLocaleAvailable(locale)) {
|
|
42
60
|
return {
|
|
43
61
|
status: "error - permanent",
|
|
@@ -55,10 +73,27 @@ export default async (
|
|
|
55
73
|
};
|
|
56
74
|
}
|
|
57
75
|
|
|
76
|
+
const safePattern = /^[-\w/.,]+$/;
|
|
77
|
+
if (username && !safePattern.test(username)) {
|
|
78
|
+
return {
|
|
79
|
+
status: "error - permanent",
|
|
80
|
+
content: renderError({
|
|
81
|
+
message: "Something went wrong",
|
|
82
|
+
secondaryMessage: "Username contains unsafe characters",
|
|
83
|
+
renderOptions: {
|
|
84
|
+
title_color,
|
|
85
|
+
text_color,
|
|
86
|
+
bg_color,
|
|
87
|
+
border_color,
|
|
88
|
+
theme,
|
|
89
|
+
},
|
|
90
|
+
}),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
58
94
|
if (
|
|
59
95
|
layout !== undefined &&
|
|
60
|
-
|
|
61
|
-
!["compact", "normal", "donut", "donut-vertical", "pie"].includes(layout))
|
|
96
|
+
!["compact", "normal", "donut", "donut-vertical", "pie"].includes(layout)
|
|
62
97
|
) {
|
|
63
98
|
return {
|
|
64
99
|
status: "error - permanent",
|
|
@@ -78,8 +113,7 @@ export default async (
|
|
|
78
113
|
|
|
79
114
|
if (
|
|
80
115
|
stats_format !== undefined &&
|
|
81
|
-
|
|
82
|
-
!["bytes", "percentages"].includes(stats_format))
|
|
116
|
+
!["bytes", "percentages"].includes(stats_format)
|
|
83
117
|
) {
|
|
84
118
|
return {
|
|
85
119
|
status: "error - permanent",
|
package/src/api/wakatime.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { renderWakatimeCard } from "../cards/wakatime.js";
|
|
2
|
+
import { findInvalidColor } from "../common/color.js";
|
|
2
3
|
import {
|
|
3
4
|
MissingParamError,
|
|
4
5
|
retrieveSecondaryMessage,
|
|
@@ -32,6 +33,23 @@ export default async ({
|
|
|
32
33
|
display_format,
|
|
33
34
|
disable_animations,
|
|
34
35
|
}) => {
|
|
36
|
+
const invalidColorInput = findInvalidColor({
|
|
37
|
+
title_color,
|
|
38
|
+
icon_color,
|
|
39
|
+
text_color,
|
|
40
|
+
bg_color,
|
|
41
|
+
border_color,
|
|
42
|
+
});
|
|
43
|
+
if (invalidColorInput) {
|
|
44
|
+
return {
|
|
45
|
+
status: "error - permanent",
|
|
46
|
+
content: renderError({
|
|
47
|
+
message: "Something went wrong",
|
|
48
|
+
secondaryMessage: `Invalid color input for parameter "${invalidColorInput}"`,
|
|
49
|
+
}),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
35
53
|
if (locale && !isLocaleAvailable(locale)) {
|
|
36
54
|
return {
|
|
37
55
|
status: "error - permanent",
|
|
@@ -49,6 +67,24 @@ export default async ({
|
|
|
49
67
|
};
|
|
50
68
|
}
|
|
51
69
|
|
|
70
|
+
const safePattern = /^[-\w/.,]+$/;
|
|
71
|
+
if (username && !safePattern.test(username)) {
|
|
72
|
+
return {
|
|
73
|
+
status: "error - permanent",
|
|
74
|
+
content: renderError({
|
|
75
|
+
message: "Something went wrong",
|
|
76
|
+
secondaryMessage: "Username contains unsafe characters",
|
|
77
|
+
renderOptions: {
|
|
78
|
+
title_color,
|
|
79
|
+
text_color,
|
|
80
|
+
bg_color,
|
|
81
|
+
border_color,
|
|
82
|
+
theme,
|
|
83
|
+
},
|
|
84
|
+
}),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
52
88
|
try {
|
|
53
89
|
const stats = await fetchWakatimeStats({ username, api_domain });
|
|
54
90
|
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Calculates the exponential cdf.
|
|
3
3
|
*
|
|
4
|
-
* @param
|
|
5
|
-
* @returns
|
|
4
|
+
* @param x The value.
|
|
5
|
+
* @returns The exponential cdf.
|
|
6
6
|
*/
|
|
7
|
-
function exponential_cdf(x) {
|
|
7
|
+
function exponential_cdf(x: number): number {
|
|
8
8
|
return 1 - 2 ** -x;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Calculates the log normal cdf.
|
|
13
13
|
*
|
|
14
|
-
* @param
|
|
15
|
-
* @returns
|
|
14
|
+
* @param x The value.
|
|
15
|
+
* @returns The log normal cdf.
|
|
16
16
|
*/
|
|
17
|
-
function log_normal_cdf(x) {
|
|
17
|
+
function log_normal_cdf(x: number): number {
|
|
18
18
|
// approximation
|
|
19
19
|
return x / (1 + x);
|
|
20
20
|
}
|
|
@@ -22,16 +22,16 @@ function log_normal_cdf(x) {
|
|
|
22
22
|
/**
|
|
23
23
|
* Calculates the users rank.
|
|
24
24
|
*
|
|
25
|
-
* @param
|
|
26
|
-
* @param
|
|
27
|
-
* @param
|
|
28
|
-
* @param
|
|
29
|
-
* @param
|
|
30
|
-
* @param
|
|
31
|
-
* @param
|
|
32
|
-
* @param
|
|
33
|
-
* @param
|
|
34
|
-
* @returns
|
|
25
|
+
* @param params Parameters on which the user's rank depends.
|
|
26
|
+
* @param params.all_commits Whether `include_all_commits` was used.
|
|
27
|
+
* @param params.commits Number of commits.
|
|
28
|
+
* @param params.prs The number of pull requests.
|
|
29
|
+
* @param params.issues The number of issues.
|
|
30
|
+
* @param params.reviews The number of reviews.
|
|
31
|
+
* @param params.repos Total number of repos (accepted for compatibility, unused in the calculation).
|
|
32
|
+
* @param params.stars The number of stars.
|
|
33
|
+
* @param params.followers The number of followers.
|
|
34
|
+
* @returns The users rank.
|
|
35
35
|
*/
|
|
36
36
|
function calculateRank({
|
|
37
37
|
all_commits,
|
|
@@ -39,11 +39,18 @@ function calculateRank({
|
|
|
39
39
|
prs,
|
|
40
40
|
issues,
|
|
41
41
|
reviews,
|
|
42
|
-
// eslint-disable-next-line no-unused-vars
|
|
43
|
-
repos, // unused
|
|
44
42
|
stars,
|
|
45
43
|
followers,
|
|
46
|
-
}
|
|
44
|
+
}: {
|
|
45
|
+
all_commits: boolean;
|
|
46
|
+
commits: number;
|
|
47
|
+
prs: number;
|
|
48
|
+
issues: number;
|
|
49
|
+
reviews: number;
|
|
50
|
+
repos: number;
|
|
51
|
+
stars: number;
|
|
52
|
+
followers: number;
|
|
53
|
+
}): { level: string; percentile: number } {
|
|
47
54
|
const COMMITS_MEDIAN = all_commits ? 1000 : 250,
|
|
48
55
|
COMMITS_WEIGHT = 2;
|
|
49
56
|
const PRS_MEDIAN = 50,
|
|
@@ -79,6 +86,9 @@ function calculateRank({
|
|
|
79
86
|
TOTAL_WEIGHT;
|
|
80
87
|
|
|
81
88
|
const level = LEVELS[THRESHOLDS.findIndex((t) => rank * 100 <= t)];
|
|
89
|
+
if (level === undefined) {
|
|
90
|
+
throw new Error("Unable to determine rank level");
|
|
91
|
+
}
|
|
82
92
|
|
|
83
93
|
return { level, percentile: rank * 100 };
|
|
84
94
|
}
|
package/src/cards/repo.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Card } from "../common/Card.js";
|
|
2
2
|
import { I18n } from "../common/I18n.js";
|
|
3
|
-
import { getCardColors } from "../common/color.js";
|
|
3
|
+
import { getCardColors, isPrefixedHexColor } from "../common/color.js";
|
|
4
4
|
import { kFormatter, wrapTextMultiline } from "../common/fmt.js";
|
|
5
5
|
import { encodeHTML } from "../common/html.js";
|
|
6
6
|
import { icons } from "../common/icons.js";
|
|
@@ -32,20 +32,29 @@ const DESCRIPTION_MAX_LINES = 3;
|
|
|
32
32
|
* @param {string} textColor The color of the text.
|
|
33
33
|
* @returns {string} Wrapped repo description SVG object.
|
|
34
34
|
*/
|
|
35
|
-
const getBadgeSVG = (label, textColor, xOffset = 0) =>
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
>
|
|
45
|
-
${
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
35
|
+
const getBadgeSVG = (label, textColor, xOffset = 0) => {
|
|
36
|
+
if (!isPrefixedHexColor(textColor)) {
|
|
37
|
+
throw new Error(`Invalid text color: "${textColor}"`);
|
|
38
|
+
}
|
|
39
|
+
if (!Number.isFinite(xOffset)) {
|
|
40
|
+
throw new Error(`Invalid xOffset: "${xOffset}"`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return `
|
|
44
|
+
<g data-testid="badge" class="badge" transform="translate(${320 + xOffset}, -18)">
|
|
45
|
+
<rect stroke="${textColor}" stroke-width="1" width="70" height="20" x="-12" y="-14" ry="10" rx="10"></rect>
|
|
46
|
+
<text
|
|
47
|
+
x="23" y="-5"
|
|
48
|
+
alignment-baseline="central"
|
|
49
|
+
dominant-baseline="central"
|
|
50
|
+
text-anchor="middle"
|
|
51
|
+
fill="${textColor}"
|
|
52
|
+
>
|
|
53
|
+
${encodeHTML(label)}
|
|
54
|
+
</text>
|
|
55
|
+
</g>
|
|
56
|
+
`;
|
|
57
|
+
};
|
|
49
58
|
|
|
50
59
|
/**
|
|
51
60
|
* @typedef {import("../fetchers/types").RepositoryData} RepositoryData Repository data.
|
|
@@ -110,6 +119,7 @@ const renderRepoCard = (repo, options = {}) => {
|
|
|
110
119
|
});
|
|
111
120
|
|
|
112
121
|
let repoFilter = encodeURIComponent(buildSearchFilter([nameWithOwner], []));
|
|
122
|
+
const encodedUsername = encodeURIComponent(username);
|
|
113
123
|
const STATS = {};
|
|
114
124
|
if (show.includes("prs_authored")) {
|
|
115
125
|
STATS.prs_authored = {
|
|
@@ -117,7 +127,7 @@ const renderRepoCard = (repo, options = {}) => {
|
|
|
117
127
|
label: i18n.t("repocard.prs-authored"),
|
|
118
128
|
value: totalPRsAuthored,
|
|
119
129
|
id: "prs_authored",
|
|
120
|
-
link: `https://github.com/search?q=${repoFilter}author%3A${
|
|
130
|
+
link: `https://github.com/search?q=${repoFilter}author%3A${encodedUsername}&type=pullrequests`,
|
|
121
131
|
};
|
|
122
132
|
}
|
|
123
133
|
if (show.includes("prs_commented")) {
|
|
@@ -126,7 +136,7 @@ const renderRepoCard = (repo, options = {}) => {
|
|
|
126
136
|
label: i18n.t("repocard.prs-commented"),
|
|
127
137
|
value: totalPRsCommented,
|
|
128
138
|
id: "prs_commented",
|
|
129
|
-
link: `https://github.com/search?q=${repoFilter}commenter%3A${
|
|
139
|
+
link: `https://github.com/search?q=${repoFilter}commenter%3A${encodedUsername}+-author%3A${encodedUsername}&type=pullrequests`,
|
|
130
140
|
};
|
|
131
141
|
}
|
|
132
142
|
if (show.includes("prs_reviewed")) {
|
|
@@ -135,7 +145,7 @@ const renderRepoCard = (repo, options = {}) => {
|
|
|
135
145
|
label: i18n.t("repocard.prs-reviewed"),
|
|
136
146
|
value: totalPRsReviewed,
|
|
137
147
|
id: "prs_reviewed",
|
|
138
|
-
link: `https://github.com/search?q=${repoFilter}reviewed-by%3A${
|
|
148
|
+
link: `https://github.com/search?q=${repoFilter}reviewed-by%3A${encodedUsername}+-author%3A${encodedUsername}&type=pullrequests`,
|
|
139
149
|
};
|
|
140
150
|
}
|
|
141
151
|
if (show.includes("issues_authored")) {
|
|
@@ -144,7 +154,7 @@ const renderRepoCard = (repo, options = {}) => {
|
|
|
144
154
|
label: i18n.t("repocard.issues-authored"),
|
|
145
155
|
value: totalIssuesAuthored,
|
|
146
156
|
id: "issues_authored",
|
|
147
|
-
link: `https://github.com/search?q=${repoFilter}author%3A${
|
|
157
|
+
link: `https://github.com/search?q=${repoFilter}author%3A${encodedUsername}&type=issues`,
|
|
148
158
|
};
|
|
149
159
|
}
|
|
150
160
|
if (show.includes("issues_commented")) {
|
|
@@ -153,7 +163,7 @@ const renderRepoCard = (repo, options = {}) => {
|
|
|
153
163
|
label: i18n.t("repocard.issues-commented"),
|
|
154
164
|
value: totalIssuesCommented,
|
|
155
165
|
id: "issues_commented",
|
|
156
|
-
link: `https://github.com/search?q=${repoFilter}commenter%3A${
|
|
166
|
+
link: `https://github.com/search?q=${repoFilter}commenter%3A${encodedUsername}+-author%3A${encodedUsername}&type=issues`,
|
|
157
167
|
};
|
|
158
168
|
}
|
|
159
169
|
|