|
@@ -0,0 +1,87 @@
|
|
|
+/**
|
|
|
+ * Calculates the exponential cdf.
|
|
|
+ *
|
|
|
+ * @param {number} x The value.
|
|
|
+ * @returns {number} The exponential cdf.
|
|
|
+ */
|
|
|
+function exponential_cdf(x) {
|
|
|
+ return 1 - 2 ** -x;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Calculates the log normal cdf.
|
|
|
+ *
|
|
|
+ * @param {number} x The value.
|
|
|
+ * @returns {number} The log normal cdf.
|
|
|
+ */
|
|
|
+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 {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.reviews The number of reviews.
|
|
|
+ * @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.
|
|
|
+ */
|
|
|
+function calculateRank({
|
|
|
+ all_commits,
|
|
|
+ commits,
|
|
|
+ prs,
|
|
|
+ issues,
|
|
|
+ reviews,
|
|
|
+ // eslint-disable-next-line no-unused-vars
|
|
|
+ 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 REVIEWS_MEDIAN = 2,
|
|
|
+ REVIEWS_WEIGHT = 1;
|
|
|
+ const STARS_MEDIAN = 50,
|
|
|
+ STARS_WEIGHT = 4;
|
|
|
+ const FOLLOWERS_MEDIAN = 10,
|
|
|
+ FOLLOWERS_WEIGHT = 1;
|
|
|
+
|
|
|
+ const TOTAL_WEIGHT =
|
|
|
+ COMMITS_WEIGHT +
|
|
|
+ PRS_WEIGHT +
|
|
|
+ ISSUES_WEIGHT +
|
|
|
+ REVIEWS_WEIGHT +
|
|
|
+ STARS_WEIGHT +
|
|
|
+ FOLLOWERS_WEIGHT;
|
|
|
+
|
|
|
+ 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 rank =
|
|
|
+ 1 -
|
|
|
+ (COMMITS_WEIGHT * exponential_cdf(commits / COMMITS_MEDIAN) +
|
|
|
+ PRS_WEIGHT * exponential_cdf(prs / PRS_MEDIAN) +
|
|
|
+ ISSUES_WEIGHT * exponential_cdf(issues / ISSUES_MEDIAN) +
|
|
|
+ REVIEWS_WEIGHT * exponential_cdf(reviews / REVIEWS_MEDIAN) +
|
|
|
+ STARS_WEIGHT * log_normal_cdf(stars / STARS_MEDIAN) +
|
|
|
+ FOLLOWERS_WEIGHT * log_normal_cdf(followers / FOLLOWERS_MEDIAN)) /
|
|
|
+ TOTAL_WEIGHT;
|
|
|
+
|
|
|
+ const level = LEVELS[THRESHOLDS.findIndex((t) => rank * 100 <= t)];
|
|
|
+
|
|
|
+ return { level, percentile: rank * 100 };
|
|
|
+}
|
|
|
+
|
|
|
+module.exports = { calculateRank };
|
|
|
+// export default calculateRank;
|