forked from mirrored/github-readme-stats
Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1afe4189cb | ||
|
|
e0b3d833b0 | ||
|
|
275c1fc1c7 | ||
|
|
73b0a91b7b | ||
|
|
c96e84a9ae |
+1
-13
@@ -90,18 +90,6 @@ Pour masquer des statistiques spécifiques, vous pouvez passer un paramètre de
|
||||

|
||||
```
|
||||
|
||||
### Ajouter le compte des contributions privées au compte des commits totaux
|
||||
|
||||
Vous pouvez ajouter le compte de toutes vos contributions privées au compte total des engagements en utilisant le paramètre de requête `?count_private=true`.
|
||||
|
||||
_Note: Si vous déployez vous-même ce projet, les contributions privées seront comptées par défaut ; sinon, vous devez choisir de partager les comptes de vos contributions privées._
|
||||
|
||||
> Options: `&count_private=true`
|
||||
|
||||
```md
|
||||

|
||||
```
|
||||
|
||||
### Afficher les icônes
|
||||
|
||||
Pour activer les icônes, vous pouvez passer `show_icons=true` dans le paramètre de requête, comme ceci :
|
||||
@@ -160,7 +148,7 @@ Vous pouvez fournir plusieurs valeurs (suivie d'une virgule) dans l'option bg_co
|
||||
- `hide_rank` - Masquer le rang _(boolean)_
|
||||
- `show_icons` - Afficher les icônes _(boolean)_
|
||||
- `include_all_commits` - Compter le total de commits au lieu de ne compter que les commits de l'année en cours _(boolean)_
|
||||
- `count_private` - Compter les commits privés _(boolean)_
|
||||
- `count_private` - Compter les contributions privées _(boolean)_
|
||||
- `line_height` - Fixer la hauteur de la ligne entre les textes _(number)_
|
||||
|
||||
#### Repo Card Exclusive Options:
|
||||
|
||||
Generated
+301
-15319
File diff suppressed because it is too large
Load Diff
+1
-2
@@ -49,8 +49,7 @@
|
||||
"lint-staged": "^13.0.3",
|
||||
"lodash.snakecase": "^4.1.1",
|
||||
"parse-diff": "^0.7.0",
|
||||
"prettier": "^2.1.2",
|
||||
"vercel": "^29.4.0"
|
||||
"prettier": "^2.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.24.0",
|
||||
|
||||
@@ -120,19 +120,6 @@ You can pass a query parameter `&hide=` to hide any specific stats with comma-se
|
||||

|
||||
```
|
||||
|
||||
### Adding private contributions count to total commits count
|
||||
|
||||
You can add the count of all your private contributions to the total commits count by using the query parameter `&count_private=true`.
|
||||
|
||||
> **Note**
|
||||
> If you are deploying this project yourself, the private contributions will be counted by default. If you are using the public Vercel instance, you need to choose to [share your private contributions](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/showing-your-private-contributions-and-achievements-on-your-profile).
|
||||
|
||||
> Options: `&count_private=true`
|
||||
|
||||
```md
|
||||

|
||||
```
|
||||
|
||||
### Showing icons
|
||||
|
||||
To enable icons, you can pass `&show_icons=true` in the query param, like so:
|
||||
@@ -283,7 +270,7 @@ You can provide multiple comma-separated values in the bg_color option to render
|
||||
- `rank_icon` - Shows alternative rank icon (i.e. `github` or `default`). Default: `default`.
|
||||
- `show_icons` - _(boolean)_. Default: `false`.
|
||||
- `include_all_commits` - Count total commits instead of just the current year commits _(boolean)_. Default: `false`.
|
||||
- `count_private` - Count private commits _(boolean)_. Default: `false`.
|
||||
- `count_private` - Count private contributions _(boolean)_. Default: `false`.
|
||||
- `line_height` - Sets the line height between text _(number)_. Default: `25`.
|
||||
- `exclude_repo` - Exclude stars from specified repositories _(Comma-separated values)_. Default: `[] (blank array)`.
|
||||
- `custom_title` - Sets a custom title for the card. Default: `<username> GitHub Stats`.
|
||||
|
||||
+50
-87
@@ -1,105 +1,68 @@
|
||||
/**
|
||||
* Calculates the probability of x taking on x or a value less than x in a normal distribution
|
||||
* with mean and standard deviation.
|
||||
*
|
||||
* @see https://stackoverflow.com/a/5263759/10629172
|
||||
*
|
||||
* @param {string} mean The mean of the normal distribution.
|
||||
* @param {number} sigma The standard deviation of the normal distribution.
|
||||
* @param {number} to The value to calculate the probability for.
|
||||
* @returns {number} Probability.
|
||||
*/
|
||||
const normalcdf = (mean, sigma, to) => {
|
||||
var z = (to - mean) / Math.sqrt(2 * sigma * sigma);
|
||||
var t = 1 / (1 + 0.3275911 * Math.abs(z));
|
||||
var a1 = 0.254829592;
|
||||
var a2 = -0.284496736;
|
||||
var a3 = 1.421413741;
|
||||
var a4 = -1.453152027;
|
||||
var a5 = 1.061405429;
|
||||
var erf =
|
||||
1 - ((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t * Math.exp(-z * z);
|
||||
var sign = 1;
|
||||
if (z < 0) {
|
||||
sign = -1;
|
||||
}
|
||||
return (1 / 2) * (1 + sign * erf);
|
||||
};
|
||||
function exponential_cdf(x) {
|
||||
return 1 - 2 ** -x;
|
||||
}
|
||||
|
||||
function log_normal_cdf(x) {
|
||||
// approximation
|
||||
return x / (1 + x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the users rank.
|
||||
*
|
||||
* @param {object} params Parameters on which the user's rank depends.
|
||||
* @param {number} params.totalRepos Total number of repos.
|
||||
* @param {number} params.totalCommits Total number of commits.
|
||||
* @param {number} params.contributions The number of contributions.
|
||||
* @param {number} params.followers The number of followers.
|
||||
* @param {boolean} params.all_commits Whether `include_all_commits` was used.
|
||||
* @param {number} params.commits Number of commits.
|
||||
* @param {number} params.prs The number of pull requests.
|
||||
* @param {number} params.issues The number of issues.
|
||||
* @param {number} params.stargazers The number of stars.
|
||||
* @returns {{level: string, score: number}}} The users rank.
|
||||
* @param {number} params.repos Total number of repos.
|
||||
* @param {number} params.stars The number of stars.
|
||||
* @param {number} params.followers The number of followers.
|
||||
* @returns {{level: string, percentile: number}}} The users rank.
|
||||
*/
|
||||
const calculateRank = ({
|
||||
totalRepos,
|
||||
totalCommits,
|
||||
contributions,
|
||||
followers,
|
||||
function calculateRank({
|
||||
all_commits,
|
||||
commits,
|
||||
prs,
|
||||
issues,
|
||||
stargazers,
|
||||
}) => {
|
||||
const COMMITS_OFFSET = 1.65;
|
||||
const CONTRIBS_OFFSET = 1.65;
|
||||
const ISSUES_OFFSET = 1;
|
||||
const STARS_OFFSET = 0.75;
|
||||
const PRS_OFFSET = 0.5;
|
||||
const FOLLOWERS_OFFSET = 0.45;
|
||||
const REPO_OFFSET = 1;
|
||||
repos, // unused
|
||||
stars,
|
||||
followers,
|
||||
}) {
|
||||
const COMMITS_MEDIAN = all_commits ? 1000 : 250,
|
||||
COMMITS_WEIGHT = 2;
|
||||
const PRS_MEDIAN = 50,
|
||||
PRS_WEIGHT = 3;
|
||||
const ISSUES_MEDIAN = 25,
|
||||
ISSUES_WEIGHT = 1;
|
||||
const STARS_MEDIAN = 50,
|
||||
STARS_WEIGHT = 4;
|
||||
const FOLLOWERS_MEDIAN = 10,
|
||||
FOLLOWERS_WEIGHT = 1;
|
||||
|
||||
const ALL_OFFSETS =
|
||||
CONTRIBS_OFFSET +
|
||||
ISSUES_OFFSET +
|
||||
STARS_OFFSET +
|
||||
PRS_OFFSET +
|
||||
FOLLOWERS_OFFSET +
|
||||
REPO_OFFSET;
|
||||
const TOTAL_WEIGHT =
|
||||
COMMITS_WEIGHT +
|
||||
PRS_WEIGHT +
|
||||
ISSUES_WEIGHT +
|
||||
STARS_WEIGHT +
|
||||
FOLLOWERS_WEIGHT;
|
||||
|
||||
const RANK_S_VALUE = 1;
|
||||
const RANK_DOUBLE_A_VALUE = 25;
|
||||
const RANK_A2_VALUE = 45;
|
||||
const RANK_A3_VALUE = 60;
|
||||
const RANK_B_VALUE = 100;
|
||||
const THRESHOLDS = [1, 12.5, 25, 37.5, 50, 62.5, 75, 87.5, 100];
|
||||
const LEVELS = ["S", "A+", "A", "A-", "B+", "B", "B-", "C+", "C"];
|
||||
|
||||
const TOTAL_VALUES =
|
||||
RANK_S_VALUE +
|
||||
RANK_DOUBLE_A_VALUE +
|
||||
RANK_A2_VALUE +
|
||||
RANK_A3_VALUE +
|
||||
RANK_B_VALUE;
|
||||
const rank =
|
||||
1 -
|
||||
(COMMITS_WEIGHT * exponential_cdf(commits / COMMITS_MEDIAN) +
|
||||
PRS_WEIGHT * exponential_cdf(prs / PRS_MEDIAN) +
|
||||
ISSUES_WEIGHT * exponential_cdf(issues / ISSUES_MEDIAN) +
|
||||
STARS_WEIGHT * log_normal_cdf(stars / STARS_MEDIAN) +
|
||||
FOLLOWERS_WEIGHT * log_normal_cdf(followers / FOLLOWERS_MEDIAN)) /
|
||||
TOTAL_WEIGHT;
|
||||
|
||||
// prettier-ignore
|
||||
const score = (
|
||||
totalCommits * COMMITS_OFFSET +
|
||||
contributions * CONTRIBS_OFFSET +
|
||||
issues * ISSUES_OFFSET +
|
||||
stargazers * STARS_OFFSET +
|
||||
prs * PRS_OFFSET +
|
||||
followers * FOLLOWERS_OFFSET +
|
||||
totalRepos * REPO_OFFSET
|
||||
) / 100;
|
||||
const level = LEVELS[THRESHOLDS.findIndex((t) => rank * 100 <= t)];
|
||||
|
||||
const normalizedScore = normalcdf(score, TOTAL_VALUES, ALL_OFFSETS) * 100;
|
||||
|
||||
const level = (() => {
|
||||
if (normalizedScore < RANK_S_VALUE) return "S+";
|
||||
if (normalizedScore < RANK_DOUBLE_A_VALUE) return "S";
|
||||
if (normalizedScore < RANK_A2_VALUE) return "A++";
|
||||
if (normalizedScore < RANK_A3_VALUE) return "A+";
|
||||
return "B+";
|
||||
})();
|
||||
|
||||
return { level, score: normalizedScore };
|
||||
};
|
||||
return { level: level, percentile: rank * 100 };
|
||||
}
|
||||
|
||||
export { calculateRank };
|
||||
export default calculateRank;
|
||||
|
||||
@@ -209,9 +209,8 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
|
||||
hide_rank ? 0 : 150,
|
||||
);
|
||||
|
||||
// the better user's score the the rank will be closer to zero so
|
||||
// subtracting 100 to get the progress in 100%
|
||||
const progress = 100 - rank.score;
|
||||
// the lower the user's percentile the better
|
||||
const progress = 100 - rank.percentile;
|
||||
const cssStyles = getStyles({
|
||||
titleColor,
|
||||
ringColor,
|
||||
|
||||
@@ -17,6 +17,7 @@ const MIN_CARD_WIDTH = 280;
|
||||
const DEFAULT_LANGS_COUNT = 5;
|
||||
const DEFAULT_LANG_COLOR = "#858585";
|
||||
const CARD_PADDING = 25;
|
||||
const COMPACT_LAYOUT_BASE_HEIGHT = 90;
|
||||
|
||||
/**
|
||||
* @typedef {import("../fetchers/types").Lang} Lang
|
||||
@@ -101,7 +102,7 @@ const getCircleLength = (radius) => {
|
||||
* @returns {number} Card height.
|
||||
*/
|
||||
const calculateCompactLayoutHeight = (totalLangs) => {
|
||||
return 90 + Math.round(totalLangs / 2) * 25;
|
||||
return COMPACT_LAYOUT_BASE_HEIGHT + Math.round(totalLangs / 2) * 25;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -654,6 +655,19 @@ const renderDonutLayout = (langs, width, totalLanguageSize) => {
|
||||
`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates the no coding activity SVG node.
|
||||
*
|
||||
* @param {{color: string, text: string, layout: import("./types").TopLangOptions["layout"]}} The function prop
|
||||
*/
|
||||
const noLanguagesDataNode = ({ color, text, layout }) => {
|
||||
return `
|
||||
<text x="${
|
||||
layout === "pie" || layout === "donut-vertical" ? CARD_PADDING : 0
|
||||
}" y="11" class="stat bold" fill="${color}">${text}</text>
|
||||
`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders card that display user's most frequently used programming languages.
|
||||
*
|
||||
@@ -699,8 +713,24 @@ const renderTopLanguages = (topLangs, options = {}) => {
|
||||
: card_width;
|
||||
let height = calculateNormalLayoutHeight(langs.length);
|
||||
|
||||
// returns theme based colors with proper overrides and defaults
|
||||
const colors = getCardColors({
|
||||
title_color,
|
||||
text_color,
|
||||
bg_color,
|
||||
border_color,
|
||||
theme,
|
||||
});
|
||||
|
||||
let finalLayout = "";
|
||||
if (layout === "pie") {
|
||||
if (langs.length === 0) {
|
||||
height = COMPACT_LAYOUT_BASE_HEIGHT;
|
||||
finalLayout = noLanguagesDataNode({
|
||||
color: colors.textColor,
|
||||
text: i18n.t("langcard.nodata"),
|
||||
layout,
|
||||
});
|
||||
} else if (layout === "pie") {
|
||||
height = calculatePieLayoutHeight(langs.length);
|
||||
finalLayout = renderPieLayout(langs, totalLanguageSize);
|
||||
} else if (layout === "donut-vertical") {
|
||||
@@ -724,15 +754,6 @@ const renderTopLanguages = (topLangs, options = {}) => {
|
||||
finalLayout = renderNormalLayout(langs, width, totalLanguageSize);
|
||||
}
|
||||
|
||||
// returns theme based colors with proper overrides and defaults
|
||||
const colors = getCardColors({
|
||||
title_color,
|
||||
text_color,
|
||||
bg_color,
|
||||
border_color,
|
||||
theme,
|
||||
});
|
||||
|
||||
const card = new Card({
|
||||
customTitle: custom_title,
|
||||
defaultTitle: i18n.t("langcard.title"),
|
||||
@@ -764,6 +785,14 @@ const renderTopLanguages = (topLangs, options = {}) => {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.stat {
|
||||
font: 600 14px 'Segoe UI', Ubuntu, "Helvetica Neue", Sans-Serif; fill: ${colors.textColor};
|
||||
}
|
||||
@supports(-moz-appearance: auto) {
|
||||
/* Selector detects Firefox */
|
||||
.stat { font-size:12px; }
|
||||
}
|
||||
.bold { font-weight: 700 }
|
||||
.lang-name {
|
||||
font: 400 11px "Segoe UI", Ubuntu, Sans-Serif;
|
||||
fill: ${colors.textColor};
|
||||
|
||||
@@ -106,6 +106,7 @@
|
||||
"Cypher": "#34c0eb",
|
||||
"Cython": "#fedf5b",
|
||||
"D": "#ba595e",
|
||||
"D2": "#526ee8",
|
||||
"DM": "#447265",
|
||||
"Dafny": "#FFEC25",
|
||||
"Darcs Patch": "#8eff23",
|
||||
@@ -185,6 +186,7 @@
|
||||
"Go": "#00ADD8",
|
||||
"Go Checksums": "#00ADD8",
|
||||
"Go Module": "#00ADD8",
|
||||
"Go Workspace": "#00ADD8",
|
||||
"Godot Resource": "#355570",
|
||||
"Golo": "#88562A",
|
||||
"Gosu": "#82937f",
|
||||
@@ -284,6 +286,7 @@
|
||||
"Lua": "#000080",
|
||||
"MATLAB": "#e16737",
|
||||
"MAXScript": "#00a6a6",
|
||||
"MDX": "#fcb32c",
|
||||
"MLIR": "#5EC8DB",
|
||||
"MQL4": "#62A8D6",
|
||||
"MQL5": "#4A76B8",
|
||||
@@ -330,11 +333,12 @@
|
||||
"Nu": "#c9df40",
|
||||
"NumPy": "#9C8AF9",
|
||||
"Nunjucks": "#3d8137",
|
||||
"Nushell": "#4E9906",
|
||||
"OASv2-json": "#85ea2d",
|
||||
"OASv2-yaml": "#85ea2d",
|
||||
"OASv3-json": "#85ea2d",
|
||||
"OASv3-yaml": "#85ea2d",
|
||||
"OCaml": "#3be133",
|
||||
"OCaml": "#ef7a08",
|
||||
"ObjectScript": "#424893",
|
||||
"Objective-C": "#438eff",
|
||||
"Objective-C++": "#6866fb",
|
||||
@@ -360,6 +364,7 @@
|
||||
"PLSQL": "#dad8d8",
|
||||
"PLpgSQL": "#336790",
|
||||
"POV-Ray SDL": "#6bac65",
|
||||
"Pact": "#F7A8B8",
|
||||
"Pan": "#cc0000",
|
||||
"Papyrus": "#6600cc",
|
||||
"Parrot": "#f3ca0a",
|
||||
@@ -398,6 +403,7 @@
|
||||
"Quake": "#882233",
|
||||
"R": "#198CE7",
|
||||
"RAML": "#77d9fb",
|
||||
"RBS": "#701516",
|
||||
"RDoc": "#701516",
|
||||
"REXX": "#d90e09",
|
||||
"RMarkdown": "#198ce7",
|
||||
@@ -472,6 +478,7 @@
|
||||
"Swift": "#F05138",
|
||||
"SystemVerilog": "#DAE1C2",
|
||||
"TI Program": "#A0AA87",
|
||||
"TL-Verilog": "#C40023",
|
||||
"TLA": "#4b0079",
|
||||
"TOML": "#9c4221",
|
||||
"TSQL": "#e38c00",
|
||||
@@ -512,6 +519,7 @@
|
||||
"Vyper": "#2980b9",
|
||||
"Web Ontology Language": "#5b70bd",
|
||||
"WebAssembly": "#04133b",
|
||||
"WebAssembly Interface Type": "#6250e7",
|
||||
"Whiley": "#d5c397",
|
||||
"Wikitext": "#fc5757",
|
||||
"Windows Registry Entries": "#52d5ff",
|
||||
|
||||
@@ -192,7 +192,7 @@ const fetchStats = async (
|
||||
totalIssues: 0,
|
||||
totalStars: 0,
|
||||
contributedTo: 0,
|
||||
rank: { level: "C", score: 0 },
|
||||
rank: { level: "C", percentile: 100 },
|
||||
};
|
||||
|
||||
let res = await statsFetcher(username);
|
||||
@@ -220,53 +220,44 @@ const fetchStats = async (
|
||||
|
||||
const user = res.data.data.user;
|
||||
|
||||
// populate repoToHide map for quick lookup
|
||||
// while filtering out
|
||||
let repoToHide = {};
|
||||
if (exclude_repo) {
|
||||
exclude_repo.forEach((repoName) => {
|
||||
repoToHide[repoName] = true;
|
||||
});
|
||||
}
|
||||
|
||||
stats.name = user.name || user.login;
|
||||
stats.totalIssues = user.openIssues.totalCount + user.closedIssues.totalCount;
|
||||
|
||||
// normal commits
|
||||
stats.totalCommits = user.contributionsCollection.totalCommitContributions;
|
||||
|
||||
// if include_all_commits then just get that,
|
||||
// since totalCommitsFetcher already sends totalCommits no need to +=
|
||||
// if include_all_commits, fetch all commits using the REST API.
|
||||
if (include_all_commits) {
|
||||
stats.totalCommits = await totalCommitsFetcher(username);
|
||||
} else {
|
||||
stats.totalCommits = user.contributionsCollection.totalCommitContributions;
|
||||
}
|
||||
|
||||
// if count_private then add private commits to totalCommits so far.
|
||||
// if count_private, add private contributions to totalCommits.
|
||||
if (count_private) {
|
||||
stats.totalCommits +=
|
||||
user.contributionsCollection.restrictedContributionsCount;
|
||||
}
|
||||
|
||||
stats.totalPRs = user.pullRequests.totalCount;
|
||||
stats.totalIssues = user.openIssues.totalCount + user.closedIssues.totalCount;
|
||||
stats.contributedTo = user.repositoriesContributedTo.totalCount;
|
||||
|
||||
// Retrieve stars while filtering out repositories to be hidden
|
||||
// Retrieve stars while filtering out repositories to be hidden.
|
||||
let repoToHide = new Set(exclude_repo);
|
||||
|
||||
stats.totalStars = user.repositories.nodes
|
||||
.filter((data) => {
|
||||
return !repoToHide[data.name];
|
||||
return !repoToHide.has(data.name);
|
||||
})
|
||||
.reduce((prev, curr) => {
|
||||
return prev + curr.stargazers.totalCount;
|
||||
}, 0);
|
||||
|
||||
stats.rank = calculateRank({
|
||||
totalCommits: stats.totalCommits,
|
||||
totalRepos: user.repositories.totalCount,
|
||||
followers: user.followers.totalCount,
|
||||
contributions: stats.contributedTo,
|
||||
stargazers: stats.totalStars,
|
||||
all_commits: include_all_commits,
|
||||
commits: stats.totalCommits,
|
||||
prs: stats.totalPRs,
|
||||
issues: stats.totalIssues,
|
||||
repos: user.repositories.totalCount,
|
||||
stars: stats.totalStars,
|
||||
followers: user.followers.totalCount,
|
||||
});
|
||||
|
||||
return stats;
|
||||
|
||||
Vendored
+1
-1
@@ -22,7 +22,7 @@ export type StatsData = {
|
||||
totalIssues: number;
|
||||
totalStars: number;
|
||||
contributedTo: number;
|
||||
rank: { level: string; score: number };
|
||||
rank: { level: string; percentile: number };
|
||||
};
|
||||
|
||||
export type Lang = {
|
||||
|
||||
+31
-1
@@ -283,7 +283,7 @@ const langCardLocales = {
|
||||
np: "अधिक प्रयोग गरिएको भाषाहरू",
|
||||
el: "Οι περισσότερο χρησιμοποιούμενες γλώσσες",
|
||||
ru: "Наиболее часто используемые языки",
|
||||
"uk-ua": "Найбільш часто використовувані мови",
|
||||
"uk-ua": "Найчастіше використовувані мови",
|
||||
id: "Bahasa Yang Paling Banyak Digunakan",
|
||||
ml: "കൂടുതൽ ഉപയോഗിച്ച ഭാഷകൾ",
|
||||
my: "Bahasa Paling Digunakan",
|
||||
@@ -293,6 +293,36 @@ const langCardLocales = {
|
||||
vi: "Ngôn Ngữ Thường Sử Dụng",
|
||||
se: "Mest använda språken",
|
||||
},
|
||||
"langcard.nodata": {
|
||||
ar: "لا توجد بيانات لغات.",
|
||||
cn: "沒有語言數據。",
|
||||
"zh-tw": "沒有語言數據。",
|
||||
cs: "Žádné jazykové údaje.",
|
||||
de: "Keine Sprachdaten.",
|
||||
bn: "কোন ভাষার ডেটা নেই।",
|
||||
en: "No languages data.",
|
||||
es: "Sin datos de idiomas.",
|
||||
fr: "Aucune donnée sur les langues.",
|
||||
hu: "Nincsenek nyelvi adatok.",
|
||||
it: "Nessun dato sulle lingue.",
|
||||
ja: "言語データがありません。",
|
||||
kr: "언어 데이터가 없습니다.",
|
||||
nl: "Ingen sprogdata.",
|
||||
"pt-pt": "Sem dados de idiomas.",
|
||||
"pt-br": "Sem dados de idiomas.",
|
||||
np: "कुनै भाषा डाटा छैन।",
|
||||
el: "Δεν υπάρχουν δεδομένα γλωσσών.",
|
||||
ru: "Нет данных о языках.",
|
||||
"uk-ua": "Немає даних про мови.",
|
||||
id: "Tidak ada data bahasa.",
|
||||
ml: "ഭാഷാ ഡാറ്റയില്ല.",
|
||||
my: "Tiada data bahasa.",
|
||||
sk: "Žiadne údaje o jazykoch.",
|
||||
tr: "Dil verisi yok.",
|
||||
pl: "Brak danych dotyczących języków.",
|
||||
vi: "Không có dữ liệu ngôn ngữ.",
|
||||
se: "Inga språkdata.",
|
||||
},
|
||||
};
|
||||
|
||||
const wakatimeCardLocales = {
|
||||
|
||||
+7
-38
@@ -12,17 +12,18 @@ const stats = {
|
||||
totalCommits: 200,
|
||||
totalIssues: 300,
|
||||
totalPRs: 400,
|
||||
contributedTo: 500,
|
||||
contributedTo: 50,
|
||||
rank: null,
|
||||
};
|
||||
|
||||
stats.rank = calculateRank({
|
||||
totalCommits: stats.totalCommits,
|
||||
totalRepos: 1,
|
||||
followers: 0,
|
||||
contributions: stats.contributedTo,
|
||||
stargazers: stats.totalStars,
|
||||
all_commits: false,
|
||||
commits: stats.totalCommits,
|
||||
prs: stats.totalPRs,
|
||||
issues: stats.totalIssues,
|
||||
repos: 1,
|
||||
stars: stats.totalStars,
|
||||
followers: 0,
|
||||
});
|
||||
|
||||
const data_stats = {
|
||||
@@ -229,38 +230,6 @@ describe("Test /api/", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("should add private contributions", async () => {
|
||||
const { req, res } = faker(
|
||||
{
|
||||
username: "anuraghazra",
|
||||
count_private: true,
|
||||
},
|
||||
data_stats,
|
||||
);
|
||||
|
||||
await api(req, res);
|
||||
|
||||
expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml");
|
||||
expect(res.send).toBeCalledWith(
|
||||
renderStatsCard(
|
||||
{
|
||||
...stats,
|
||||
totalCommits: stats.totalCommits + 100,
|
||||
rank: calculateRank({
|
||||
totalCommits: stats.totalCommits + 100,
|
||||
totalRepos: 1,
|
||||
followers: 0,
|
||||
contributions: stats.contributedTo,
|
||||
stargazers: stats.totalStars,
|
||||
prs: stats.totalPRs,
|
||||
issues: stats.totalIssues,
|
||||
}),
|
||||
},
|
||||
{},
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it("should allow changing ring_color", async () => {
|
||||
const { req, res } = faker(
|
||||
{
|
||||
|
||||
@@ -2,17 +2,101 @@ import "@testing-library/jest-dom";
|
||||
import { calculateRank } from "../src/calculateRank.js";
|
||||
|
||||
describe("Test calculateRank", () => {
|
||||
it("should calculate rank correctly", () => {
|
||||
it("new user gets C rank", () => {
|
||||
expect(
|
||||
calculateRank({
|
||||
totalCommits: 100,
|
||||
totalRepos: 5,
|
||||
followers: 100,
|
||||
contributions: 61,
|
||||
stargazers: 400,
|
||||
prs: 300,
|
||||
issues: 200,
|
||||
all_commits: false,
|
||||
commits: 0,
|
||||
prs: 0,
|
||||
issues: 0,
|
||||
repos: 0,
|
||||
stars: 0,
|
||||
followers: 0,
|
||||
}),
|
||||
).toStrictEqual({ level: "A+", score: 49.25629684876535 });
|
||||
).toStrictEqual({ level: "C", percentile: 100 });
|
||||
});
|
||||
|
||||
it("beginner user gets B- rank", () => {
|
||||
expect(
|
||||
calculateRank({
|
||||
all_commits: false,
|
||||
commits: 125,
|
||||
prs: 25,
|
||||
issues: 10,
|
||||
repos: 0,
|
||||
stars: 25,
|
||||
followers: 5,
|
||||
}),
|
||||
).toStrictEqual({ level: "B-", percentile: 69.333868386557 });
|
||||
});
|
||||
|
||||
it("median user gets B+ rank", () => {
|
||||
expect(
|
||||
calculateRank({
|
||||
all_commits: false,
|
||||
commits: 250,
|
||||
prs: 50,
|
||||
issues: 25,
|
||||
repos: 0,
|
||||
stars: 50,
|
||||
followers: 10,
|
||||
}),
|
||||
).toStrictEqual({ level: "B+", percentile: 50 });
|
||||
});
|
||||
|
||||
it("average user gets B+ rank (include_all_commits)", () => {
|
||||
expect(
|
||||
calculateRank({
|
||||
all_commits: true,
|
||||
commits: 1000,
|
||||
prs: 50,
|
||||
issues: 25,
|
||||
repos: 0,
|
||||
stars: 50,
|
||||
followers: 10,
|
||||
}),
|
||||
).toStrictEqual({ level: "B+", percentile: 50 });
|
||||
});
|
||||
|
||||
it("advanced user gets A rank", () => {
|
||||
expect(
|
||||
calculateRank({
|
||||
all_commits: false,
|
||||
commits: 500,
|
||||
prs: 100,
|
||||
issues: 50,
|
||||
repos: 0,
|
||||
stars: 200,
|
||||
followers: 40,
|
||||
}),
|
||||
).toStrictEqual({ level: "A", percentile: 22.72727272727273 });
|
||||
});
|
||||
|
||||
it("expert user gets A+ rank", () => {
|
||||
expect(
|
||||
calculateRank({
|
||||
all_commits: false,
|
||||
commits: 1000,
|
||||
prs: 200,
|
||||
issues: 100,
|
||||
repos: 0,
|
||||
stars: 800,
|
||||
followers: 160,
|
||||
}),
|
||||
).toStrictEqual({ level: "A+", percentile: 6.082887700534744 });
|
||||
});
|
||||
|
||||
it("sindresorhus gets S rank", () => {
|
||||
expect(
|
||||
calculateRank({
|
||||
all_commits: false,
|
||||
commits: 1300,
|
||||
prs: 1500,
|
||||
issues: 4500,
|
||||
repos: 0,
|
||||
stars: 600000,
|
||||
followers: 50000,
|
||||
}),
|
||||
).toStrictEqual({ level: "S", percentile: 0.49947889605312934 });
|
||||
});
|
||||
});
|
||||
|
||||
+39
-62
@@ -102,13 +102,13 @@ describe("Test fetchStats", () => {
|
||||
it("should fetch correct stats", async () => {
|
||||
let stats = await fetchStats("anuraghazra");
|
||||
const rank = calculateRank({
|
||||
totalCommits: 100,
|
||||
totalRepos: 5,
|
||||
followers: 100,
|
||||
contributions: 61,
|
||||
stargazers: 300,
|
||||
all_commits: false,
|
||||
commits: 100,
|
||||
prs: 300,
|
||||
issues: 200,
|
||||
repos: 5,
|
||||
stars: 300,
|
||||
followers: 100,
|
||||
});
|
||||
|
||||
expect(stats).toStrictEqual({
|
||||
@@ -132,13 +132,13 @@ describe("Test fetchStats", () => {
|
||||
|
||||
let stats = await fetchStats("anuraghazra");
|
||||
const rank = calculateRank({
|
||||
totalCommits: 100,
|
||||
totalRepos: 5,
|
||||
followers: 100,
|
||||
contributions: 61,
|
||||
stargazers: 300,
|
||||
all_commits: false,
|
||||
commits: 100,
|
||||
prs: 300,
|
||||
issues: 200,
|
||||
repos: 5,
|
||||
stars: 300,
|
||||
followers: 100,
|
||||
});
|
||||
|
||||
expect(stats).toStrictEqual({
|
||||
@@ -161,49 +161,26 @@ describe("Test fetchStats", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("should fetch and add private contributions", async () => {
|
||||
let stats = await fetchStats("anuraghazra", true);
|
||||
const rank = calculateRank({
|
||||
totalCommits: 150,
|
||||
totalRepos: 5,
|
||||
followers: 100,
|
||||
contributions: 61,
|
||||
stargazers: 300,
|
||||
prs: 300,
|
||||
issues: 200,
|
||||
});
|
||||
|
||||
expect(stats).toStrictEqual({
|
||||
contributedTo: 61,
|
||||
name: "Anurag Hazra",
|
||||
totalCommits: 150,
|
||||
totalIssues: 200,
|
||||
totalPRs: 300,
|
||||
totalStars: 300,
|
||||
rank,
|
||||
});
|
||||
});
|
||||
|
||||
it("should fetch total commits", async () => {
|
||||
mock
|
||||
.onGet("https://api.github.com/search/commits?q=author:anuraghazra")
|
||||
.reply(200, { total_count: 1000 });
|
||||
|
||||
let stats = await fetchStats("anuraghazra", true, true);
|
||||
let stats = await fetchStats("anuraghazra", false, true);
|
||||
const rank = calculateRank({
|
||||
totalCommits: 1050,
|
||||
totalRepos: 5,
|
||||
followers: 100,
|
||||
contributions: 61,
|
||||
stargazers: 300,
|
||||
all_commits: true,
|
||||
commits: 1000,
|
||||
prs: 300,
|
||||
issues: 200,
|
||||
repos: 5,
|
||||
stars: 300,
|
||||
followers: 100,
|
||||
});
|
||||
|
||||
expect(stats).toStrictEqual({
|
||||
contributedTo: 61,
|
||||
name: "Anurag Hazra",
|
||||
totalCommits: 1050,
|
||||
totalCommits: 1000,
|
||||
totalIssues: 200,
|
||||
totalPRs: 300,
|
||||
totalStars: 300,
|
||||
@@ -216,21 +193,21 @@ describe("Test fetchStats", () => {
|
||||
.onGet("https://api.github.com/search/commits?q=author:anuraghazra")
|
||||
.reply(200, { total_count: 1000 });
|
||||
|
||||
let stats = await fetchStats("anuraghazra", true, true, ["test-repo-1"]);
|
||||
let stats = await fetchStats("anuraghazra", false, true, ["test-repo-1"]);
|
||||
const rank = calculateRank({
|
||||
totalCommits: 1050,
|
||||
totalRepos: 5,
|
||||
followers: 100,
|
||||
contributions: 61,
|
||||
stargazers: 200,
|
||||
all_commits: true,
|
||||
commits: 1000,
|
||||
prs: 300,
|
||||
issues: 200,
|
||||
repos: 5,
|
||||
stars: 200,
|
||||
followers: 100,
|
||||
});
|
||||
|
||||
expect(stats).toStrictEqual({
|
||||
contributedTo: 61,
|
||||
name: "Anurag Hazra",
|
||||
totalCommits: 1050,
|
||||
totalCommits: 1000,
|
||||
totalIssues: 200,
|
||||
totalPRs: 300,
|
||||
totalStars: 200,
|
||||
@@ -243,13 +220,13 @@ describe("Test fetchStats", () => {
|
||||
|
||||
let stats = await fetchStats("anuraghazra");
|
||||
const rank = calculateRank({
|
||||
totalCommits: 100,
|
||||
totalRepos: 5,
|
||||
followers: 100,
|
||||
contributions: 61,
|
||||
stargazers: 400,
|
||||
all_commits: false,
|
||||
commits: 100,
|
||||
prs: 300,
|
||||
issues: 200,
|
||||
repos: 5,
|
||||
stars: 400,
|
||||
followers: 100,
|
||||
});
|
||||
|
||||
expect(stats).toStrictEqual({
|
||||
@@ -268,13 +245,13 @@ describe("Test fetchStats", () => {
|
||||
|
||||
let stats = await fetchStats("anuraghazra");
|
||||
const rank = calculateRank({
|
||||
totalCommits: 100,
|
||||
totalRepos: 5,
|
||||
followers: 100,
|
||||
contributions: 61,
|
||||
stargazers: 300,
|
||||
all_commits: false,
|
||||
commits: 100,
|
||||
prs: 300,
|
||||
issues: 200,
|
||||
repos: 5,
|
||||
stars: 300,
|
||||
followers: 100,
|
||||
});
|
||||
|
||||
expect(stats).toStrictEqual({
|
||||
@@ -293,13 +270,13 @@ describe("Test fetchStats", () => {
|
||||
|
||||
let stats = await fetchStats("anuraghazra");
|
||||
const rank = calculateRank({
|
||||
totalCommits: 100,
|
||||
totalRepos: 5,
|
||||
followers: 100,
|
||||
contributions: 61,
|
||||
stargazers: 300,
|
||||
all_commits: false,
|
||||
commits: 100,
|
||||
prs: 300,
|
||||
issues: 200,
|
||||
repos: 5,
|
||||
stars: 300,
|
||||
followers: 100,
|
||||
});
|
||||
|
||||
expect(stats).toStrictEqual({
|
||||
|
||||
Reference in New Issue
Block a user